mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 14:54:37 +00:00
## Summary
Fixes Storybook rendering issue where all components fail to load with
`_sfc_main is not defined` error in **local development** since v1.29.3.
## Problem
After upgrading to v1.29.3, all Storybook components fail to render **in
local development** (`pnpm storybook`) with the following error:
```
ReferenceError: _sfc_main is not defined
The component failed to render properly, likely due to a configuration issue in Storybook.
```
**Important**: This issue only affects **local development**
environments. The deployed/built Storybook works correctly.
This affects both:
- Main Storybook (`pnpm storybook`)
- Desktop-ui Storybook instances
## Root Cause
In v1.29.3, commit `64430708e` ("perf: tree shaking and minify #6068")
enabled build optimizations in `vite.config.mts`:
```typescript
// Before (v1.29.2)
rollupOptions: {
treeshake: false
}
esbuild: {
minifyIdentifiers: false
}
// After (v1.29.3)
rollupOptions: {
treeshake: true // ⚠️ Enabled
}
esbuild: {
minifyIdentifiers: SHOULD_MINIFY // ⚠️ Conditionally enabled
}
```
While these optimizations are beneficial for production builds, they
cause issues in **Storybook's local dev server**:
1. **Tree-shaking in dev mode**: Rollup incorrectly identifies Vue SFC's
`_sfc_main` exports as unused code during the dev server's module
transformation
2. **Identifier minification**: esbuild minifies `_sfc_main` to shorter
names in development, breaking Storybook's HMR (Hot Module Replacement)
and dynamic module loading
Since Storybook's `main.ts` inherits settings from `vite.config.mts` via
`mergeConfig`, these optimizations were applied to Storybook's dev
server configuration, causing Vue components to fail rendering in local
development.
**Why deployed Storybook works**: Production builds have different
optimization pipelines that handle Vue SFCs correctly, but the dev
server's real-time transformation breaks with these settings.
## Solution
Added explicit build configuration overrides in both Storybook
configurations to ensure the **dev server** doesn't inherit problematic
optimizations:
**Files changed:**
- `.storybook/main.ts`
- `apps/desktop-ui/.storybook/main.ts`
**Changes:**
```typescript
esbuild: {
// Prevent minification of identifiers to preserve _sfc_main in dev mode
minifyIdentifiers: false,
keepNames: true
},
build: {
rollupOptions: {
// Disable tree-shaking for Storybook dev server to prevent Vue SFC exports from being removed
treeshake: false,
// ... existing onwarn config
}
}
```
This ensures Storybook's **local development server** prioritizes
stability and debuggability over bundle size optimization, while
production builds continue to benefit from tree-shaking and
minification.
## Testing
1. Cleared Storybook and Vite caches: `rm -rf .storybook/.cache
node_modules/.vite`
2. Started local Storybook dev server with `pnpm storybook`
3. Verified all component stories render correctly without `_sfc_main`
errors
4. Ran `pnpm typecheck` to ensure TypeScript compilation succeeds
5. Tested HMR (Hot Module Replacement) works correctly with component
changes
## Context
- This is a **local development-only** issue; deployed Storybook builds
work fine
- Storybook dev server requires special handling because it dynamically
imports and hot-reloads all stories at runtime
- Vue SFC compilation generates `_sfc_main` as an internal identifier
that must be preserved during dev transformations
- Development tools like Storybook benefit from unoptimized builds for
better debugging, HMR, and stability
- Production builds remain optimized with tree-shaking and minification
enabled
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6635-bugfix-Fix-Storybook-_sfc_main-undefined-error-after-v1-29-3-2a56d73d36508194a25eef56789e5e2b)
by [Unito](https://www.unito.io)
Storybook Configuration for ComfyUI Frontend
What is Storybook?
Storybook is a frontend workshop for building UI components and pages in isolation. It allows developers to:
- Build components independently from the main application
- Test components with different props and states
- Document component APIs and usage patterns
- Share components across teams and projects
- Catch visual regressions through visual testing
Storybook vs Other Testing Tools
| Tool | Purpose | Use Case |
|---|---|---|
| Storybook | Component isolation & documentation | Developing, testing, and showcasing individual UI components |
| Playwright | End-to-end testing | Full user workflow testing across multiple pages |
| Vitest | Unit testing | Testing business logic, utilities, and component behavior |
| Vue Testing Library | Component testing | Testing component interactions and DOM output |
When to Use Storybook
✅ Use Storybook for:
- Developing new UI components in isolation
- Creating component documentation and examples
- Testing different component states and props
- Sharing components with designers and stakeholders
- Visual regression testing
- Building a component library or design system
❌ Don't use Storybook for:
- Testing complex user workflows (use Playwright)
- Testing business logic (use Vitest)
- Integration testing between components (use Vue Testing Library)
How to Use Storybook
Development Commands
# Start Storybook development server
pnpm storybook
# Build static Storybook for deployment
pnpm build-storybook
Creating Stories
Stories are located alongside components in src/ directories with the pattern *.stories.ts:
// MyComponent.stories.ts
import type { Meta, StoryObj } from '@storybook/vue3'
import MyComponent from './MyComponent.vue'
const meta: Meta<typeof MyComponent> = {
title: 'Components/MyComponent',
component: MyComponent,
parameters: {
layout: 'centered'
}
}
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
title: 'Hello World'
}
}
export const WithVariant: Story = {
args: {
title: 'Variant Example',
variant: 'secondary'
}
}
Available Features
- Vue 3 Support: Full Vue 3 composition API and reactivity
- PrimeVue Integration: All PrimeVue components and theming
- ComfyUI Theming: Custom ComfyUI theme preset applied
- Pinia Stores: Access to application stores for components that need state
- TypeScript: Full TypeScript support with proper type checking
- CSS/SCSS: Component styling support
- Auto-documentation: Automatic prop tables and component documentation
- Chromatic Integration: Automated visual regression testing for component stories
Development Tips
ComfyUI Storybook Guidelines
Scope – When to Create Stories
- PrimeVue components:
No need to create stories. Just refer to the official PrimeVue documentation. - Custom shared components (design system components):
Always create stories. These components are built in collaboration with designers, and Storybook serves as both documentation and a communication tool. - Container components (logic-heavy):
Do not create stories. Only the underlying pure UI components should be included in Storybook.
Maintenance Philosophy
- Stories are lightweight and generally stable.
Once created, they rarely need updates unless:- The design changes
- New props (e.g. size, color variants) are introduced
- For existing usage patterns, simply copy real code examples into Storybook to create stories.
File Placement
- Keep
*.stories.tsfiles at the same level as the component (similar to test files). - This makes it easier to check usage examples without navigating to another directory.
Developer/Designer Workflow
- UI vs Container: Separate pure UI components from container components.
Only UI components should live in Storybook. - Communication Tool: Storybook is not just about code quality—it enables designers and developers to see:
- Which props exist
- What cases are covered
- How variants (e.g. size, colors) look in isolation
- Example:
PackActionButton.vuewraps a PrimeVue button with additional logic.
→ Only create a story for the base UI button, not for the wrapper.
Suggested Workflow
- Use PrimeVue docs for standard components
- Use Storybook for shared/custom components that define our design system
- Keep story files alongside components
- When in doubt, focus on components reused across the app or those that need to be showcased to designers
Best Practices
- Keep Stories Simple: Each story should demonstrate one specific use case
- Use Realistic Data: Use data that resembles real application usage
- Document Edge Cases: Create stories for loading states, errors, and edge cases
- Group Related Stories: Use consistent naming and grouping for related components
Component Testing Strategy
// Example: Testing different component states
export const Loading: Story = {
args: {
isLoading: true
}
}
export const Error: Story = {
args: {
error: 'Failed to load data'
}
}
export const WithLongText: Story = {
args: {
description: 'Very long description that might cause layout issues...'
}
}
Debugging Tips
- Use browser DevTools to inspect component behavior
- Check the Storybook console for Vue warnings or errors
- Use the Controls addon to dynamically change props
- Leverage the Actions addon to test event handling
Configuration Files
main.ts: Core Storybook configuration and Vite integrationpreview.ts: Global decorators, parameters, and Vue app setupmanager.ts: Storybook UI customization (if needed)preview-head.html: Injects custom HTML into the<head>of every Storybook iframe (used for global styles, fonts, or fixes for iframe-specific issues)
Chromatic Visual Testing
This project uses Chromatic for automated visual regression testing of Storybook components.
How It Works
- Automated Testing: Every push to
mainandsno-storybookbranches triggers Chromatic builds - Pull Request Reviews: PRs against
mainbranch include visual diffs for component changes - Baseline Management: Changes on
mainbranch are automatically accepted as new baselines - Cross-browser Testing: Tests across multiple browsers and viewports
Viewing Results
- Check the GitHub Actions tab for Chromatic workflow status
- Click on the Chromatic build link in PR comments to review visual changes
- Accept or reject visual changes directly in the Chromatic UI
Best Practices for Visual Testing
- Consistent Stories: Ensure stories render consistently across different environments
- Meaningful Names: Use descriptive story names that clearly indicate the component state
- Edge Cases: Include stories for loading, error, and empty states
- Realistic Data: Use data that closely resembles production usage
Integration with ComfyUI
This Storybook setup includes:
- ComfyUI-specific theming and styling
- Pre-configured Pinia stores for state management
- Internationalization (i18n) support
- PrimeVue component library integration
- Proper alias resolution for
@/imports
Icon Usage in Storybook
In this project, only the <i class="icon-[lucide--folder]" /> syntax from unplugin-icons is supported in Storybook.
Example:
<script setup lang="ts">
</script>
<template>
<i class="icon-[lucide--trophy] text-neutral size-4" />
<i class="icon-[lucide--settings] text-neutral size-4" />
</template>
This approach ensures icons render correctly in Storybook and remain consistent with the rest of the app.