Skip to content

fix: broken tailwind starter#9982

Merged
snowystinger merged 31 commits into
mainfrom
fix-broken-tailwind-starter
Apr 28, 2026
Merged

fix: broken tailwind starter#9982
snowystinger merged 31 commits into
mainfrom
fix-broken-tailwind-starter

Conversation

@snowystinger
Copy link
Copy Markdown
Member

Closes

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

🧢 Your Project:

snowystinger and others added 30 commits April 24, 2026 14:21
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rename .js -> .mjs, convert CJS require/exports to ESM import/export.
Ports five-virtual-file split from upgrade-sb-10 reference branch.
Uses createRequire for @parcel/utils (CJS-only package).
…s for Task 3.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…in.mjs at folders

Storybook 10's preset loader tries to import() any addon path that doesn't end
in "preset" as a Node.js module.  The custom-addons register.js files contain
JSX and cannot be parsed by Node.js, causing CriticalPresetLoadError on startup.

Fix: rename each register.js to manager.js so Storybook's resolveAddonName()
finds a *manager* file and returns type:"virtual" with managerEntries — meaning
Parcel bundles the file rather than Node.js importing it directly.  Update
main.mjs to reference the addon directories instead of the register.js paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ovider addon

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p crash

Parcel bundles storybook/internal/preview-api and chunk-SZQXB3JV.js into
a CJS bundle with a circular dependency. During initialization, the chunk's
top-level highlight/preview.ts runs `(_previewApi.addons)?.ready` before the
preview-api chunk's lazy getter has resolved its internal chunk reference.
Result: `TypeError: Cannot read properties of undefined (reading 'addons')`
fires as an unhandled promise rejection and the preview never initializes.

The line is guarded by `globalThis?.FEATURES?.highlight && ...` so setting
features.highlight=false short-circuits the buggy codepath. Trade-off:
disables the highlight feature used by addon-a11y for accessibility-violation
visualization.

This is a workaround; the underlying Parcel + SB10 bundling interaction
should be investigated as a follow-up.
…re FEATURES.highlight

Root-cause fix replacing the previous symptom-workaround. Storybook's
dist/csf/index.js has a circular dependency with dist/_browser-chunks/chunk-SZQXB3JV.js
and dist/preview-api/index.js. When Parcel's CJS bundler initialises these modules,
csf/index.js runs its highlight-addon preview.ts code (line 916) before the
storybook/preview-api module's 'addons' export is fully resolved. The resulting
getter access throws TypeError during the circular-dep init window.

The fix defers the highlight initialisation one microtask tick using
Promise.resolve().then(), wrapped in try/catch for belt-and-braces safety.
By the time the callback fires all circular deps are resolved and 'addons'
holds the live AddonStore instance. Highlights initialise correctly.

Patch is applied via patch-package (already in postinstall).
Restores FEATURES.highlight to its default true, preserving accessibility-
violation visualisation that addon-a11y depends on.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s to globals

Match upstream Storybook 10 builders (@storybook/builder-vite,
@storybook/builder-webpack5) by externalizing every module key in
storybook/internal/preview/globals.js's globalsNameReferenceMap. For each
specifier, the resolver returns a synthetic ESM cache file at
node_modules/.cache/sb-parcel-externals/<key>.js with shape:

  const { addons, PreviewWeb, ... } = globalThis.__STORYBOOK_MODULE_*;
  export { addons, PreviewWeb, ... };
  export default globalThis.__STORYBOOK_MODULE_*;

The runtime bundle (storybook/internal/preview/runtime) populates these
globals via its top-level setup() side effect; once Task 1.2 hoists the
runtime import, externalized modules resolve to live bindings on the
already-populated globals — eliminating the CJS circular-dep that the
node_modules patch currently masks.

This task adds the resolver only; preview-entry generator + iframe
template alignment follow in Tasks 1.2 and 1.3, after which Task 1.4
removes the patch.
…ew-api path

Move `import { setup } from 'storybook/internal/preview/runtime'` to be the
first import in the generated preview-main.js so runtime.js's top-level setup()
call populates __STORYBOOK_MODULE_* globals before setup-addons.js (or any other
externalized specifier) evaluates and tries to destructure those globals.

Also switch `from 'storybook/internal/preview-api'` to the public
`from 'storybook/preview-api'` to match the externalize map and upstream
Vite/webpack5 ordering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… upstream

