From 7e5af52ae8934232102ec14addf1e18ece478a80 Mon Sep 17 00:00:00 2001 From: Ian VanSchooten Date: Mon, 9 May 2022 16:19:38 -0400 Subject: [PATCH] Disable HMR for web-components projects (#372) Fixes #370. When using `storyStoreV7`, we configure HMR to swap out the `importFn` when stories change. However, this breaks web-components projects (see https://github.com/storybookjs/storybook/tree/master/app/web-components#setup-page-reload-via-hmr). So, instead, this change checks if the framework is `web-components` and if so, refreshes the page instead of performing an HMR. It's still pretty quick, and not a full page reload. You can test this out by starting up our `lit-ts` example (which I've configured to use storyStoreV7 now), open the story, and save the component or story file. It shouldn't blow up anymore. One bummer is that MDX files also no longer HMR, though technically they could. But I can't find a way to detect which part of the `importFn` changed, in order to determine whether to HMR or not, and it's safer to just avoid it for all stories when using web-components. --- examples/lit-ts/.storybook/main.ts | 5 +- .../codegen-modern-iframe-script.ts | 46 +++++++++++-------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/examples/lit-ts/.storybook/main.ts b/examples/lit-ts/.storybook/main.ts index 4b13e910..b5d72c17 100644 --- a/examples/lit-ts/.storybook/main.ts +++ b/examples/lit-ts/.storybook/main.ts @@ -8,7 +8,10 @@ module.exports = { builder: '@storybook/builder-vite', }, framework: '@storybook/web-components', - features: { buildStoriesJson: true }, + features: { + buildStoriesJson: true, + storyStoreV7: true, + }, async viteFinal(config, { configType }) { return mergeConfig(config, { // prettier-ignore diff --git a/packages/builder-vite/codegen-modern-iframe-script.ts b/packages/builder-vite/codegen-modern-iframe-script.ts index 31b43b05..83725493 100644 --- a/packages/builder-vite/codegen-modern-iframe-script.ts +++ b/packages/builder-vite/codegen-modern-iframe-script.ts @@ -4,7 +4,7 @@ import { transformAbsPath } from './utils/transform-abs-path'; import type { ExtendedOptions } from './types'; export async function generateModernIframeScriptCode(options: ExtendedOptions) { - const { presets, configDir } = options; + const { presets, configDir, framework } = options; const previewOrConfigFile = loadPreviewOrConfigFile({ configDir }); const presetEntries = await presets.apply('config', [], options); @@ -12,14 +12,37 @@ export async function generateModernIframeScriptCode(options: ExtendedOptions) { .filter(Boolean) .map((configEntry) => transformAbsPath(configEntry)); - // noinspection UnnecessaryLocalVariableJS + const generateHMRHandler = (framework: string): string => { + // Web components are not compatible with HMR, so disable HMR, reload page instead. + if (framework === 'web-components') { + return ` + if (import.meta.hot) { + import.meta.hot.decline(); + }`.trim(); + } + + return ` + if (import.meta.hot) { + import.meta.hot.accept('${virtualStoriesFile}', (newModule) => { + // importFn has changed so we need to patch the new one in + preview.onStoriesChanged({ importFn: newModule.importFn }); + }); + + import.meta.hot.accept(${JSON.stringify(configEntries)}, ([...newConfigEntries]) => { + const newGetProjectAnnotations = () => composeConfigs(newConfigEntries); + + // getProjectAnnotations has changed so we need to patch the new one in + preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations }); + }); + }`.trim(); + }; + /** * This code is largely taken from https://github.com/storybookjs/storybook/blob/d1195cbd0c61687f1720fefdb772e2f490a46584/lib/builder-webpack4/src/preview/virtualModuleModernEntry.js.handlebars * Some small tweaks were made to `getProjectAnnotations` (since `import()` needs to be resolved asynchronously) * and the HMR implementation has been tweaked to work with Vite. * @todo Inline variable and remove `noinspection` */ - // language=JavaScript const code = ` import { composeConfigs, PreviewWeb } from '@storybook/preview-web'; import { ClientApi } from '@storybook/client-api'; @@ -38,21 +61,8 @@ export async function generateModernIframeScriptCode(options: ExtendedOptions) { window.__STORYBOOK_CLIENT_API__ = new ClientApi({ storyStore: preview.storyStore }); preview.initialize({ importFn, getProjectAnnotations }); - - if (import.meta.hot) { - import.meta.hot.accept('${virtualStoriesFile}', (newModule) => { - - // importFn has changed so we need to patch the new one in - preview.onStoriesChanged({ importFn: newModule.importFn }); - }); - - import.meta.hot.accept(${JSON.stringify(configEntries)}, ([...newConfigEntries]) => { - const newGetProjectAnnotations = () => composeConfigs(newConfigEntries); - - // getProjectAnnotations has changed so we need to patch the new one in - preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations }); - }); - } + + ${generateHMRHandler(framework)}; `.trim(); return code; }