Skip to content

Latest commit

 

History

History
156 lines (111 loc) · 7.15 KB

File metadata and controls

156 lines (111 loc) · 7.15 KB

Performance

Emulsify Core favors predictable output and simple project configuration. The defaults are suitable for small and medium component libraries, and the release fixtures cover the main supported structures. Larger libraries should keep source roots intentional and use the fixture commands below to compare changes.

For repeated developer-workload measurements, use the opt-in audit, resolver, and browser benchmarks. The 4.5.0 measurements distinguish release behavior changes from the measured grouped-resolver optimization.

Development Sourcemaps

vite build --watch leaves JavaScript and CSS readable and emits external maps for JavaScript and direct stylesheet entries. One-shot production builds minify both and omit maps:

build: {
  sourcemap: watching,
  minify: !watching,
  cssMinify: !watching,
}

Vite normally discards the Sass/PostCSS map when a build extracts CSS as a Rollup asset. Core retains the combined map for each direct stylesheet entry, attaches it to the finalized CSS, and rebases source paths when Drupal moves a component map from dist/components/ to root components/. Final asset URL rewrites preserve line mappings; a length-changing URL can shift columns inside that value without changing the selector or declaration's source line.

Development maps remain on disk for devtools but are excluded from reporter counts, sizes, largest-file summaries, verbose listings, and rebuild details.

Storybook Twig Imports

Storybook's Twig resolver eagerly imports compiled Twig modules with import.meta.glob(..., { eager: true }), but raw Twig source strings and text asset strings for source() are loaded lazily.

This supports:

  • include() for Twig templates.
  • source() for raw Twig source, loaded on demand and cached after the first request.
  • source('@assets/...') for inline text assets, loaded on demand from build-time asset source maps.
  • Namespaces derived from project.emulsify.json.

Compiled Twig modules stay eager because Storybook stories need synchronous render functions. Raw source loading is deferred because most projects call source() for only a small subset of templates and assets. The first render that asks for a lazy raw source may render without that source while the dynamic import resolves; Emulsify then re-renders the Twig story and subsequent renders read the cached string synchronously.

Large projects with many generated, archived, or CMS-only Twig files can still see larger Storybook output from compiled module imports, but lazy raw source loading reduces the retained string heap for templates and text assets that never call source().

For large libraries:

  • Keep only active Storybook-rendered Twig files under Storybook source roots.
  • Move generated or archived Twig files outside src/components, root ./components, or explicit variant.structureImplementations roots when Storybook does not need them.
  • Prefer explicit variant.structureImplementations roots when a repository has multiple source areas.
  • Avoid storing large raw fixtures under Twig roots unless stories need to render or source() them.

Storybook Text Asset Sources

source('@assets/foo.svg') first checks a Core-generated build-time asset source map. That internal map is generated from configured assets.roots plus existing assets and src/assets directories. SVG, HTML, Twig, CSS, JavaScript, JSON, TXT, and Markdown files are lazy ?raw imports.

This removes the common synchronous XHR path for inline assets. A first render that requests a new text asset may render without it while the import resolves; the Storybook Twig renderer re-renders and subsequent reads are synchronous from memory.

The sync-XHR fallback is disabled by default. Its deprecated opt-in is reached only when the generated module reports no asset-root coverage; it is not a general fallback for a missing file in an active asset map:

platformAdapter: {
  storybook: {
    allowSyncXhrSource: true,
  },
}

That fallback blocks the main thread and is scheduled for removal in a future major release.

Storybook CSS Loading

Storybook eagerly imports CSS from the selected render path by default so component styles are available in the iframe. none and wordpress projects load compiled CSS from dist/**/*.css. Drupal projects that mirror component output load component CSS from components/**/*.css and shared compiled CSS from dist/**/*.css excluding dist/components/**/*.css, because dist/components and root components represent the same component CSS through different paths.

The eager glob performs the CSS imports directly; no runtime iteration is needed after the glob runs.

Projects with very large CSS libraries can opt out and import CSS from their own Storybook preview override:

export const parameters = {
  emulsify: {
    loadAllCSS: false,
  },
};

When emulsify.loadAllCSS is false, Emulsify skips the eager CSS glob entirely.

Tailwind Scanning

Tailwind CSS v4 can scan project sources automatically, but explicit @source lines make Emulsify structures easier to reason about:

@import 'tailwindcss';

@source "../components";
@source "../../components";
@source "../foundation";
@source "../layout";
@source "../tokens";

Use only the roots your project actually uses. Do not point Tailwind at dist/, .out/, node_modules/, generated fixture output, or archived templates.

Copied Files Versus Compiled Files

Emulsify Core compiles JavaScript and Sass/CSS entries. It copies Twig templates, component metadata, and static component assets.

Copied files are intentionally not transformed by Vite. This keeps CMS-facing templates and metadata predictable and avoids unnecessary build work. The copy pass uses the normalized project structure model so copied files land beside the matching compiled output.

Validation Commands

Use these commands to compare release-readiness behavior:

npm run fixtures:release

Release fixtures live under .github/fixtures/release/. They are repository development assets for CI and local validation, and are not included in the npm package installed by consuming projects.

Run one fixture when debugging a specific project shape:

npm run fixtures:release -- --fixture mixed-storybook
npm run fixtures:release -- --fixture large-twig-storybook

List available fixtures:

npm run fixtures:release:list

The large-twig-storybook fixture reports Storybook build time, total output size, total JavaScript size, fixture-owned JavaScript size, and generated Twig component count. Build timing is trend data for comparison under equivalent conditions; it has no fixed pass/fail duration budget.

There is a separate enforced byte ceiling in scripts/release-fixtures.js: fixture-owned JavaScript must total less than 182,329 bytes. The ceiling is exclusive, so 182,329 bytes fails. It applies only to the fixture's _content-*, gallery-*, gallery.stories-*, and item-* JavaScript chunks under storybook-assets/, not all Storybook manager/runtime chunks or the total output size. Changing this byte limit is a fixture policy change; it is not a timing result.