diff --git a/code/lib/core-common/package.json b/code/lib/core-common/package.json index b9a99f8c2866..4de4e355038c 100644 --- a/code/lib/core-common/package.json +++ b/code/lib/core-common/package.json @@ -44,6 +44,7 @@ }, "dependencies": { "@babel/core": "^7.20.2", + "@storybook/csf-tools": "7.0.0-beta.34", "@storybook/node-logger": "7.0.0-beta.34", "@storybook/types": "7.0.0-beta.34", "@types/babel__core": "^7.1.20", diff --git a/code/lib/core-common/src/utils/load-main-config.ts b/code/lib/core-common/src/utils/load-main-config.ts index 743a863a956a..c2168816d5fa 100644 --- a/code/lib/core-common/src/utils/load-main-config.ts +++ b/code/lib/core-common/src/utils/load-main-config.ts @@ -3,8 +3,12 @@ import type { StorybookConfig } from '@storybook/types'; import { serverRequire } from './interpret-require'; import { validateConfigurationFiles } from './validate-configuration-files'; -export function loadMainConfig({ configDir }: { configDir: string }): StorybookConfig { - validateConfigurationFiles(configDir); +export async function loadMainConfig({ + configDir, +}: { + configDir: string; +}): Promise { + await validateConfigurationFiles(configDir); return serverRequire(path.resolve(configDir, 'main')); } diff --git a/code/lib/core-common/src/utils/validate-configuration-files.ts b/code/lib/core-common/src/utils/validate-configuration-files.ts index 040a12b1191d..6c7c64e416d4 100644 --- a/code/lib/core-common/src/utils/validate-configuration-files.ts +++ b/code/lib/core-common/src/utils/validate-configuration-files.ts @@ -1,20 +1,29 @@ import { dedent } from 'ts-dedent'; import glob from 'glob'; import path from 'path'; +import { readConfig } from '@storybook/csf-tools'; +import { once } from '@storybook/node-logger'; import { boost } from './interpret-files'; -export function validateConfigurationFiles(configDir: string) { +export async function validateConfigurationFiles(configDir: string) { const extensionsPattern = `{${Array.from(boost).join(',')}}`; - const exists = (file: string) => - !!glob.sync(path.resolve(configDir, `${file}${extensionsPattern}`)).length; + const mainConfigMatches = glob.sync(path.resolve(configDir, `main${extensionsPattern}`)); - const main = exists('main'); + const [mainConfigPath] = mainConfigMatches; - if (!main) { + if (!mainConfigPath) { throw new Error(dedent` No configuration files have been found in your configDir (${path.resolve(configDir)}). - Storybook needs either a "main" or "config" file. + Storybook needs "main.js" file, please add it. `); + } else { + const main = await readConfig(mainConfigPath); + if (!main.hasDefaultExport) { + once.warn(dedent` + Your main.js is not using a default export, which is the recommended format. Please update it. + For more info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#esm-format-in-mainjs + `); + } } } diff --git a/code/lib/core-server/src/build-dev.ts b/code/lib/core-server/src/build-dev.ts index bac27a0069b6..da8e2d2c2972 100644 --- a/code/lib/core-server/src/build-dev.ts +++ b/code/lib/core-server/src/build-dev.ts @@ -67,7 +67,7 @@ export async function buildDevStandalone( options.serverChannelUrl = getServerChannelUrl(port, options); /* eslint-enable no-param-reassign */ - const { framework } = loadMainConfig(options); + const { framework } = await loadMainConfig(options); const corePresets = []; const frameworkName = typeof framework === 'string' ? framework : framework?.name; diff --git a/code/lib/core-server/src/build-static.ts b/code/lib/core-server/src/build-static.ts index 78bffa6c28c0..f8f651a05c2b 100644 --- a/code/lib/core-server/src/build-static.ts +++ b/code/lib/core-server/src/build-static.ts @@ -63,7 +63,7 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption await emptyDir(options.outputDir); await ensureDir(options.outputDir); - const { framework } = loadMainConfig(options); + const { framework } = await loadMainConfig(options); const corePresets = []; const frameworkName = typeof framework === 'string' ? framework : framework?.name; diff --git a/code/lib/csf-tools/src/ConfigFile.ts b/code/lib/csf-tools/src/ConfigFile.ts index d0ac7daf02be..caaccf2ae7b8 100644 --- a/code/lib/csf-tools/src/ConfigFile.ts +++ b/code/lib/csf-tools/src/ConfigFile.ts @@ -119,6 +119,8 @@ export class ConfigFile { fileName?: string; + hasDefaultExport = false; + constructor(ast: t.File, code: string, fileName?: string) { this._ast = ast; this._code = code; @@ -131,6 +133,7 @@ export class ConfigFile { traverse.default(this._ast, { ExportDefaultDeclaration: { enter({ node, parent }) { + self.hasDefaultExport = true; const decl = t.isIdentifier(node.declaration) && t.isProgram(parent) ? _findVarInitialization(node.declaration.name, parent) diff --git a/code/lib/telemetry/src/storybook-metadata.ts b/code/lib/telemetry/src/storybook-metadata.ts index 6973345880e6..f0445252acf9 100644 --- a/code/lib/telemetry/src/storybook-metadata.ts +++ b/code/lib/telemetry/src/storybook-metadata.ts @@ -189,7 +189,7 @@ export const getStorybookMetadata = async (_configDir?: string) => { '--config-dir' ) as string)) ?? '.storybook'; - const mainConfig = loadMainConfig({ configDir }); + const mainConfig = await loadMainConfig({ configDir }); cachedMetadata = await computeStorybookMetadata({ mainConfig, packageJson }); return cachedMetadata; }; diff --git a/code/yarn.lock b/code/yarn.lock index 848cada3cc27..947c822ee7fb 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6050,6 +6050,7 @@ __metadata: resolution: "@storybook/core-common@workspace:lib/core-common" dependencies: "@babel/core": ^7.20.2 + "@storybook/csf-tools": 7.0.0-beta.34 "@storybook/node-logger": 7.0.0-beta.34 "@storybook/types": 7.0.0-beta.34 "@types/babel__core": ^7.1.20