diff --git a/code/builders/builder-vite/src/index.ts b/code/builders/builder-vite/src/index.ts index 614dc87bc561..80b1ac875377 100644 --- a/code/builders/builder-vite/src/index.ts +++ b/code/builders/builder-vite/src/index.ts @@ -25,7 +25,8 @@ export * from './types'; */ export type StorybookViteConfig = StorybookBaseConfig & StorybookConfigVite; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; function iframeMiddleware(options: Options, server: ViteDevServer): RequestHandler { return async (req, res, next) => { @@ -66,7 +67,7 @@ export const start: ViteBuilder['start'] = async ({ }) => { server = await createViteServer(options as Options, devServer); - const previewResolvedDir = wrapForPnP('@storybook/preview'); + const previewResolvedDir = getAbsolutePath('@storybook/preview'); const previewDirOrigin = join(previewResolvedDir, 'dist'); router.use(`/sb-preview`, express.static(previewDirOrigin, { immutable: true, maxAge: '5m' })); @@ -84,7 +85,7 @@ export const start: ViteBuilder['start'] = async ({ export const build: ViteBuilder['build'] = async ({ options }) => { const viteCompilation = viteBuild(options as Options); - const previewResolvedDir = wrapForPnP('@storybook/preview'); + const previewResolvedDir = getAbsolutePath('@storybook/preview'); const previewDirOrigin = join(previewResolvedDir, 'dist'); const previewDirTarget = join(options.outputDir || '', `sb-preview`); diff --git a/code/builders/builder-webpack5/package.json b/code/builders/builder-webpack5/package.json index 4b835f82677b..4abf9073ca54 100644 --- a/code/builders/builder-webpack5/package.json +++ b/code/builders/builder-webpack5/package.json @@ -55,7 +55,7 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@babel/core": "^7.22.0", + "@babel/core": "^7.22.9", "@storybook/addons": "7.1.0", "@storybook/channels": "7.1.0", "@storybook/client-api": "7.1.0", diff --git a/code/builders/builder-webpack5/src/index.ts b/code/builders/builder-webpack5/src/index.ts index 35f1fea6c81f..0106cfea091d 100644 --- a/code/builders/builder-webpack5/src/index.ts +++ b/code/builders/builder-webpack5/src/index.ts @@ -20,7 +20,8 @@ export const printDuration = (startTime: [number, number]) => .replace(' s', ' seconds') .replace(' m', ' minutes'); -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; let compilation: ReturnType | undefined; let reject: (reason?: any) => void; @@ -175,7 +176,7 @@ const starter: StarterFunction = async function* starterGeneratorFn({ compilation = webpackDevMiddleware(compiler, middlewareOptions); - const previewResolvedDir = wrapForPnP('@storybook/preview'); + const previewResolvedDir = getAbsolutePath('@storybook/preview'); const previewDirOrigin = join(previewResolvedDir, 'dist'); router.use(`/sb-preview`, express.static(previewDirOrigin, { immutable: true, maxAge: '5m' })); @@ -288,7 +289,7 @@ const builder: BuilderFunction = async function* builderGeneratorFn({ startTime, }); }); - const previewResolvedDir = wrapForPnP('@storybook/preview'); + const previewResolvedDir = getAbsolutePath('@storybook/preview'); const previewDirOrigin = join(previewResolvedDir, 'dist'); const previewDirTarget = join(options.outputDir || '', `sb-preview`); diff --git a/code/builders/builder-webpack5/src/preview/iframe-webpack.config.ts b/code/builders/builder-webpack5/src/preview/iframe-webpack.config.ts index 44ec4e92c8e5..d2f6ec6affbc 100644 --- a/code/builders/builder-webpack5/src/preview/iframe-webpack.config.ts +++ b/code/builders/builder-webpack5/src/preview/iframe-webpack.config.ts @@ -27,7 +27,8 @@ import { dedent } from 'ts-dedent'; import type { BuilderOptions, TypescriptOptions } from '../types'; import { createBabelLoader, createSWCLoader } from './loaders'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; const storybookPaths: Record = { ...[ @@ -40,12 +41,12 @@ const storybookPaths: Record = { ].reduce( (acc, sbPackage) => ({ ...acc, - [`@storybook/${sbPackage}`]: wrapForPnP(`@storybook/${sbPackage}`), + [`@storybook/${sbPackage}`]: getAbsolutePath(`@storybook/${sbPackage}`), }), {} ), // deprecated, remove in 8.0 - [`@storybook/api`]: wrapForPnP(`@storybook/manager-api`), + [`@storybook/api`]: getAbsolutePath(`@storybook/manager-api`), }; export default async ( diff --git a/code/frameworks/angular/src/preset.ts b/code/frameworks/angular/src/preset.ts index 6e359b452138..ce5796d0c222 100644 --- a/code/frameworks/angular/src/preset.ts +++ b/code/frameworks/angular/src/preset.ts @@ -3,7 +3,8 @@ import { PresetProperty } from '@storybook/types'; import { StorybookConfig } from './types'; import { StandaloneOptions } from './builders/utils/standalone-options'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ require.resolve('./server/framework-preset-angular-cli'), @@ -30,7 +31,7 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, }; diff --git a/code/frameworks/ember/src/preset.ts b/code/frameworks/ember/src/preset.ts index bedd1cdb3ebd..6524132780e5 100644 --- a/code/frameworks/ember/src/preset.ts +++ b/code/frameworks/ember/src/preset.ts @@ -2,7 +2,8 @@ import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ require.resolve('./server/framework-preset-babel-ember'), @@ -15,7 +16,7 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, }; diff --git a/code/frameworks/html-vite/src/preset.ts b/code/frameworks/html-vite/src/preset.ts index 814831785a39..4ae871b6e589 100644 --- a/code/frameworks/html-vite/src/preset.ts +++ b/code/frameworks/html-vite/src/preset.ts @@ -1,7 +1,12 @@ import type { PresetProperty } from '@storybook/types'; +import { dirname, join } from 'path'; import type { StorybookConfig } from './types'; +function getAbsolutePath(value: I): I { + return dirname(require.resolve(join(value, 'package.json'))) as any; +} + export const core: PresetProperty<'core', StorybookConfig> = { - builder: '@storybook/builder-vite', - renderer: '@storybook/html', + builder: getAbsolutePath('@storybook/builder-vite'), + renderer: getAbsolutePath('@storybook/html'), }; diff --git a/code/frameworks/html-webpack5/src/preset.ts b/code/frameworks/html-webpack5/src/preset.ts index 57093fdba5d3..969bee1b1e63 100644 --- a/code/frameworks/html-webpack5/src/preset.ts +++ b/code/frameworks/html-webpack5/src/preset.ts @@ -2,10 +2,11 @@ import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ - wrapForPnP('@storybook/preset-html-webpack'), + getAbsolutePath('@storybook/preset-html-webpack'), ]; export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { @@ -14,9 +15,9 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, - renderer: wrapForPnP('@storybook/html'), + renderer: getAbsolutePath('@storybook/html'), }; }; diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index 8823db34ade8..46d2a31d092b 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -64,12 +64,12 @@ "@babel/plugin-proposal-object-rest-spread": "^7.20.7", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.20.0", - "@babel/plugin-transform-runtime": "^7.22.0", - "@babel/preset-env": "^7.22.0", - "@babel/preset-react": "^7.22.0", - "@babel/preset-typescript": "^7.21.0", - "@babel/runtime": "^7.22.0", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-transform-runtime": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/preset-react": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", "@storybook/addon-actions": "7.1.0", "@storybook/builder-webpack5": "7.1.0", "@storybook/core-common": "7.1.0", @@ -97,8 +97,8 @@ "tsconfig-paths-webpack-plugin": "^4.0.1" }, "devDependencies": { - "@babel/core": "^7.22.0", - "@babel/types": "^7.22.0", + "@babel/core": "^7.22.9", + "@babel/types": "^7.22.5", "@types/babel__core": "^7", "@types/babel__plugin-transform-runtime": "^7", "@types/babel__preset-env": "^7", diff --git a/code/frameworks/nextjs/src/font/webpack/loader/local/get-font-face-declarations.ts b/code/frameworks/nextjs/src/font/webpack/loader/local/get-font-face-declarations.ts index 2e0ddeefc53c..20e1df8deeb2 100644 --- a/code/frameworks/nextjs/src/font/webpack/loader/local/get-font-face-declarations.ts +++ b/code/frameworks/nextjs/src/font/webpack/loader/local/get-font-face-declarations.ts @@ -29,7 +29,7 @@ export async function getFontFaceDeclarations(options: LoaderOptions, rootContex return `@font-face { font-family: ${id}; - src: url(${localFontPath}); + src: url(.${localFontPath}); }`; } return localFontSrc @@ -38,7 +38,7 @@ export async function getFontFaceDeclarations(options: LoaderOptions, rootContex return `@font-face { font-family: ${id}; - src: url(${localFontPath}); + src: url(.${localFontPath}); ${font.weight ? `font-weight: ${font.weight};` : ''} ${font.style ? `font-style: ${font.style};` : ''} }`; diff --git a/code/frameworks/preact-vite/src/preset.ts b/code/frameworks/preact-vite/src/preset.ts index aecc5b9a904a..2d4e18d77e90 100644 --- a/code/frameworks/preact-vite/src/preset.ts +++ b/code/frameworks/preact-vite/src/preset.ts @@ -1,11 +1,15 @@ import { hasVitePlugins } from '@storybook/builder-vite'; import type { PresetProperty } from '@storybook/types'; import preact from '@preact/preset-vite'; +import { dirname, join } from 'path'; import type { StorybookConfig } from './types'; +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; + export const core: PresetProperty<'core', StorybookConfig> = { - builder: '@storybook/builder-vite', - renderer: '@storybook/preact', + builder: getAbsolutePath('@storybook/builder-vite'), + renderer: getAbsolutePath('@storybook/preact'), }; export const viteFinal: StorybookConfig['viteFinal'] = async (config) => { diff --git a/code/frameworks/preact-webpack5/src/preset.ts b/code/frameworks/preact-webpack5/src/preset.ts index 5808ca929166..e815e7884248 100644 --- a/code/frameworks/preact-webpack5/src/preset.ts +++ b/code/frameworks/preact-webpack5/src/preset.ts @@ -2,10 +2,11 @@ import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ - wrapForPnP('@storybook/preset-preact-webpack'), + getAbsolutePath('@storybook/preset-preact-webpack'), ]; export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { @@ -14,9 +15,9 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, - renderer: wrapForPnP('@storybook/preact'), + renderer: getAbsolutePath('@storybook/preact'), }; }; diff --git a/code/frameworks/react-vite/src/preset.ts b/code/frameworks/react-vite/src/preset.ts index 26a577af7900..207f60988ebc 100644 --- a/code/frameworks/react-vite/src/preset.ts +++ b/code/frameworks/react-vite/src/preset.ts @@ -4,11 +4,12 @@ import { hasVitePlugins } from '@storybook/builder-vite'; import { dirname, join } from 'path'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const core: PresetProperty<'core', StorybookConfig> = { - builder: wrapForPnP('@storybook/builder-vite') as '@storybook/builder-vite', - renderer: wrapForPnP('@storybook/react'), + builder: getAbsolutePath('@storybook/builder-vite'), + renderer: getAbsolutePath('@storybook/react'), }; export const viteFinal: StorybookConfig['viteFinal'] = async (config, { presets }) => { diff --git a/code/frameworks/react-webpack5/src/preset.ts b/code/frameworks/react-webpack5/src/preset.ts index b03832ae272f..873d214c597c 100644 --- a/code/frameworks/react-webpack5/src/preset.ts +++ b/code/frameworks/react-webpack5/src/preset.ts @@ -4,10 +4,11 @@ import { dirname, join } from 'path'; import type { PresetProperty, Options } from '@storybook/types'; import type { FrameworkOptions, StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ - wrapForPnP('@storybook/preset-react-webpack'), + getAbsolutePath('@storybook/preset-react-webpack'), ]; const defaultFrameworkOptions: FrameworkOptions = { @@ -28,7 +29,7 @@ export const frameworkOptions = async ( } if (typeof config === 'undefined') { return { - name: wrapForPnP('@storybook/react-webpack5') as '@storybook/react-webpack5', + name: getAbsolutePath('@storybook/react-webpack5'), options: defaultFrameworkOptions, }; } @@ -48,10 +49,10 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, - renderer: wrapForPnP('@storybook/react'), + renderer: getAbsolutePath('@storybook/react'), }; }; @@ -60,7 +61,7 @@ export const webpack: StorybookConfig['webpack'] = async (config) => { config.resolve.alias = { ...config.resolve?.alias, - '@storybook/react': wrapForPnP('@storybook/react'), + '@storybook/react': getAbsolutePath('@storybook/react'), }; return config; }; diff --git a/code/frameworks/server-webpack5/src/preset.ts b/code/frameworks/server-webpack5/src/preset.ts index 852c2a9c9409..0dd7d63814f0 100644 --- a/code/frameworks/server-webpack5/src/preset.ts +++ b/code/frameworks/server-webpack5/src/preset.ts @@ -2,10 +2,11 @@ import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ - wrapForPnP('@storybook/preset-server-webpack'), + getAbsolutePath('@storybook/preset-server-webpack'), ]; export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { @@ -14,9 +15,9 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, - renderer: wrapForPnP('@storybook/server'), + renderer: getAbsolutePath('@storybook/server'), }; }; diff --git a/code/frameworks/svelte-vite/src/preset.ts b/code/frameworks/svelte-vite/src/preset.ts index bf7a7f742511..220812cf7c5a 100644 --- a/code/frameworks/svelte-vite/src/preset.ts +++ b/code/frameworks/svelte-vite/src/preset.ts @@ -1,12 +1,16 @@ import { hasVitePlugins } from '@storybook/builder-vite'; import type { PresetProperty } from '@storybook/types'; +import { dirname, join } from 'path'; import type { StorybookConfig } from './types'; import { handleSvelteKit } from './utils'; import { svelteDocgen } from './plugins/svelte-docgen'; +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; + export const core: PresetProperty<'core', StorybookConfig> = { - builder: '@storybook/builder-vite', - renderer: '@storybook/svelte', + builder: getAbsolutePath('@storybook/builder-vite'), + renderer: getAbsolutePath('@storybook/svelte'), }; export const viteFinal: NonNullable = async (config, options) => { diff --git a/code/frameworks/svelte-webpack5/src/preset.ts b/code/frameworks/svelte-webpack5/src/preset.ts index 7486869f3b61..176bce0c0bc5 100644 --- a/code/frameworks/svelte-webpack5/src/preset.ts +++ b/code/frameworks/svelte-webpack5/src/preset.ts @@ -2,10 +2,11 @@ import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ - wrapForPnP('@storybook/preset-svelte-webpack'), + getAbsolutePath('@storybook/preset-svelte-webpack'), ]; export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { @@ -14,9 +15,9 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, - renderer: wrapForPnP('@storybook/svelte'), + renderer: getAbsolutePath('@storybook/svelte'), }; }; diff --git a/code/frameworks/sveltekit/src/preset.ts b/code/frameworks/sveltekit/src/preset.ts index 6c98e344eff4..e92e45079f63 100644 --- a/code/frameworks/sveltekit/src/preset.ts +++ b/code/frameworks/sveltekit/src/preset.ts @@ -2,12 +2,16 @@ import { viteFinal as svelteViteFinal } from '@storybook/svelte-vite/preset'; import type { PresetProperty } from '@storybook/types'; import { withoutVitePlugins } from '@storybook/builder-vite'; +import { dirname, join } from 'path'; import { configOverrides } from './plugins/config-overrides'; import { type StorybookConfig } from './types'; +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; + export const core: PresetProperty<'core', StorybookConfig> = { - builder: '@storybook/builder-vite', - renderer: '@storybook/svelte', + builder: getAbsolutePath('@storybook/builder-vite'), + renderer: getAbsolutePath('@storybook/svelte'), }; export const viteFinal: NonNullable = async (config, options) => { diff --git a/code/frameworks/vue-vite/src/preset.ts b/code/frameworks/vue-vite/src/preset.ts index f047581dd797..bf5b7d45ea5b 100644 --- a/code/frameworks/vue-vite/src/preset.ts +++ b/code/frameworks/vue-vite/src/preset.ts @@ -1,21 +1,22 @@ -import path from 'path'; +import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import { mergeConfig } from 'vite'; import type { StorybookConfig } from './types'; import { vueDocgen } from './plugins/vue-docgen'; +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; + export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { const framework = await options.presets.apply('framework'); return { ...config, builder: { - name: path.dirname( - require.resolve(path.join('@storybook/builder-vite', 'package.json')) - ) as '@storybook/builder-vite', + name: getAbsolutePath('@storybook/builder-vite'), options: typeof framework === 'string' ? {} : framework?.options.builder || {}, }, - renderer: '@storybook/vue', + renderer: getAbsolutePath('@storybook/vue'), }; }; diff --git a/code/frameworks/vue-webpack5/src/preset.ts b/code/frameworks/vue-webpack5/src/preset.ts index 911ea437f8bd..661053fddefb 100644 --- a/code/frameworks/vue-webpack5/src/preset.ts +++ b/code/frameworks/vue-webpack5/src/preset.ts @@ -2,10 +2,11 @@ import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ - wrapForPnP('@storybook/preset-vue-webpack'), + getAbsolutePath('@storybook/preset-vue-webpack'), ]; export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { @@ -14,10 +15,10 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, - renderer: wrapForPnP('@storybook/vue'), + renderer: getAbsolutePath('@storybook/vue'), }; }; diff --git a/code/frameworks/vue3-vite/src/preset.ts b/code/frameworks/vue3-vite/src/preset.ts index 7af3f31056e7..faa7ecc49a1a 100644 --- a/code/frameworks/vue3-vite/src/preset.ts +++ b/code/frameworks/vue3-vite/src/preset.ts @@ -1,12 +1,16 @@ import { hasVitePlugins } from '@storybook/builder-vite'; import type { PresetProperty } from '@storybook/types'; import { mergeConfig, type PluginOption } from 'vite'; +import { dirname, join } from 'path'; import type { StorybookConfig } from './types'; import { vueDocgen } from './plugins/vue-docgen'; +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; + export const core: PresetProperty<'core', StorybookConfig> = { - builder: '@storybook/builder-vite', - renderer: '@storybook/vue3', + builder: getAbsolutePath('@storybook/builder-vite'), + renderer: getAbsolutePath('@storybook/vue3'), }; export const viteFinal: StorybookConfig['viteFinal'] = async (config, { presets }) => { diff --git a/code/frameworks/vue3-webpack5/src/preset.ts b/code/frameworks/vue3-webpack5/src/preset.ts index 1ace38e86044..0dd1e931ddd4 100644 --- a/code/frameworks/vue3-webpack5/src/preset.ts +++ b/code/frameworks/vue3-webpack5/src/preset.ts @@ -2,10 +2,11 @@ import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ - wrapForPnP('@storybook/preset-vue3-webpack'), + getAbsolutePath('@storybook/preset-vue3-webpack'), ]; export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { @@ -14,10 +15,10 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, - renderer: wrapForPnP('@storybook/vue3'), + renderer: getAbsolutePath('@storybook/vue3'), }; }; diff --git a/code/frameworks/web-components-vite/src/preset.ts b/code/frameworks/web-components-vite/src/preset.ts index cd53f7d76283..a3bb7c4d66a2 100644 --- a/code/frameworks/web-components-vite/src/preset.ts +++ b/code/frameworks/web-components-vite/src/preset.ts @@ -1,7 +1,11 @@ import type { PresetProperty } from '@storybook/types'; +import { dirname, join } from 'path'; import type { StorybookConfig } from './types'; +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; + export const core: PresetProperty<'core', StorybookConfig> = { - builder: '@storybook/builder-vite', - renderer: '@storybook/web-components', + builder: getAbsolutePath('@storybook/builder-vite'), + renderer: getAbsolutePath('@storybook/web-components'), }; diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index 0cb3e19f7358..f92bbf8d382e 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -50,7 +50,7 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@babel/preset-env": "^7.22.0", + "@babel/preset-env": "^7.22.9", "@storybook/builder-webpack5": "7.1.0", "@storybook/core-common": "7.1.0", "@storybook/preset-web-components-webpack": "7.1.0", diff --git a/code/frameworks/web-components-webpack5/src/preset.ts b/code/frameworks/web-components-webpack5/src/preset.ts index 930e7d3f906b..101539931f27 100644 --- a/code/frameworks/web-components-webpack5/src/preset.ts +++ b/code/frameworks/web-components-webpack5/src/preset.ts @@ -2,10 +2,11 @@ import { dirname, join } from 'path'; import type { PresetProperty } from '@storybook/types'; import type { StorybookConfig } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const addons: PresetProperty<'addons', StorybookConfig> = [ - wrapForPnP('@storybook/preset-web-components-webpack'), + getAbsolutePath('@storybook/preset-web-components-webpack'), ]; export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { @@ -14,9 +15,9 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti return { ...config, builder: { - name: wrapForPnP('@storybook/builder-webpack5') as '@storybook/builder-webpack5', + name: getAbsolutePath('@storybook/builder-webpack5'), options: typeof framework === 'string' ? {} : framework.options.builder || {}, }, - renderer: wrapForPnP('@storybook/web-components'), + renderer: getAbsolutePath('@storybook/web-components'), }; }; diff --git a/code/jest.config.base.js b/code/jest.config.base.js index 77a03b8b082b..9fdc75f588a9 100644 --- a/code/jest.config.base.js +++ b/code/jest.config.base.js @@ -87,6 +87,8 @@ module.exports = { '/prebuilt/', '/generators/', '/template/', + // The export format used in the following file is not supported by jest. + '/code/frameworks/nextjs/src/next-image-loader-stub.ts', '/__mocks__ /', '/__mockdata__/', '/__mocks-ng-workspace__/', diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index 9bd3956de4a1..cc588c3bc95d 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -54,8 +54,9 @@ "test": "jest test/**/*.test.js" }, "dependencies": { - "@babel/core": "^7.22.0", - "@babel/preset-env": "^7.22.0", + "@babel/core": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/types": "^7.22.5", "@ndelangen/get-tarball": "^3.0.7", "@storybook/codemod": "7.1.0", "@storybook/core-common": "7.1.0", diff --git a/code/lib/cli/src/automigrate/fixes/__test__/main-config-with-wrappers.js b/code/lib/cli/src/automigrate/fixes/__test__/main-config-with-wrappers.js new file mode 100644 index 000000000000..7e6280732df5 --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/__test__/main-config-with-wrappers.js @@ -0,0 +1,21 @@ +import path from 'path'; + +const wrapForPnp = (packageName) => + path.dirname(require.resolve(path.join(packageName, 'package.json'))); + +const config = { + stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + wrapForPnp('@storybook/addon-links'), + wrapForPnp('@storybook/addon-essentials'), + wrapForPnp('@storybook/addon-interactions'), + ], + framework: { + name: wrapForPnp('@storybook/angular'), + options: {}, + }, + docs: { + autodocs: 'tag', + }, +}; +export default config; diff --git a/code/lib/cli/src/automigrate/fixes/__test__/main-config-without-wrappers.js b/code/lib/cli/src/automigrate/fixes/__test__/main-config-without-wrappers.js new file mode 100644 index 000000000000..0979ef60ff60 --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/__test__/main-config-without-wrappers.js @@ -0,0 +1,16 @@ +const config = { + stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + ], + framework: { + name: '@storybook/angular', + options: {}, + }, + docs: { + autodocs: 'tag', + }, +}; +export default config; diff --git a/code/lib/cli/src/automigrate/fixes/index.ts b/code/lib/cli/src/automigrate/fixes/index.ts index 4de0e7d63689..2becfe0b156a 100644 --- a/code/lib/cli/src/automigrate/fixes/index.ts +++ b/code/lib/cli/src/automigrate/fixes/index.ts @@ -18,6 +18,7 @@ import { missingBabelRc } from './missing-babelrc'; import { angularBuilders } from './angular-builders'; import { incompatibleAddons } from './incompatible-addons'; import { angularBuildersMultiproject } from './angular-builders-multiproject'; +import { wrapRequire } from './wrap-require'; export * from '../types'; @@ -40,6 +41,7 @@ export const allFixes: Fix[] = [ missingBabelRc, angularBuildersMultiproject, angularBuilders, + wrapRequire, ]; export const initFixes: Fix[] = [missingBabelRc, eslintPlugin]; diff --git a/code/lib/cli/src/automigrate/fixes/wrap-require-utils.ts b/code/lib/cli/src/automigrate/fixes/wrap-require-utils.ts new file mode 100644 index 000000000000..c1a33b3119f6 --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/wrap-require-utils.ts @@ -0,0 +1,187 @@ +/* eslint-disable no-param-reassign */ +import * as t from '@babel/types'; +import type { ConfigFile } from '@storybook/csf-tools'; + +const defaultRequireWrapperName = 'getAbsolutePath'; + +/** + * Checks if the following node declarations exists in the main config file. + * @example + * const = () => {}; + * function () {} + */ +function doesVariableOrFunctionDeclarationExist(node: t.Node, name: string) { + return ( + (t.isVariableDeclaration(node) && + node.declarations.length === 1 && + t.isVariableDeclarator(node.declarations[0]) && + t.isIdentifier(node.declarations[0].id) && + node.declarations[0].id?.name === name) || + (t.isFunctionDeclaration(node) && t.isIdentifier(node.id) && node.id.name === name) + ); +} + +/** + * Wrap a value with require wrapper. + * @example + * // Before + * { framework: 'react' } + * + * // After + * { framework: wrapForPnp('react') } + */ +function getReferenceToRequireWrapper(config: ConfigFile, value: string) { + return t.callExpression( + t.identifier(getRequireWrapperName(config) ?? defaultRequireWrapperName), + [t.stringLiteral(value)] + ); +} + +/** + * Returns the name of the require wrapper function if it exists in the main config file. + * @returns Name of the require wrapper function. + */ +export function getRequireWrapperName(config: ConfigFile) { + const declarationName = config.getBodyDeclarations().flatMap((node) => + // eslint-disable-next-line no-nested-ternary + doesVariableOrFunctionDeclarationExist(node, 'wrapForPnp') + ? ['wrapForPnp'] + : doesVariableOrFunctionDeclarationExist(node, defaultRequireWrapperName) + ? [defaultRequireWrapperName] + : [] + ); + + if (declarationName.length) { + return declarationName[0]; + } + + return null; +} + +/** + * Check if the node needs to be wrapped with require wrapper. + */ +export function isRequireWrapperNecessary( + node: t.Node, + cb: (node: t.StringLiteral | t.ObjectProperty | t.ArrayExpression) => void = () => {} +) { + if (t.isStringLiteral(node)) { + // value will be converted from StringLiteral to CallExpression. + cb(node); + return true; + } + + if (t.isObjectExpression(node)) { + const nameProperty = node.properties.find( + (property) => + t.isObjectProperty(property) && t.isIdentifier(property.key) && property.key.name === 'name' + ) as t.ObjectProperty; + + if (nameProperty && t.isStringLiteral(nameProperty.value)) { + cb(nameProperty); + return true; + } + } + + if ( + t.isArrayExpression(node) && + node.elements.some((element) => isRequireWrapperNecessary(element)) + ) { + cb(node); + return true; + } + + return false; +} + +/** + * Get all fields that need to be wrapped with require wrapper. + * @returns Array of fields that need to be wrapped with require wrapper. + */ +export function getFieldsForRequireWrapper(config: ConfigFile) { + const frameworkNode = config.getFieldNode(['framework']); + const builderNode = config.getFieldNode(['core', 'builder']); + const rendererNode = config.getFieldNode(['core', 'renderer']); + const addons = config.getFieldNode(['addons']); + + const fieldsWithRequireWrapper = [ + ...(frameworkNode ? [frameworkNode] : []), + ...(builderNode ? [builderNode] : []), + ...(rendererNode ? [rendererNode] : []), + ...(addons && t.isArrayExpression(addons) ? [addons] : []), + ]; + + return fieldsWithRequireWrapper; +} + +/** + * Returns AST for the following function + * @example + * function getAbsolutePath(value) { + * return dirname(require.resolve(join(value, 'package.json'))) + * } + */ +export function getRequireWrapperAsCallExpression( + isConfigTypescript: boolean +): t.FunctionDeclaration { + const functionDeclaration = { + ...t.functionDeclaration( + t.identifier(defaultRequireWrapperName), + [ + { + ...t.identifier('value'), + ...(isConfigTypescript + ? { typeAnnotation: t.tsTypeAnnotation(t.tSStringKeyword()) } + : {}), + }, + ], + t.blockStatement([ + t.returnStatement( + t.callExpression(t.identifier('dirname'), [ + t.callExpression(t.memberExpression(t.identifier('require'), t.identifier('resolve')), [ + t.callExpression(t.identifier('join'), [ + t.identifier('value'), + t.stringLiteral('package.json'), + ]), + ]), + ]) + ), + ]) + ), + ...(isConfigTypescript ? { returnType: t.tSTypeAnnotation(t.tsAnyKeyword()) } : {}), + }; + + t.addComment( + functionDeclaration, + 'leading', + '*\n * This function is used to resolve the absolute path of a package.\n * It is needed in projects that use Yarn PnP or are set up within a monorepo.\n' + ); + + return functionDeclaration; +} + +export function wrapValueWithRequireWrapper(config: ConfigFile, node: t.Node) { + isRequireWrapperNecessary(node, (n) => { + if (t.isStringLiteral(n)) { + const wrapperNode = getReferenceToRequireWrapper(config, n.value); + Object.keys(n).forEach((k: keyof typeof n) => { + delete n[k]; + }); + Object.keys(wrapperNode).forEach((k: keyof typeof wrapperNode) => { + (n as any)[k] = wrapperNode[k]; + }); + } + + if (t.isObjectProperty(n) && t.isStringLiteral(n.value)) { + n.value = getReferenceToRequireWrapper(config, n.value.value) as any; + } + + if (t.isArrayExpression(n)) { + n.elements.forEach((element, index, elements) => { + if (t.isStringLiteral(element)) { + elements[index] = getReferenceToRequireWrapper(config, element.value); + } + }); + } + }); +} diff --git a/code/lib/cli/src/automigrate/fixes/wrap-require.test.ts b/code/lib/cli/src/automigrate/fixes/wrap-require.test.ts new file mode 100644 index 000000000000..e040eb6e29f7 --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/wrap-require.test.ts @@ -0,0 +1,77 @@ +import { wrapRequire } from './wrap-require'; +import * as detect from '../../detect'; + +jest.mock('../../detect', () => ({ + ...jest.requireActual('../../detect'), + detectPnp: jest.fn(), +})); + +describe('wrapRequire', () => { + describe('check', () => { + it('should return null if not in a monorepo and pnp is not enabled', async () => { + (detect.detectPnp as any as jest.SpyInstance).mockResolvedValue(false); + + const check = wrapRequire.check({ + packageManager: { + isStorybookInMonorepo: () => false, + }, + storybookVersion: '7.0.0', + mainConfigPath: require.resolve('./__test__/main-config-without-wrappers.js'), + } as any); + + await expect(check).resolves.toBeNull(); + }); + + it('should return the configuration object if in a pnp environment', async () => { + (detect.detectPnp as any as jest.SpyInstance).mockResolvedValue(true); + + const check = wrapRequire.check({ + packageManager: { + isStorybookInMonorepo: () => false, + }, + storybookVersion: '7.0.0', + mainConfigPath: require.resolve('./__test__/main-config-without-wrappers.js'), + } as any); + + await expect(check).resolves.toEqual({ + isConfigTypescript: false, + isPnp: true, + isStorybookInMonorepo: false, + storybookVersion: '7.0.0', + }); + }); + + it('should return the configuration object if in a monorepo environment', async () => { + (detect.detectPnp as any as jest.SpyInstance).mockResolvedValue(false); + + const check = wrapRequire.check({ + packageManager: { + isStorybookInMonorepo: () => true, + }, + storybookVersion: '7.0.0', + mainConfigPath: require.resolve('./__test__/main-config-without-wrappers.js'), + } as any); + + await expect(check).resolves.toEqual({ + isConfigTypescript: false, + isPnp: false, + isStorybookInMonorepo: true, + storybookVersion: '7.0.0', + }); + }); + + it('should return null, if all fields have the require wrapper', async () => { + (detect.detectPnp as any as jest.SpyInstance).mockResolvedValue(true); + + const check = wrapRequire.check({ + packageManager: { + isStorybookInMonorepo: () => true, + }, + storybookVersion: '7.0.0', + mainConfigPath: require.resolve('./__test__/main-config-with-wrappers.js'), + } as any); + + await expect(check).resolves.toBeNull(); + }); + }); +}); diff --git a/code/lib/cli/src/automigrate/fixes/wrap-require.ts b/code/lib/cli/src/automigrate/fixes/wrap-require.ts new file mode 100644 index 000000000000..5cbe883a4948 --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/wrap-require.ts @@ -0,0 +1,77 @@ +import chalk from 'chalk'; +import { dedent } from 'ts-dedent'; +import { readConfig } from '@storybook/csf-tools'; +import type { Fix } from '../types'; +import { detectPnp } from '../../detect'; +import { updateMainConfig } from '../helpers/mainConfigFile'; +import { + getFieldsForRequireWrapper, + getRequireWrapperAsCallExpression, + getRequireWrapperName, + isRequireWrapperNecessary, + wrapValueWithRequireWrapper, +} from './wrap-require-utils'; + +interface WrapRequireRunOptions { + storybookVersion: string; + isStorybookInMonorepo: boolean; + isPnp: boolean; + isConfigTypescript: boolean; +} + +export const wrapRequire: Fix = { + id: 'wrap-require', + + async check({ packageManager, storybookVersion, mainConfigPath }) { + const isStorybookInMonorepo = await packageManager.isStorybookInMonorepo(); + const isPnp = await detectPnp(); + + const config = await readConfig(mainConfigPath); + + if (!isStorybookInMonorepo && !isPnp) { + return null; + } + + if (!getFieldsForRequireWrapper(config).some((node) => isRequireWrapperNecessary(node))) { + return null; + } + + const isConfigTypescript = mainConfigPath.endsWith('.ts') || mainConfigPath.endsWith('.tsx'); + + return { storybookVersion, isStorybookInMonorepo, isPnp, isConfigTypescript }; + }, + + prompt({ storybookVersion, isStorybookInMonorepo }) { + const sbFormatted = chalk.cyan(`Storybook ${storybookVersion}`); + + return dedent`We have detected that you're using ${sbFormatted} in a ${ + isStorybookInMonorepo ? 'monorepo' : 'PnP' + } project. + For Storybook to work correctly, some fields in your main config must be updated. We can do this for you automatically. + + More info: https://storybook.js.org/docs/react/faq#how-do-i-fix-module-resolution-in-special-environments`; + }, + + async run({ dryRun, mainConfigPath, result }) { + return new Promise((resolve, reject) => { + updateMainConfig({ dryRun, mainConfigPath }, (mainConfig) => { + try { + getFieldsForRequireWrapper(mainConfig).forEach((node) => { + wrapValueWithRequireWrapper(mainConfig, node); + }); + + if (getRequireWrapperName(mainConfig) === null) { + mainConfig.setImport(['dirname', 'join'], 'path'); + mainConfig.setBodyDeclaration( + getRequireWrapperAsCallExpression(result.isConfigTypescript) + ); + } + + resolve(); + } catch (e) { + reject(e); + } + }); + }); + }, +}; diff --git a/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts b/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts index d1ccbff10d32..b5325df31ac2 100644 --- a/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts +++ b/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts @@ -133,7 +133,7 @@ export type GetStorybookData = typeof getStorybookData; */ export const updateMainConfig = async ( { mainConfigPath, dryRun }: { mainConfigPath: string; dryRun: boolean }, - callback: (main: ConfigFile) => Promise + callback: (main: ConfigFile) => Promise | void ) => { try { const main = await readConfig(mainConfigPath); diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts index 03c667e9dac2..55d89637fe9a 100644 --- a/code/lib/cli/src/generators/baseGenerator.ts +++ b/code/lib/cli/src/generators/baseGenerator.ts @@ -99,14 +99,15 @@ const getRendererPackage = (framework: string, renderer: string) => { return `@storybook/${renderer}`; }; -const wrapForPnp = (packageName: string) => - `%%path.dirname(require.resolve(path.join('${packageName}', 'package.json')))%%`; +const applyRequireWrapper = (packageName: string) => `%%getAbsolutePath('${packageName}')%%`; const getFrameworkDetails = ( renderer: SupportedRenderers, builder: Builder, pnp: boolean, - framework?: SupportedFrameworks + language: SupportedLanguage, + framework?: SupportedFrameworks, + shouldApplyRequireWrapperOnPackageNames?: boolean ): { type: 'framework' | 'renderer'; packages: string[]; @@ -117,13 +118,19 @@ const getFrameworkDetails = ( } => { const frameworkPackage = getFrameworkPackage(framework, renderer, builder); - const frameworkPackagePath = pnp ? wrapForPnp(frameworkPackage) : frameworkPackage; + const frameworkPackagePath = shouldApplyRequireWrapperOnPackageNames + ? applyRequireWrapper(frameworkPackage) + : frameworkPackage; const rendererPackage = getRendererPackage(framework, renderer); - const rendererPackagePath = pnp ? wrapForPnp(rendererPackage) : rendererPackage; + const rendererPackagePath = shouldApplyRequireWrapperOnPackageNames + ? applyRequireWrapper(rendererPackage) + : rendererPackage; const builderPackage = getBuilderDetails(builder); - const builderPackagePath = pnp ? wrapForPnp(builderPackage) : builderPackage; + const builderPackagePath = shouldApplyRequireWrapperOnPackageNames + ? applyRequireWrapper(builderPackage) + : builderPackage; const isExternalFramework = !!getExternalFramework(frameworkPackage); const isKnownFramework = @@ -187,6 +194,9 @@ export async function baseGenerator( }; process.on('SIGINT', setNodeProcessExiting); + const isStorybookInMonorepository = packageManager.isStorybookInMonorepo(); + const shouldApplyRequireWrapperOnPackageNames = isStorybookInMonorepository || pnp; + const stopIfExiting = async (callback: () => Promise) => { if (isNodeProcessExiting) { throw new HandledError('Canceled by the user'); @@ -226,7 +236,14 @@ export async function baseGenerator( rendererId, framework: frameworkInclude, builder: builderInclude, - } = getFrameworkDetails(renderer, builder, pnp, framework); + } = getFrameworkDetails( + renderer, + builder, + pnp, + language, + framework, + shouldApplyRequireWrapperOnPackageNames + ); // added to main.js const addons = [ @@ -361,11 +378,35 @@ export async function baseGenerator( await fse.ensureDir(`./${storybookConfigFolder}`); if (addMainFile) { + const prefixes = shouldApplyRequireWrapperOnPackageNames + ? [ + 'import { join, dirname } from "path"', + language === SupportedLanguage.JAVASCRIPT + ? dedent`/** + * This function is used to resolve the absolute path of a package. + * It is needed in projects that use Yarn PnP or are set up within a monorepo. + */ + function getAbsolutePath(value) { + return dirname(require.resolve(join(value, 'package.json'))) + }` + : dedent`/** + * This function is used to resolve the absolute path of a package. + * It is needed in projects that use Yarn PnP or are set up within a monorepo. + */ + function getAbsolutePath(value: string): any { + return dirname(require.resolve(join(value, 'package.json'))) + }`, + ] + : []; + await configureMain({ framework: { name: frameworkInclude, options: options.framework || {} }, + prefixes, storybookConfigFolder, docs: { autodocs: 'tag' }, - addons: pnp ? addons.map(wrapForPnp) : addons, + addons: shouldApplyRequireWrapperOnPackageNames + ? addons.map((addon) => applyRequireWrapper(addon)) + : addons, extensions, language, ...(staticDir ? { staticDirs: [path.join('..', staticDir)] } : null), @@ -380,7 +421,12 @@ export async function baseGenerator( }); } - await configurePreview({ frameworkPreviewParts, storybookConfigFolder, language, rendererId }); + await configurePreview({ + frameworkPreviewParts, + storybookConfigFolder, + language, + rendererId, + }); if (addScripts) { await stopIfExiting(async () => diff --git a/code/lib/cli/src/generators/configure.test.ts b/code/lib/cli/src/generators/configure.test.ts index 78a2ebb6eb3f..c79eea9a253c 100644 --- a/code/lib/cli/src/generators/configure.test.ts +++ b/code/lib/cli/src/generators/configure.test.ts @@ -14,6 +14,7 @@ describe('configureMain', () => { await configureMain({ language: SupportedLanguage.JAVASCRIPT, addons: [], + prefixes: [], storybookConfigFolder: '.storybook', framework: { name: '@storybook/react-vite', @@ -42,6 +43,7 @@ describe('configureMain', () => { await configureMain({ language: SupportedLanguage.TYPESCRIPT_4_9, addons: [], + prefixes: [], storybookConfigFolder: '.storybook', framework: { name: '@storybook/react-vite', @@ -54,6 +56,7 @@ describe('configureMain', () => { expect(mainConfigPath).toEqual('./.storybook/main.ts'); expect(mainConfigContent).toMatchInlineSnapshot(` "import type { StorybookConfig } from '@storybook/react-vite'; + const config: StorybookConfig = { stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [], @@ -69,6 +72,7 @@ describe('configureMain', () => { test('should handle resolved paths in pnp', async () => { await configureMain({ language: SupportedLanguage.JAVASCRIPT, + prefixes: [], addons: [ "%%path.dirname(require.resolve(path.join('@storybook/addon-links', 'package.json')))%%", "%%path.dirname(require.resolve(path.join('@storybook/addon-essentials', 'package.json')))%%", diff --git a/code/lib/cli/src/generators/configure.ts b/code/lib/cli/src/generators/configure.ts index 569c8cbc52f3..6001a17b6024 100644 --- a/code/lib/cli/src/generators/configure.ts +++ b/code/lib/cli/src/generators/configure.ts @@ -9,6 +9,7 @@ interface ConfigureMainOptions { staticDirs?: string[]; storybookConfigFolder: string; language: SupportedLanguage; + prefixes: string[]; /** * Extra values for main.js * @@ -54,6 +55,7 @@ export async function configureMain({ extensions = ['js', 'jsx', 'mjs', 'ts', 'tsx'], storybookConfigFolder, language, + prefixes = [], ...custom }: ConfigureMainOptions) { const srcPath = path.resolve(storybookConfigFolder, '../src'); @@ -67,7 +69,7 @@ export async function configureMain({ const isTypescript = language === SupportedLanguage.TYPESCRIPT_4_9 || language === SupportedLanguage.TYPESCRIPT_3_8; - let mainConfigTemplate = dedent`<>const config<> = <>; + let mainConfigTemplate = dedent`<><>const config<> = <>; export default config;`; const frameworkPackage = sanitizeFramework(custom.framework?.name); @@ -82,6 +84,7 @@ export async function configureMain({ .replace(/%%['"]/g, ''); const imports = []; + const finalPrefixes = [...prefixes]; if (custom.framework?.name.includes('path.dirname(')) { imports.push(`import path from 'path';`); @@ -90,11 +93,12 @@ export async function configureMain({ if (isTypescript) { imports.push(`import type { StorybookConfig } from '${frameworkPackage}';`); } else { - imports.push(`/** @type { import('${frameworkPackage}').StorybookConfig } */`); + finalPrefixes.push(`/** @type { import('${frameworkPackage}').StorybookConfig } */`); } const mainJsContents = mainConfigTemplate - .replace('<>', `${imports.join('\n\n')}\n`) + .replace('<>', `${imports.join('\n\n')}\n\n`) + .replace('<>', finalPrefixes.length > 0 ? `${finalPrefixes.join('\n\n')}\n` : '') .replace('<>', isTypescript ? ': StorybookConfig' : '') .replace('<>', mainContents); diff --git a/code/lib/cli/src/js-package-manager/JsPackageManager.ts b/code/lib/cli/src/js-package-manager/JsPackageManager.ts index aea7bf07f17f..f973a92c5012 100644 --- a/code/lib/cli/src/js-package-manager/JsPackageManager.ts +++ b/code/lib/cli/src/js-package-manager/JsPackageManager.ts @@ -6,7 +6,7 @@ import path from 'path'; import fs from 'fs'; import dedent from 'ts-dedent'; -import { readFile, writeFile } from 'fs-extra'; +import { readFile, readFileSync, writeFile } from 'fs-extra'; import { commandLog } from '../helpers'; import type { PackageJson, PackageJsonWithDepsAndDevDeps } from './PackageJson'; import storybookPackagesVersions from '../versions'; @@ -76,6 +76,51 @@ export abstract class JsPackageManager { this.cwd = options?.cwd || process.cwd(); } + /** Detect whether Storybook gets initialized in a monorepository/workspace environment + * The cwd doesn't have to be the root of the monorepo, it can be a subdirectory + * @returns true, if Storybook is initialized inside a monorepository/workspace + */ + public isStorybookInMonorepo() { + let cwd = process.cwd(); + + // eslint-disable-next-line no-constant-condition + while (true) { + try { + const turboJsonPath = `${cwd}/turbo.json`; + const rushJsonPath = `${cwd}/rush.json`; + + if (fs.existsSync(turboJsonPath) || fs.existsSync(rushJsonPath)) { + return true; + } + + const packageJsonPath = require.resolve(`${cwd}/package.json`); + + // read packagejson with readFileSync + const packageJsonFile = readFileSync(packageJsonPath, 'utf8'); + const packageJson = JSON.parse(packageJsonFile) as PackageJsonWithDepsAndDevDeps; + + if (packageJson.workspaces) { + return true; + } + } catch (err) { + // Package.json not found or invalid in current directory + } + + // Move up to the parent directory + const parentDir = path.dirname(cwd); + + // Check if we have reached the root of the filesystem + if (parentDir === cwd) { + break; + } + + // Update cwd to the parent directory + cwd = parentDir; + } + + return false; + } + /** * Install dependencies listed in `package.json` */ diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index cf9296466690..1074906019e2 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -45,9 +45,9 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@babel/core": "^7.22.0", - "@babel/preset-env": "^7.22.0", - "@babel/types": "^7.22.0", + "@babel/core": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/types": "^7.22.5", "@storybook/csf": "^0.1.0", "@storybook/csf-tools": "7.1.0", "@storybook/node-logger": "7.1.0", diff --git a/code/lib/csf-tools/package.json b/code/lib/csf-tools/package.json index ccba3dda6bf9..087cb3117c0b 100644 --- a/code/lib/csf-tools/package.json +++ b/code/lib/csf-tools/package.json @@ -41,10 +41,10 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@babel/generator": "^7.22.0", - "@babel/parser": "^7.22.0", - "@babel/traverse": "^7.22.0", - "@babel/types": "^7.22.0", + "@babel/generator": "^7.22.9", + "@babel/parser": "^7.22.7", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", "@storybook/csf": "^0.1.0", "@storybook/types": "7.1.0", "fs-extra": "^11.1.0", diff --git a/code/lib/csf-tools/src/ConfigFile.test.ts b/code/lib/csf-tools/src/ConfigFile.test.ts index 86b6806638da..58df95ba4999 100644 --- a/code/lib/csf-tools/src/ConfigFile.test.ts +++ b/code/lib/csf-tools/src/ConfigFile.test.ts @@ -2,6 +2,7 @@ import { dedent } from 'ts-dedent'; import { formatConfig, loadConfig } from './ConfigFile'; +import { babelPrint } from './babelParse'; expect.addSnapshotSerializer({ print: (val: any) => val, @@ -1049,4 +1050,85 @@ describe('ConfigFile', () => { expect(config.getNamesFromPath(['addons'])).toBeUndefined(); }); }); + + describe('setImport', () => { + it(`supports setting a default import for a field that does not exist`, () => { + const source = dedent` + const config: StorybookConfig = { }; + export default config; + `; + + const config = loadConfig(source).parse(); + config.setImport('path', 'path'); + + // eslint-disable-next-line no-underscore-dangle + const parsed = babelPrint(config._ast); + + expect(parsed).toMatchInlineSnapshot(` + import path from 'path'; + const config: StorybookConfig = { }; + export default config; + `); + }); + + it(`supports setting a default import for a field that does exist`, () => { + const source = dedent` + const config: StorybookConfig = { }; + export default config; + `; + + const config = loadConfig(source).parse(); + config.setImport('path', 'path'); + + // eslint-disable-next-line no-underscore-dangle + const parsed = babelPrint(config._ast); + + expect(parsed).toMatchInlineSnapshot(` + import path from 'path'; + const config: StorybookConfig = { }; + export default config; + `); + }); + + it(`supports setting a named import for a field that does not exist`, () => { + const source = dedent` + const config: StorybookConfig = { }; + export default config; + `; + + const config = loadConfig(source).parse(); + config.setImport(['dirname'], 'path'); + + // eslint-disable-next-line no-underscore-dangle + const parsed = babelPrint(config._ast); + + expect(parsed).toMatchInlineSnapshot(` + import { dirname } from 'path'; + const config: StorybookConfig = { }; + export default config; + `); + }); + + it(`supports setting a named import for a field where the source already exists`, () => { + const source = dedent` + import { dirname } from 'path'; + + const config: StorybookConfig = { }; + export default config; + `; + + const config = loadConfig(source).parse(); + config.setImport(['dirname'], 'path'); + + // eslint-disable-next-line no-underscore-dangle + const parsed = babelPrint(config._ast); + + expect(parsed).toMatchInlineSnapshot(` + import { dirname } from 'path'; + + const config: StorybookConfig = { }; + export default config; + `); + }); + }); }); diff --git a/code/lib/csf-tools/src/ConfigFile.ts b/code/lib/csf-tools/src/ConfigFile.ts index 4f0db3e0d74f..7374d065f0e0 100644 --- a/code/lib/csf-tools/src/ConfigFile.ts +++ b/code/lib/csf-tools/src/ConfigFile.ts @@ -514,6 +514,97 @@ export class ConfigFile { } this.setFieldNode(path, valueNode); } + + getBodyDeclarations() { + return this._ast.program.body; + } + + setBodyDeclaration(declaration: t.Declaration) { + this._ast.program.body.push(declaration); + } + + /** + * Set import specifiers for a given import statement. + * @description Does not support setting type imports (yet) + * @param importSpecifiers - The import specifiers to set. If a string is passed in, a default import will be set. Otherwise, an array of named imports will be set + * @param fromImport - The module to import from + * @example + * // import { foo } from 'bar'; + * setImport(['foo'], 'bar'); + * + * // import foo from 'bar'; + * setImport('foo', 'bar'); + * + */ + setImport(importSpecifier: string[] | string, fromImport: string) { + const getNewImportSpecifier = (specifier: string) => + t.importSpecifier(t.identifier(specifier), t.identifier(specifier)); + + /** + * Returns true, when the given import declaration has the given import specifier + * @example + * // import { foo } from 'bar'; + * hasImportSpecifier(declaration, 'foo'); + */ + const hasImportSpecifier = (declaration: t.ImportDeclaration, name: string) => + declaration.specifiers.find( + (specifier) => + t.isImportSpecifier(specifier) && + t.isIdentifier(specifier.imported) && + specifier.imported.name === name + ); + + /** + * Returns true, when the given import declaration has the given default import specifier + * @example + * // import foo from 'bar'; + * hasImportSpecifier(declaration, 'foo'); + */ + const hasDefaultImportSpecifier = (declaration: t.ImportDeclaration, name: string) => + declaration.specifiers.find((specifier) => t.isImportDefaultSpecifier(specifier)); + + const importDeclaration = this._ast.program.body.find( + (node) => t.isImportDeclaration(node) && node.source.value === fromImport + ) as t.ImportDeclaration | undefined; + + // if the import specifier is a string, we're dealing with default imports + if (typeof importSpecifier === 'string') { + // If the import declaration with the given source exists + if (importDeclaration) { + if (!hasDefaultImportSpecifier(importDeclaration, importSpecifier)) { + // If the import declaration hasn't a default specifier, we add it + importDeclaration.specifiers.push( + t.importDefaultSpecifier(t.identifier(importSpecifier)) + ); + } + // If the import declaration with the given source doesn't exist + } else { + // Add the import declaration to the top of the file + this._ast.program.body.unshift( + t.importDeclaration( + [t.importDefaultSpecifier(t.identifier(importSpecifier))], + t.stringLiteral(fromImport) + ) + ); + } + // if the import specifier is an array, we're dealing with named imports + } else if (importDeclaration) { + importSpecifier.forEach((specifier) => { + if (!hasImportSpecifier(importDeclaration, specifier)) { + importDeclaration.specifiers.push(getNewImportSpecifier(specifier)); + } + }); + } else { + this._ast.program.body.unshift( + t.importDeclaration( + importSpecifier.map((specifier) => + t.importSpecifier(t.identifier(specifier), t.identifier(specifier)) + ), + t.stringLiteral(fromImport) + ) + ); + } + } } export const loadConfig = (code: string, fileName?: string) => { diff --git a/code/lib/csf-tools/src/babelParse.ts b/code/lib/csf-tools/src/babelParse.ts index 97c292ab21ca..43f49d4c166a 100644 --- a/code/lib/csf-tools/src/babelParse.ts +++ b/code/lib/csf-tools/src/babelParse.ts @@ -36,6 +36,16 @@ export const babelParse = (code: string) => { }); }; +export const babelPrint = (ast: recast.types.ASTNode) => { + return recast.print(ast, { + quote: 'single', + trailingComma: true, + tabWidth: 2, + wrapColumn: 80, + arrowParensAlways: true, + }).code; +}; + export const babelParseExpression = (code: string) => { return babelParser.parseExpression(code, parserOptions); }; diff --git a/code/lib/docs-tools/package.json b/code/lib/docs-tools/package.json index 621204561739..fbfa6ec0c09b 100644 --- a/code/lib/docs-tools/package.json +++ b/code/lib/docs-tools/package.json @@ -51,7 +51,7 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@babel/core": "^7.22.0", + "@babel/core": "^7.22.9", "jest-specific-snapshot": "^8.0.0", "require-from-string": "^2.0.2", "typescript": "~4.9.3" diff --git a/code/package.json b/code/package.json index 835211e712f9..75645add176c 100644 --- a/code/package.json +++ b/code/package.json @@ -91,11 +91,11 @@ "type-fest": "^3.11.0" }, "dependencies": { - "@babel/core": "^7.22.0", - "@babel/preset-env": "^7.22.0", - "@babel/preset-react": "^7.22.0", - "@babel/preset-typescript": "^7.21.0", - "@babel/runtime": "^7.20.1", + "@babel/core": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/preset-react": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", "@emotion/jest": "^11.10.0", "@jest/globals": "^29.3.1", "@nx/workspace": "16.2.1", diff --git a/code/presets/preact-webpack/package.json b/code/presets/preact-webpack/package.json index a91416277780..bb4df40c8b46 100644 --- a/code/presets/preact-webpack/package.json +++ b/code/presets/preact-webpack/package.json @@ -48,8 +48,8 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.21.0", - "@babel/preset-typescript": "^7.21.0", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", "@storybook/core-webpack": "7.1.0", "@types/node": "^16.0.0" }, diff --git a/code/presets/preact-webpack/src/index.ts b/code/presets/preact-webpack/src/index.ts index 76c50e0affb0..758012bf73ab 100644 --- a/code/presets/preact-webpack/src/index.ts +++ b/code/presets/preact-webpack/src/index.ts @@ -3,7 +3,8 @@ import type { StorybookConfig } from './types'; export * from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; export const babel: StorybookConfig['babelDefault'] = (config) => { return { @@ -38,10 +39,10 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = (config) => { ...config.resolve, alias: { ...(config.resolve?.alias || {}), - react: wrapForPnP('preact/compat'), - 'react-dom/test-utils': wrapForPnP('preact/test-utils'), - 'react-dom': wrapForPnP('preact/compat'), - 'react/jsx-runtime': wrapForPnP('preact/jsx-runtime'), + react: getAbsolutePath('preact/compat'), + 'react-dom/test-utils': getAbsolutePath('preact/test-utils'), + 'react-dom': getAbsolutePath('preact/compat'), + 'react/jsx-runtime': getAbsolutePath('preact/jsx-runtime'), }, }, }; diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json index 2df91891daa1..e5d9162d2d97 100644 --- a/code/presets/react-webpack/package.json +++ b/code/presets/react-webpack/package.json @@ -63,8 +63,8 @@ "prep": "../../../scripts/prepare/bundle.ts" }, "dependencies": { - "@babel/preset-flow": "^7.21.0", - "@babel/preset-react": "^7.22.0", + "@babel/preset-flow": "^7.22.5", + "@babel/preset-react": "^7.22.5", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5", "@storybook/core-webpack": "7.1.0", "@storybook/docs-tools": "7.1.0", diff --git a/code/presets/react-webpack/src/framework-preset-react.ts b/code/presets/react-webpack/src/framework-preset-react.ts index 9b0aeaad314d..e913a32b5332 100644 --- a/code/presets/react-webpack/src/framework-preset-react.ts +++ b/code/presets/react-webpack/src/framework-preset-react.ts @@ -6,7 +6,8 @@ import { logger } from '@storybook/node-logger'; import type { Options, Preset } from '@storybook/core-webpack'; import type { StorybookConfig, ReactOptions } from './types'; -const wrapForPnP = (input: string) => dirname(require.resolve(join(input, 'package.json'))); +const getAbsolutePath = (input: I): I => + dirname(require.resolve(join(input, 'package.json'))) as any; const applyFastRefresh = async (options: Options) => { const isDevelopment = options.configType === 'DEVELOPMENT'; @@ -26,7 +27,7 @@ export const babel: StorybookConfig['babel'] = async (config, options) => { ], }; }; -const storybookReactDirName = wrapForPnP('@storybook/preset-react-webpack'); +const storybookReactDirName = getAbsolutePath('@storybook/preset-react-webpack'); // TODO: improve node_modules detection const context = storybookReactDirName.includes('node_modules') ? join(storybookReactDirName, '../../') // Real life case, already in node_modules diff --git a/code/presets/web-components-webpack/package.json b/code/presets/web-components-webpack/package.json index 3ca95d692bd7..f9f7c9e3392d 100644 --- a/code/presets/web-components-webpack/package.json +++ b/code/presets/web-components-webpack/package.json @@ -53,7 +53,7 @@ "dependencies": { "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/preset-env": "^7.22.0", + "@babel/preset-env": "^7.22.9", "@storybook/core-webpack": "7.1.0", "@types/node": "^16.0.0", "babel-loader": "^7.0.0 || ^8.0.0 || ^9.0.0", diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json index 6faeea8a0b82..3397766ee669 100644 --- a/code/renderers/react/package.json +++ b/code/renderers/react/package.json @@ -75,7 +75,7 @@ "util-deprecate": "^1.0.2" }, "devDependencies": { - "@babel/core": "^7.22.0", + "@babel/core": "^7.22.9", "@types/util-deprecate": "^1.0.0", "expect-type": "^0.15.0", "jest-specific-snapshot": "^8.0.0", diff --git a/code/yarn.lock b/code/yarn.lock index d1ab427890f5..63fd993f2c7d 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -453,7 +453,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.0, @babel/core@npm:^7.12.3, @babel/core@npm:^7.13.16, @babel/core@npm:^7.19.6, @babel/core@npm:^7.20.12, @babel/core@npm:^7.22.0, @babel/core@npm:^7.22.1, @babel/core@npm:^7.3.4, @babel/core@npm:^7.7.5": +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.0, @babel/core@npm:^7.12.3, @babel/core@npm:^7.13.16, @babel/core@npm:^7.19.6, @babel/core@npm:^7.20.12, @babel/core@npm:^7.22.1, @babel/core@npm:^7.22.9, @babel/core@npm:^7.3.4, @babel/core@npm:^7.7.5": version: 7.22.9 resolution: "@babel/core@npm:7.22.9" dependencies: @@ -488,7 +488,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.12.11, @babel/generator@npm:^7.22.0, @babel/generator@npm:^7.22.5, @babel/generator@npm:^7.22.7, @babel/generator@npm:^7.22.9, @babel/generator@npm:^7.7.2, @babel/generator@npm:^7.8.7": +"@babel/generator@npm:^7.12.11, @babel/generator@npm:^7.22.5, @babel/generator@npm:^7.22.7, @babel/generator@npm:^7.22.9, @babel/generator@npm:^7.7.2, @babel/generator@npm:^7.8.7": version: 7.22.9 resolution: "@babel/generator@npm:7.22.9" dependencies: @@ -771,7 +771,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.11.5, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.18.4, @babel/parser@npm:^7.20.15, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.3, @babel/parser@npm:^7.21.4, @babel/parser@npm:^7.22.0, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.22.7, @babel/parser@npm:^7.4.5, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.7.0, @babel/parser@npm:^7.8.6, @babel/parser@npm:^7.8.7, @babel/parser@npm:^7.9.6": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.11.5, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.18.4, @babel/parser@npm:^7.20.15, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.3, @babel/parser@npm:^7.21.4, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.22.7, @babel/parser@npm:^7.4.5, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.7.0, @babel/parser@npm:^7.8.6, @babel/parser@npm:^7.8.7, @babel/parser@npm:^7.9.6": version: 7.22.7 resolution: "@babel/parser@npm:7.22.7" bin: @@ -1044,7 +1044,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-assertions@npm:^7.20.0, @babel/plugin-syntax-import-assertions@npm:^7.22.5": +"@babel/plugin-syntax-import-assertions@npm:^7.22.5": version: 7.22.5 resolution: "@babel/plugin-syntax-import-assertions@npm:7.22.5" dependencies: @@ -1221,7 +1221,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.22.5, @babel/plugin-transform-async-generator-functions@npm:^7.22.7": +"@babel/plugin-transform-async-generator-functions@npm:^7.22.7": version: 7.22.7 resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.7" dependencies: @@ -1295,7 +1295,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.22.5, @babel/plugin-transform-classes@npm:^7.22.6": +"@babel/plugin-transform-classes@npm:^7.22.6": version: 7.22.6 resolution: "@babel/plugin-transform-classes@npm:7.22.6" dependencies: @@ -1731,7 +1731,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.14.9, @babel/plugin-transform-react-jsx@npm:^7.19.0, @babel/plugin-transform-react-jsx@npm:^7.21.0, @babel/plugin-transform-react-jsx@npm:^7.22.5": +"@babel/plugin-transform-react-jsx@npm:^7.14.9, @babel/plugin-transform-react-jsx@npm:^7.19.0, @babel/plugin-transform-react-jsx@npm:^7.22.5": version: 7.22.5 resolution: "@babel/plugin-transform-react-jsx@npm:7.22.5" dependencies: @@ -1787,17 +1787,17 @@ __metadata: dependencies: "@babel/helper-module-imports": ^7.22.5 "@babel/helper-plugin-utils": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.3 - babel-plugin-polyfill-corejs3: ^0.8.1 - babel-plugin-polyfill-regenerator: ^0.5.0 - semver: ^6.3.0 + babel-plugin-polyfill-corejs2: ^0.4.4 + babel-plugin-polyfill-corejs3: ^0.8.2 + babel-plugin-polyfill-regenerator: ^0.5.1 + semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 checksum: 2dcd59bbf14622c2cc088a311a16073b777e34abe733a940c4df6d48fd58900fb7cb22aa2a4645939162cc717618f8e55e96c227ad61f9ae9bca098078aa7345 languageName: node linkType: hard -"@babel/plugin-transform-runtime@npm:^7.13.9, @babel/plugin-transform-runtime@npm:^7.22.0": +"@babel/plugin-transform-runtime@npm:^7.13.9, @babel/plugin-transform-runtime@npm:^7.22.9": version: 7.22.9 resolution: "@babel/plugin-transform-runtime@npm:7.22.9" dependencies: @@ -1944,8 +1944,8 @@ __metadata: version: 7.22.5 resolution: "@babel/preset-env@npm:7.22.5" dependencies: - "@babel/compat-data": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 + "@babel/compat-data": ^7.22.9 + "@babel/helper-compilation-targets": ^7.22.9 "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-validator-option": ^7.22.5 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.22.5 @@ -1970,13 +1970,13 @@ __metadata: "@babel/plugin-syntax-top-level-await": ^7.14.5 "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 "@babel/plugin-transform-arrow-functions": ^7.22.5 - "@babel/plugin-transform-async-generator-functions": ^7.22.5 + "@babel/plugin-transform-async-generator-functions": ^7.22.7 "@babel/plugin-transform-async-to-generator": ^7.22.5 "@babel/plugin-transform-block-scoped-functions": ^7.22.5 "@babel/plugin-transform-block-scoping": ^7.22.5 "@babel/plugin-transform-class-properties": ^7.22.5 "@babel/plugin-transform-class-static-block": ^7.22.5 - "@babel/plugin-transform-classes": ^7.22.5 + "@babel/plugin-transform-classes": ^7.22.6 "@babel/plugin-transform-computed-properties": ^7.22.5 "@babel/plugin-transform-destructuring": ^7.22.5 "@babel/plugin-transform-dotall-regex": ^7.22.5 @@ -2001,7 +2001,7 @@ __metadata: "@babel/plugin-transform-object-rest-spread": ^7.22.5 "@babel/plugin-transform-object-super": ^7.22.5 "@babel/plugin-transform-optional-catch-binding": ^7.22.5 - "@babel/plugin-transform-optional-chaining": ^7.22.5 + "@babel/plugin-transform-optional-chaining": ^7.22.6 "@babel/plugin-transform-parameters": ^7.22.5 "@babel/plugin-transform-private-methods": ^7.22.5 "@babel/plugin-transform-private-property-in-object": ^7.22.5 @@ -2019,18 +2019,18 @@ __metadata: "@babel/plugin-transform-unicode-sets-regex": ^7.22.5 "@babel/preset-modules": ^0.1.5 "@babel/types": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.3 - babel-plugin-polyfill-corejs3: ^0.8.1 - babel-plugin-polyfill-regenerator: ^0.5.0 - core-js-compat: ^3.30.2 - semver: ^6.3.0 + babel-plugin-polyfill-corejs2: ^0.4.4 + babel-plugin-polyfill-corejs3: ^0.8.2 + babel-plugin-polyfill-regenerator: ^0.5.1 + core-js-compat: ^3.31.0 + semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 checksum: dd2b70e96102fc2a64f57c3ab177abeb5aac3f71f47701787b6264d91d7d3ea3d38526d8e1133eb667ca88e87c997ed4a1b8d498ca8be2af07ae4995dfac1b83 languageName: node linkType: hard -"@babel/preset-env@npm:^7.16.5, @babel/preset-env@npm:^7.22.0": +"@babel/preset-env@npm:^7.16.5, @babel/preset-env@npm:^7.22.9": version: 7.22.9 resolution: "@babel/preset-env@npm:7.22.9" dependencies: @@ -2120,7 +2120,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-flow@npm:^7.13.13, @babel/preset-flow@npm:^7.21.0": +"@babel/preset-flow@npm:^7.13.13, @babel/preset-flow@npm:^7.22.5": version: 7.22.5 resolution: "@babel/preset-flow@npm:7.22.5" dependencies: @@ -2148,7 +2148,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-react@npm:^7.22.0": +"@babel/preset-react@npm:^7.22.5": version: 7.22.5 resolution: "@babel/preset-react@npm:7.22.5" dependencies: @@ -2164,7 +2164,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.21.0": +"@babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.22.5": version: 7.22.5 resolution: "@babel/preset-typescript@npm:7.22.5" dependencies: @@ -2238,7 +2238,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.8, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.0, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.8, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2": version: 7.22.6 resolution: "@babel/runtime@npm:7.22.6" dependencies: @@ -2278,7 +2278,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.22.0, @babel/traverse@npm:^7.22.5, @babel/traverse@npm:^7.22.6, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.0, @babel/traverse@npm:^7.8.6": +"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.22.5, @babel/traverse@npm:^7.22.6, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.0, @babel/traverse@npm:^7.8.6": version: 7.22.8 resolution: "@babel/traverse@npm:7.22.8" dependencies: @@ -2296,7 +2296,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.4, @babel/types@npm:^7.22.0, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.7.0, @babel/types@npm:^7.7.2, @babel/types@npm:^7.8.3, @babel/types@npm:^7.8.6, @babel/types@npm:^7.8.7, @babel/types@npm:^7.9.6": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.4, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.7.0, @babel/types@npm:^7.7.2, @babel/types@npm:^7.8.3, @babel/types@npm:^7.8.6, @babel/types@npm:^7.8.7, @babel/types@npm:^7.9.6": version: 7.22.5 resolution: "@babel/types@npm:7.22.5" dependencies: @@ -6319,7 +6319,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/builder-webpack5@workspace:builders/builder-webpack5" dependencies: - "@babel/core": ^7.22.0 + "@babel/core": ^7.22.9 "@storybook/addons": 7.1.0 "@storybook/channels": 7.1.0 "@storybook/client-api": 7.1.0 @@ -6418,8 +6418,9 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/cli@workspace:lib/cli" dependencies: - "@babel/core": ^7.22.0 - "@babel/preset-env": ^7.22.0 + "@babel/core": ^7.22.9 + "@babel/preset-env": ^7.22.9 + "@babel/types": ^7.22.5 "@ndelangen/get-tarball": ^3.0.7 "@storybook/client-api": 7.1.0 "@storybook/codemod": 7.1.0 @@ -6493,9 +6494,9 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/codemod@workspace:lib/codemod" dependencies: - "@babel/core": ^7.22.0 - "@babel/preset-env": ^7.22.0 - "@babel/types": ^7.22.0 + "@babel/core": ^7.22.9 + "@babel/preset-env": ^7.22.9 + "@babel/types": ^7.22.5 "@storybook/csf": ^0.1.0 "@storybook/csf-tools": 7.1.0 "@storybook/node-logger": 7.1.0 @@ -6697,10 +6698,10 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/csf-tools@workspace:lib/csf-tools" dependencies: - "@babel/generator": ^7.22.0 - "@babel/parser": ^7.22.0 - "@babel/traverse": ^7.22.0 - "@babel/types": ^7.22.0 + "@babel/generator": ^7.22.9 + "@babel/parser": ^7.22.7 + "@babel/traverse": ^7.22.8 + "@babel/types": ^7.22.5 "@storybook/csf": ^0.1.0 "@storybook/types": 7.1.0 "@types/fs-extra": ^11.0.1 @@ -6742,7 +6743,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/docs-tools@workspace:lib/docs-tools" dependencies: - "@babel/core": ^7.22.0 + "@babel/core": ^7.22.9 "@storybook/core-common": 7.1.0 "@storybook/preview-api": 7.1.0 "@storybook/types": 7.1.0 @@ -6988,20 +6989,20 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/nextjs@workspace:frameworks/nextjs" dependencies: - "@babel/core": ^7.22.0 + "@babel/core": ^7.22.9 "@babel/plugin-proposal-class-properties": ^7.18.6 "@babel/plugin-proposal-export-namespace-from": ^7.18.9 "@babel/plugin-proposal-numeric-separator": ^7.18.6 "@babel/plugin-proposal-object-rest-spread": ^7.20.7 "@babel/plugin-syntax-bigint": ^7.8.3 "@babel/plugin-syntax-dynamic-import": ^7.8.3 - "@babel/plugin-syntax-import-assertions": ^7.20.0 - "@babel/plugin-transform-runtime": ^7.22.0 - "@babel/preset-env": ^7.22.0 - "@babel/preset-react": ^7.22.0 - "@babel/preset-typescript": ^7.21.0 - "@babel/runtime": ^7.22.0 - "@babel/types": ^7.22.0 + "@babel/plugin-syntax-import-assertions": ^7.22.5 + "@babel/plugin-transform-runtime": ^7.22.9 + "@babel/preset-env": ^7.22.9 + "@babel/preset-react": ^7.22.5 + "@babel/preset-typescript": ^7.22.5 + "@babel/runtime": ^7.22.6 + "@babel/types": ^7.22.5 "@storybook/addon-actions": 7.1.0 "@storybook/builder-webpack5": 7.1.0 "@storybook/core-common": 7.1.0 @@ -7167,8 +7168,8 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/preset-preact-webpack@workspace:presets/preact-webpack" dependencies: - "@babel/plugin-transform-react-jsx": ^7.21.0 - "@babel/preset-typescript": ^7.21.0 + "@babel/plugin-transform-react-jsx": ^7.22.5 + "@babel/preset-typescript": ^7.22.5 "@storybook/core-webpack": 7.1.0 "@types/node": ^16.0.0 preact: ^10.5.13 @@ -7183,8 +7184,8 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/preset-react-webpack@workspace:presets/react-webpack" dependencies: - "@babel/preset-flow": ^7.21.0 - "@babel/preset-react": ^7.22.0 + "@babel/preset-flow": ^7.22.5 + "@babel/preset-react": ^7.22.5 "@pmmmwh/react-refresh-webpack-plugin": ^0.5.5 "@storybook/core-webpack": 7.1.0 "@storybook/docs-tools": 7.1.0 @@ -7303,7 +7304,7 @@ __metadata: dependencies: "@babel/plugin-syntax-dynamic-import": ^7.8.3 "@babel/plugin-syntax-import-meta": ^7.10.4 - "@babel/preset-env": ^7.22.0 + "@babel/preset-env": ^7.22.9 "@storybook/core-webpack": 7.1.0 "@types/node": ^16.0.0 babel-loader: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -7440,7 +7441,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/react@workspace:renderers/react" dependencies: - "@babel/core": ^7.22.0 + "@babel/core": ^7.22.9 "@storybook/client-logger": 7.1.0 "@storybook/core-client": 7.1.0 "@storybook/docs-tools": 7.1.0 @@ -7480,11 +7481,11 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/root@workspace:." dependencies: - "@babel/core": ^7.22.0 - "@babel/preset-env": ^7.22.0 - "@babel/preset-react": ^7.22.0 - "@babel/preset-typescript": ^7.21.0 - "@babel/runtime": ^7.20.1 + "@babel/core": ^7.22.9 + "@babel/preset-env": ^7.22.9 + "@babel/preset-react": ^7.22.5 + "@babel/preset-typescript": ^7.22.5 + "@babel/runtime": ^7.22.6 "@emotion/jest": ^11.10.0 "@jest/globals": ^29.3.1 "@nx/workspace": 16.2.1 @@ -8054,7 +8055,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/web-components-webpack5@workspace:frameworks/web-components-webpack5" dependencies: - "@babel/preset-env": ^7.22.0 + "@babel/preset-env": ^7.22.9 "@storybook/builder-webpack5": 7.1.0 "@storybook/core-common": 7.1.0 "@storybook/preset-web-components-webpack": 7.1.0 @@ -11303,7 +11304,7 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-corejs2@npm:^0.4.3, babel-plugin-polyfill-corejs2@npm:^0.4.4": +"babel-plugin-polyfill-corejs2@npm:^0.4.4": version: 0.4.4 resolution: "babel-plugin-polyfill-corejs2@npm:0.4.4" dependencies: @@ -11316,7 +11317,7 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-corejs3@npm:^0.8.1, babel-plugin-polyfill-corejs3@npm:^0.8.2": +"babel-plugin-polyfill-corejs3@npm:^0.8.2": version: 0.8.2 resolution: "babel-plugin-polyfill-corejs3@npm:0.8.2" dependencies: @@ -11328,7 +11329,7 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-regenerator@npm:^0.5.0, babel-plugin-polyfill-regenerator@npm:^0.5.1": +"babel-plugin-polyfill-regenerator@npm:^0.5.1": version: 0.5.1 resolution: "babel-plugin-polyfill-regenerator@npm:0.5.1" dependencies: @@ -13382,7 +13383,7 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.30.2, core-js-compat@npm:^3.31.0": +"core-js-compat@npm:^3.31.0": version: 3.31.1 resolution: "core-js-compat@npm:3.31.1" dependencies: diff --git a/docs/faq.md b/docs/faq.md index be9c8d6491b9..03432b6ce3ed 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -10,7 +10,7 @@ Here are some answers to frequently asked questions. If you have a question, you - [How can I run coverage tests with Create React App and leave out stories?](#how-can-i-run-coverage-tests-with-create-react-app-and-leave-out-stories) - [I see `ReferenceError: React is not defined` when using Storybook with Next.js](#i-see-referenceerror-react-is-not-defined-when-using-storybook-with-nextjs) - [How do I setup Storybook to share Webpack configuration with Next.js?](#how-do-i-setup-storybook-to-share-webpack-configuration-with-nextjs) -- [How do I fix module resolution while using pnpm Plug-n-Play?](#how-do-i-fix-module-resolution-while-using-pnpm-plug-n-play) +- [How do I fix module resolution in special environments?](#how-do-i-fix-module-resolution-in-special-environments) - [How do I setup React Fast Refresh with Storybook?](#how-do-i-setup-react-fast-refresh-with-storybook) - [How do I setup the new React Context Root API with Storybook?](#how-do-i-setup-the-new-react-context-root-api-with-storybook) - [Why is there no addons channel?](#why-is-there-no-addons-channel) @@ -117,9 +117,9 @@ export default { }; ``` -## How do I fix module resolution while using pnpm Plug-n-Play? +## How do I fix module resolution in special environments? -In case you are using [pnpm](https://pnpm.io/), you might run into issues with module resolution similar to this when running Storybook: +In case you are using [yarn Plug-n-Play](https://yarnpkg.com/features/pnp) or your project is set up within a mono repository environment, you might run into issues with module resolution similar to this when running Storybook: ```shell WARN Failed to load preset: "@storybook/react-webpack5/preset"` diff --git a/docs/snippets/common/storybook-main-pnpm-with-module-resolution.js.mdx b/docs/snippets/common/storybook-main-pnpm-with-module-resolution.js.mdx index 7b70439e066a..4ffa05ad3ff6 100644 --- a/docs/snippets/common/storybook-main-pnpm-with-module-resolution.js.mdx +++ b/docs/snippets/common/storybook-main-pnpm-with-module-resolution.js.mdx @@ -3,19 +3,19 @@ import path from 'path'; -const wrapForPnp = (packageName) => +const getAbsolutePath = (packageName) => path.dirname(require.resolve(path.join(packageName, 'package.json'))); export default { framework: { // Replace your-framework with the framework you are using (e.g., react-webpack5, vue3-vite) - name: wrapForPnp('@storybook/your-framework'), + name: getAbsolutePath('@storybook/your-framework'), options: {}, }, stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [ - //👇 Use wrapForPnp when referencing Storybook's addons and frameworks - wrapForPnp('@storybook/addon-essentials'), + //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks + getAbsolutePath('@storybook/addon-essentials'), ], }; ``` diff --git a/docs/snippets/common/storybook-main-pnpm-with-module-resolution.ts.mdx b/docs/snippets/common/storybook-main-pnpm-with-module-resolution.ts.mdx index 9dfedba3d0c1..a7e750975b3d 100644 --- a/docs/snippets/common/storybook-main-pnpm-with-module-resolution.ts.mdx +++ b/docs/snippets/common/storybook-main-pnpm-with-module-resolution.ts.mdx @@ -6,19 +6,19 @@ import type { StorybookConfig } from '@storybook/your-framework'; import path from 'path'; -const wrapForPnp = (packageName: string) => +const getAbsolutePath = (packageName: string): any => path.dirname(require.resolve(path.join(packageName, 'package.json'))); const config: StorybookConfig = { framework: { // Replace your-framework with the same one you've imported above. - name: wrapForPnp('@storybook/your-framework'), + name: getAbsolutePath('@storybook/your-framework'), options: {}, }, stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [ - //👇 Use wrapForPnp when referencing Storybook's addons and frameworks - wrapForPnp('@storybook/addon-essentials'), + //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks + getAbsolutePath('@storybook/addon-essentials'), ], };