A flexible component library that supports multiple implementation modes for different use cases, from lightweight static HTML to full Vue.js applications.
- Overview
- Component Architecture
- Component Modes
- Export System
- Development with Storybook
- Project Structure
- Getting Started
- CLI Commands
- Bundle System
This component library is designed to provide maximum flexibility for different deployment scenarios. Components can be implemented in three distinct modes:
- No-JS Mode - Pure HTML/CSS components for static sites
- Petite-Vue Mode - Lightweight interactive components using Petite-Vue
- Full Vue Mode - Complete Vue.js components with full framework features
Each component follows a consistent file structure:
src/components/ComponentName/
├── ComponentName.html # HTML template (for no-js and petite-vue modes)
├── ComponentName.vue # Vue component (for full Vue mode)
├── ComponentName.ts # TypeScript logic (for petite-vue mode)
├── ComponentName.scss # Styles
├── ComponentName.json # Default data/configuration
├── ComponentName.types.ts # TypeScript interfaces
└── ComponentName.stories.ts # Storybook stories
Example: BasicButton
- Files:
.html,.scss,.types.ts,.stories.ts - Use Case: Static websites, email templates, CDN delivery
- Features: Pure HTML markup with CSS styling
- Bundle Size: Minimal (CSS only)
<!-- BasicButton.html -->
<button class="basic-button">CTA Label</button>Export Output:
component.html- Ready-to-use HTML pagecomponent.css- Compiled styles
Example: SimpleBanner
- Files:
.html,.ts,.scss,.json,.types.ts,.stories.ts - Use Case: CMS integration, lightweight websites, progressive enhancement
- Features: Reactive data binding, event handling, dynamic content loading
- Bundle Size: Small (~10kb including Petite-Vue)
<!-- SimpleBanner.html -->
<div class="simple-banner" v-scope>
<h1>{{ title }}</h1>
<p>{{ subtitle }}</p>
<a :href="cta.href">{{ cta.text }}</a>
</div>// SimpleBanner.ts
import { createApp } from 'petite-vue';
import { useFetchData } from '../../composables/useFetchData';
const data = await useFetchData({ componentName: 'SimpleBanner' });
createApp(data).mount('.simple-banner');Export Output:
component.html- HTML page with componentcomponent.js- Petite-Vue bundle with component logiccomponent.css- Compiled stylescomponent.json- Configuration datavendor.js- Petite-Vue runtime
Example: HeroBanner, SimpleButton
- Files:
.vue,.scss,.json,.types.ts,.stories.ts - Use Case: Vue.js applications, complex interactions, component composition
- Features: Full Vue.js ecosystem, child components, advanced reactivity, TypeScript support
- Bundle Size: Larger (~100kb+ including Vue.js)
<!-- HeroBanner.vue -->
<template>
<div class="herobanner">
<h1>{{ computedTitle }}</h1>
<p>{{ computedSubtitle }}</p>
<SimpleButton
v-if="computedCta"
v-bind="computedCta"
@click="handleCtaClick"
/>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import SimpleButton from '../SimpleButton/SimpleButton.vue';
import { useFetchData } from '../../composables/useFetchData';
// Component logic with full Vue.js features
</script>Export Output:
component.html- HTML page with custom elementscomponent.js- Vue component bundle (as custom elements)component.css- Compiled stylescomponent.json- Configuration datavendor.js- Vue.js runtime
The following npm scripts are available for exporting components and bundles:
| Script | Output | Description |
| ------------------------------------------------ | ------------ | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| npm run export -- <ComponentName | BundleName> | Bare HTML markup (not a full HTML page), <name>.js, vendor.js, and optional CSS/JSON | For embedding in existing sites. Produces minimal HTML and separate JS bundles. |
| npm run export:webpage -- <ComponentName | BundleName> | Full HTML page, <name>.js, vendor.js, and optional CSS/JSON | For standalone preview or deployment. |
| npm run export:single -- <ComponentName | BundleName> | Bare HTML markup, single <name>.js (no vendor.js), and optional CSS/JSON | For embedding with a single JS bundle. |
| npm run export:single:webpage -- <ComponentName | BundleName> | Full HTML page, single <name>.js (no vendor.js), and optional CSS/JSON | For standalone preview with a single JS bundle. |
dist/
├── ComponentName/
│ ├── ComponentName.html # Main HTML file (bare markup or full page)
│ ├── ComponentName.js # Component logic (single or split bundle)
│ ├── ComponentName.css # Compiled styles (if needed)
│ ├── ComponentName.json # Configuration data (if exists)
│ └── vendor.js # Framework runtime (if not using single bundle)
└── BundleName/
├── bundlename.html # Bundle HTML file (bare markup or full page)
├── bundlename.js # Combined bundle logic (single or split bundle)
├── bundlename.css # Combined styles
├── vendor.js # Framework runtime (if not using single bundle)
└── *.json # Individual component configs
Define component bundles in the bundles/ directory:
// bundles/marketing.json
{
"name": "Marketing Components",
"description": "Components for marketing pages",
"components": ["HeroBanner", "SimpleButton", "SimpleBanner"]
}Bundles can contain components from different modes:
- Vue components are converted to custom elements
- Petite-Vue components use data attributes
- CSS-only components are included as-is
- All styles are bundled together
- Appropriate runtimes are included
npm run dev
Storybook serves as the development environment and component preview system.
- Preview static HTML output
- Test different content variations
- Validate CSS styling across breakpoints
- Interactive previews with live data binding
- Test dynamic content loading
- Validate reactive behaviors
- Complete component interaction testing
- Child component integration
- Event handling and state management
- Props and emits validation
Each component includes comprehensive stories:
// Component.stories.ts
export const Default: Story = {
args: {
/* default props */
},
parameters: {
docs: {
description: {
story: 'Description of this story variant',
},
},
},
};
export const WithExternalData: Story = {
args: { externalData: true },
// Demonstrates dynamic data loading
};project/
├── src/
│ ├── components/
│ │ ├── BasicButton/ # No-JS component example
│ │ ├── SimpleBanner/ # Petite-Vue component example
│ │ ├── HeroBanner/ # Vue component example
│ │ └── SimpleButton/ # Vue component example
│ └── composables/
│ └── useFetchData.ts # Shared utilities
├── bundles/
│ └── all.json # Bundle configurations
├── scripts/
│ └── export.ts # Export system logic
├── .storybook/ # Storybook configuration
├── docs/ # Storybook documentation (MDX files)
└── dist/ # Export output directory
- Node.js 18+
- npm
npm install
# Start Storybook development server
npm run dev
# Export a component
npm run export -- SimpleButton
# Export with webpage mode
npm run export:webpage -- HeroBanner
# Export a bundle
npm run export -- all
# Type checking
npm run typecheck
# Linting
npm run lint
# Formatting
npm run format
npm run dev- Start Storybook development servernpm run build:sb- Build Storybook for production
npm run export -- <ComponentName|BundleName>- Export for embedding (bare markup, split JS)npm run export:webpage -- <ComponentName|BundleName>- Export as webpage (full HTML, split JS)npm run export:single -- <ComponentName|BundleName>- Export for embedding (bare markup, single JS bundle)npm run export:single:webpage -- <ComponentName|BundleName>- Export as webpage (full HTML, single JS bundle)
npm run typecheck- Run TypeScript type checkingnpm run lint- Run ESLint with auto-fixnpm run lint:check- Run ESLint without fixingnpm run format- Format code with Prettiernpm run format:check- Check code formatting
BasicButton- No-JS HTML/CSS buttonSimpleBanner- Petite-Vue interactive bannerHeroBanner- Full Vue hero section with child componentsSimpleButton- Full Vue button component
all- All components bundled together
- Start with the simplest mode that meets requirements
- Use TypeScript interfaces for all component props
- Include comprehensive Storybook stories
- Test all three export modes for mixed bundles
- Provide meaningful default data in
.jsonfiles
- Use no-JS mode for static content delivery
- Use petite-Vue mode for CMS integration and progressive enhancement
- Use full Vue mode for Vue.js applications
- Create bundles for related component sets
- Use webpage mode for standalone component previews
- No-JS components have zero runtime overhead
- Petite-Vue adds ~10kb overhead but enables interactivity
- Full Vue components provide maximum features with larger bundle size
- Bundle components by usage context to optimize loading