Skip to content

Commit

Permalink
Disable HMR for web-components projects (#372)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
IanVS authored May 9, 2022
1 parent c526544 commit 7e5af52
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 19 deletions.
5 changes: 4 additions & 1 deletion examples/lit-ts/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 28 additions & 18 deletions packages/builder-vite/codegen-modern-iframe-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,45 @@ 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);
const configEntries = [...presetEntries, previewOrConfigFile]
.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';
Expand All @@ -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;
}

0 comments on commit 7e5af52

Please sign in to comment.