fix(plugin): reload preview on external Stencil builds via staticDirs#53
Open
davidpett wants to merge 4 commits into
Open
fix(plugin): reload preview on external Stencil builds via staticDirs#53davidpett wants to merge 4 commits into
davidpett wants to merge 4 commits into
Conversation
Consumers that run `stencil build --watch` separately and serve the prebuilt output through Storybook `staticDirs` (e.g. `['../dist/esm']`) with a lazy `defineCustomElements()` never import a component `.tsx` into Vite's module graph. unplugin-stencil therefore never compiles the project, its style/component dependency maps stay empty, and the existing eager/lazy/style reload paths can't fire — so `dist/esm` rebuilds on disk while the preview never reloads. Watch the resolved `staticDirs` directories directly: register them with the Vite watcher (they live outside the root, so chokidar won't track them otherwise) and, on a `*.js` change, invalidate the cached dist/esm modules and send the `stencil:reload` event. Reloads are debounced since one external rebuild rewrites many chunks at once, and skipped while a lazy in-graph rebuild is pending to avoid double reloads. Auto-detected and opt-in: a no-op when no `staticDirs` are configured.
Condense the verbose comments added for the external-build reload path and read `options.configType` inline instead of destructuring.
The preview can hit a late Vite dep-optimization pass ("optimized
dependencies changed. reloading") just after boot, tearing down the
iframe mid-render and leaving the `before` hook waiting on a detached
document until it times out. Re-enter the frame and re-query each tick
so a reload here no longer flakes the suite.
…ion reload
Storybook and Stencil deps (`storybook/internal/docs-tools`,
`@stencil/core`, `@stencil/core/internal/client`) were discovered lazily
on the first preview load, triggering a Vite dep re-optimization
("optimized dependencies changed. reloading") that tore down the iframe
just as the first story rendered. Pre-bundle them via `optimizeDeps`
so all optimization happens at startup and the preview renders once,
without a surprise reload — which also stabilizes the HMR e2e suite.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two related fixes for the Stencil Storybook dev preview:
stencil build --watchand serves the prebuilt output through StorybookstaticDirs(e.g.staticDirs: ['../dist/esm']) with a lazydefineCustomElements()inpreview.tsx.1. External-build HMR
In the external-build / lazy setup, stories never import a component
.tsxinto Vite's module graph, so the injectedunplugin-stencilnever compiles the project and its dependency maps stay empty. On a rebuild the externalstencil --watchrewritesdist/esm/*.js, but those are static assets Vite doesn't track as modules — so the existing eager / lazy / style reload paths instencilPreviewReloadPlugincan't fire and the preview never reloads.Changes in
packages/plugin/src/preset.ts:staticDirsto absolute paths inviteFinal(viaoptions.presets.apply('staticDirs'), relative toconfigDir) and pass them tostencilPreviewReloadPlugin.server.watcher.add()those dirs —dist/esmlives outside Vite's root, so chokidar won't watch it otherwise.*.jschange inside a watched static dir, invalidate the cacheddist/esmmodules and send the existingstencil:reloadevent.Auto-detected / opt-in: a no-op when no
staticDirsare configured.2. Pre-bundle deps to avoid mid-session reload
storybook/internal/docs-tools,@stencil/core, and@stencil/core/internal/clientwere discovered lazily on the first preview load, triggering Vite dep re-optimizations (optimized dependencies changed. reloading) that tore down the iframe as the first story rendered. This surfaced as a CI flake in the HMR e2e suite (the reload raced the initial<my-component>render) but also affects real users as a surprise full reload on first load.optimizeDeps.includefor those deps so all optimization happens at startup and the preview renders once, without a reload.beforehook (tests/hmr.e2e.ts) to re-enter the iframe and re-query across any reload, as defense-in-depth.Test plan
example-lazy(externalstencil build --watch+staticDirs: ['../dist/esm']): preview renders with no startup reload; editing a component reloads the preview.example(eager, in-graph): editing a component/style reloads once (no double-fire / regression).reloadingmessages observed in either suite after pre-bundling.build_and_testgreen.