After externalizing storybook runtime modules (Task 1.1) and hoisting
the runtime import (Task 1.2), runtime.js's setup() populates every
__STORYBOOK_MODULE_* global plus __STORYBOOK_ADDONS_PREVIEW and
__STORYBOOK_ADDONS_CHANNEL__. Our hand-rolled init-addons IIFE and
preview.js bootstrap entry exist only to mask the cycle that those
populate-the-globals tasks now resolve at the source.

- iframe.html: drop the inline init IIFE, add TAGS_OPTIONS / OTHER_GLOBALS
  placeholders, set window.module=undefined and window.global=window
  (matches upstream Vite); script tag now points at preview-main.js
- gen-preview-modern.mjs: remove generatePreviewBootstrap and
  generateInitAddonsGlobal helpers and their exports
- preset.mjs: stop emitting preview.js and init-addons-global.js to
  generated-entries; only setup-addons.js and preview-main.js are needed

The patch (patches/storybook+10.3.5.patch) is still in place and
removed in Task 1.4.
…externalize-runtime alignment)

Tasks 1.1-1.3 ported the upstream Storybook 10 externalize-the-runtime
pattern: storybook/preview-api and 9 sibling specifiers are now resolved
to synthetic cache files reading from globalThis.__STORYBOOK_MODULE_*,
populated by storybook/internal/preview/runtime's setup() side effect
which runs first in the preview entry. The Parcel CJS circular-dep
that motivated the patch (storybook/preview-api <-> chunk-SZQXB3JV.js
through dist/csf/index.js) no longer exists in our bundle graph because
storybook/preview-api is no longer bundled at all.

FEATURES.highlight is restored to its default true; addon-a11y's
violation visualization works again. Verified across all four config
dirs (.storybook, .storybook-s2, .chromatic, .chromatic-fc) for both
dev and build modes.
The @vueless/storybook-dark-mode toolbar toggle was a no-op in the v3/rac
Storybook because nothing in .storybook reacted to its DARK_MODE event.

- preview.js: subscribe to DARK_MODE_EVENT_NAME on the addons channel and
  reflect the state on document.documentElement.dataset.colorScheme.
  Initial value reads from the addon's `sb-addon-themes-3` localStorage key
  so the first paint is correct (matches the .storybook-s2 pattern).
- custom-addons/provider/index.js: consume useDarkMode() and feed isDark
  through to the React Spectrum Provider's `colorScheme` prop whenever the
  ProviderSwitcher dropdown is set to "Auto". An explicit dropdown choice
  still wins.
Add succinct comments at non-obvious decision points across the custom
Parcel-based Storybook 10 builder, referencing the official Builder API
docs (https://storybook.js.org/docs/builders/builder-api) and the upstream
@storybook/builder-vite and @storybook/builder-webpack5 reference
implementations. Highlights:

- parcel-resolver-storybook: top-of-file block explaining the
  externalize-the-runtime pattern, the globalsNameReferenceMap source,
  the .cache layout, and the CJS-cycle issue it sidesteps; per-branch
  comments for externals / react-dom/client shim / story: pipeline.
- storybook-builder-parcel/preset.mjs: Builder API contract summary,
  rationale for the 9003->3000 reverse proxy, list of the five generated
  files, and the bail() / module-scope watcher rationale.
- gen-preview-modern.mjs: explicit ordering rationale for runtime ->
  setup-addons -> PreviewWeb, why processPreviewAnnotation needs
  toPackageExportSpecifier under Parcel, and why toImportFn uses static
  imports + Object.assign instead of Promise.all + spread.
- gen-iframe-modern.mjs / templates/iframe.html: provenance from
  upstream Vite's input/iframe.html and the OTHER_GLOBALS placeholder
  workaround.
- StoryTransformer.ts / StorybookMDXTransformer.mjs: brief headers
  describing what each transformer does and the IPC-based docgen
  optimization.

No code logic changes; comments only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…torybook-10-upgrade"

This reverts commit bf62a86, reversing
changes made to edc24b0.
@snowystinger snowystinger changed the title Fix broken tailwind starter fix: broken tailwind starter Apr 25, 2026
This reverts commit 3267dae.
@rspbot
Copy link
Copy Markdown

rspbot commented Apr 25, 2026

@snowystinger snowystinger added this pull request to the merge queue Apr 28, 2026
Merged via the queue into main with commit d266cac Apr 28, 2026
29 checks passed
@snowystinger snowystinger deleted the fix-broken-tailwind-starter branch April 28, 2026 17:00
@yihuiliao yihuiliao added the no testing Does not require manual testing during testing session label May 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no testing Does not require manual testing during testing session

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants