diff --git a/code/core/src/common/utils/load-main-config.ts b/code/core/src/common/utils/load-main-config.ts index 579680e8da8f..b02ac8d6a42c 100644 --- a/code/core/src/common/utils/load-main-config.ts +++ b/code/core/src/common/utils/load-main-config.ts @@ -14,16 +14,18 @@ import { validateConfigurationFiles } from './validate-configuration-files'; export async function loadMainConfig({ configDir = '.storybook', cwd, + skipCache, }: { configDir: string; cwd?: string; + skipCache?: boolean; }): Promise { await validateConfigurationFiles(configDir, cwd); const mainPath = getInterpretedFile(resolve(configDir, 'main')) as string; try { - const out = await importModule(mainPath); + const out = await importModule(mainPath, { skipCache }); return out; } catch (e) { if (!(e instanceof Error)) { diff --git a/code/core/src/shared/utils/module.ts b/code/core/src/shared/utils/module.ts index 10eb9812ccf7..e4aa51f84e35 100644 --- a/code/core/src/shared/utils/module.ts +++ b/code/core/src/shared/utils/module.ts @@ -51,7 +51,10 @@ let isTypescriptLoaderRegistered = false; * // Returns the default export or the entire module * ``` */ -export async function importModule(path: string) { +export async function importModule( + path: string, + { skipCache = false }: { skipCache?: boolean } = {} +) { if (!isTypescriptLoaderRegistered) { const typescriptLoaderUrl = importMetaResolve('storybook/internal/bin/loader'); register(typescriptLoaderUrl, import.meta.url); @@ -61,12 +64,17 @@ export async function importModule(path: string) { let mod; try { const resolvedPath = win32.isAbsolute(path) ? pathToFileURL(path).href : path; - mod = await import(resolvedPath); + // When applicable, add a hash to the import URL to bypass cache + const importUrl = skipCache ? `${resolvedPath}?${Date.now()}` : resolvedPath; + mod = await import(importUrl); } catch (importError) { try { // fallback to require to support older behavior // this is relevant for presets that are only available with the "require" condition in a package's export map const require = createRequire(import.meta.url); + if (skipCache) { + delete require.cache[require.resolve(path)]; + } mod = require(path); } catch (requireError) { /* diff --git a/code/lib/cli-storybook/src/add.ts b/code/lib/cli-storybook/src/add.ts index 3d6fb548a7f2..95ca4722a0bd 100644 --- a/code/lib/cli-storybook/src/add.ts +++ b/code/lib/cli-storybook/src/add.ts @@ -1,8 +1,6 @@ -import { isAbsolute, join } from 'node:path'; - import { type PackageManagerName, - serverRequire, + loadMainConfig, syncStorybookAddons, versions, } from 'storybook/internal/common'; @@ -182,7 +180,8 @@ export async function add( // TODO: remove try/catch once CSF factories is shipped, for now gracefully handle any error try { - await syncStorybookAddons(mainConfig, previewConfigPath!, configDir); + const newMainConfig = await loadMainConfig({ configDir, skipCache: true }); + await syncStorybookAddons(newMainConfig, previewConfigPath!, configDir); } catch (e) { // }