mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-15 05:02:24 +08:00
Merge branch 'next' into docs_updates_contributions
This commit is contained in:
commit
6a94ba89e7
@ -1,4 +1,4 @@
|
||||
import { dirname, isAbsolute, join, resolve } from 'path';
|
||||
import { dirname, join, resolve } from 'path';
|
||||
import { DefinePlugin, HotModuleReplacementPlugin, ProgressPlugin, ProvidePlugin } from 'webpack';
|
||||
import type { Configuration } from 'webpack';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
@ -7,25 +7,20 @@ import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';
|
||||
import TerserWebpackPlugin from 'terser-webpack-plugin';
|
||||
import VirtualModulePlugin from 'webpack-virtual-modules';
|
||||
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
||||
import slash from 'slash';
|
||||
import type { TransformOptions as EsbuildOptions } from 'esbuild';
|
||||
import type { JsMinifyOptions as SwcOptions } from '@swc/core';
|
||||
import type { Options, CoreConfig, DocsOptions, PreviewAnnotation } from '@storybook/types';
|
||||
import type { Options, CoreConfig, DocsOptions } from '@storybook/types';
|
||||
import { globalsNameReferenceMap } from '@storybook/preview/globals';
|
||||
import {
|
||||
getBuilderOptions,
|
||||
getRendererName,
|
||||
stringifyProcessEnvs,
|
||||
handlebars,
|
||||
interpolate,
|
||||
normalizeStories,
|
||||
readTemplate,
|
||||
loadPreviewOrConfigFile,
|
||||
isPreservingSymlinks,
|
||||
} from '@storybook/core-common';
|
||||
import { toRequireContextString, toImportFn } from '@storybook/core-webpack';
|
||||
import type { BuilderOptions } from '@storybook/core-webpack';
|
||||
import { getVirtualModuleMapping } from '@storybook/core-webpack';
|
||||
import { dedent } from 'ts-dedent';
|
||||
import type { BuilderOptions, TypescriptOptions } from '../types';
|
||||
import type { TypescriptOptions } from '../types';
|
||||
import { createBabelLoader, createSWCLoader } from './loaders';
|
||||
|
||||
const getAbsolutePath = <I extends string>(input: I): I =>
|
||||
@ -114,92 +109,6 @@ export default async (
|
||||
|
||||
const builderOptions = await getBuilderOptions<BuilderOptions>(options);
|
||||
|
||||
const previewAnnotations = [
|
||||
...(await presets.apply<PreviewAnnotation[]>('previewAnnotations', [], options)).map(
|
||||
(entry) => {
|
||||
// If entry is an object, use the absolute import specifier.
|
||||
// This is to maintain back-compat with community addons that bundle other addons
|
||||
// and package managers that "hide" sub dependencies (e.g. pnpm / yarn pnp)
|
||||
// The vite builder uses the bare import specifier.
|
||||
if (typeof entry === 'object') {
|
||||
return entry.absolute;
|
||||
}
|
||||
|
||||
// TODO: Remove as soon as we drop support for disabled StoryStoreV7
|
||||
if (isAbsolute(entry)) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
return slash(entry);
|
||||
}
|
||||
),
|
||||
loadPreviewOrConfigFile(options),
|
||||
].filter(Boolean);
|
||||
|
||||
const virtualModuleMapping: Record<string, string> = {};
|
||||
if (features?.storyStoreV7) {
|
||||
const storiesFilename = 'storybook-stories.js';
|
||||
const storiesPath = resolve(join(workingDir, storiesFilename));
|
||||
|
||||
const needPipelinedImport = !!builderOptions.lazyCompilation && !isProd;
|
||||
virtualModuleMapping[storiesPath] = toImportFn(stories, { needPipelinedImport });
|
||||
const configEntryPath = resolve(join(workingDir, 'storybook-config-entry.js'));
|
||||
virtualModuleMapping[configEntryPath] = handlebars(
|
||||
await readTemplate(
|
||||
require.resolve(
|
||||
'@storybook/builder-webpack5/templates/virtualModuleModernEntry.js.handlebars'
|
||||
)
|
||||
),
|
||||
{
|
||||
storiesFilename,
|
||||
previewAnnotations,
|
||||
}
|
||||
// We need to double escape `\` for webpack. We may have some in windows paths
|
||||
).replace(/\\/g, '\\\\');
|
||||
entries.push(configEntryPath);
|
||||
} else {
|
||||
const rendererName = await getRendererName(options);
|
||||
|
||||
const rendererInitEntry = resolve(join(workingDir, 'storybook-init-renderer-entry.js'));
|
||||
virtualModuleMapping[rendererInitEntry] = `import '${slash(rendererName)}';`;
|
||||
entries.push(rendererInitEntry);
|
||||
|
||||
const entryTemplate = await readTemplate(
|
||||
join(__dirname, '..', '..', 'templates', 'virtualModuleEntry.template.js')
|
||||
);
|
||||
|
||||
previewAnnotations.forEach((previewAnnotationFilename: string | undefined) => {
|
||||
if (!previewAnnotationFilename) return;
|
||||
|
||||
// Ensure that relative paths end up mapped to a filename in the cwd, so a later import
|
||||
// of the `previewAnnotationFilename` in the template works.
|
||||
const entryFilename = previewAnnotationFilename.startsWith('.')
|
||||
? `${previewAnnotationFilename.replace(/(\w)(\/|\\)/g, '$1-')}-generated-config-entry.js`
|
||||
: `${previewAnnotationFilename}-generated-config-entry.js`;
|
||||
// NOTE: although this file is also from the `dist/cjs` directory, it is actually a ESM
|
||||
// file, see https://github.com/storybookjs/storybook/pull/16727#issuecomment-986485173
|
||||
virtualModuleMapping[entryFilename] = interpolate(entryTemplate, {
|
||||
previewAnnotationFilename,
|
||||
});
|
||||
entries.push(entryFilename);
|
||||
});
|
||||
if (stories.length > 0) {
|
||||
const storyTemplate = await readTemplate(
|
||||
join(__dirname, '..', '..', 'templates', 'virtualModuleStory.template.js')
|
||||
);
|
||||
// NOTE: this file has a `.cjs` extension as it is a CJS file (from `dist/cjs`) and runs
|
||||
// in the user's webpack mode, which may be strict about the use of require/import.
|
||||
// See https://github.com/storybookjs/storybook/issues/14877
|
||||
const storiesFilename = resolve(join(workingDir, `generated-stories-entry.cjs`));
|
||||
virtualModuleMapping[storiesFilename] = interpolate(storyTemplate, {
|
||||
rendererName,
|
||||
})
|
||||
// Make sure we also replace quotes for this one
|
||||
.replace("'{{stories}}'", stories.map(toRequireContextString).join(','));
|
||||
entries.push(storiesFilename);
|
||||
}
|
||||
}
|
||||
|
||||
const shouldCheckTs =
|
||||
typescriptOptions.check && !typescriptOptions.skipBabel && !typescriptOptions.skipCompiler;
|
||||
const tsCheckOptions = typescriptOptions.checkOptions || {};
|
||||
@ -226,6 +135,12 @@ export default async (
|
||||
externals['@storybook/blocks'] = '__STORYBOOK_BLOCKS_EMPTY_MODULE__';
|
||||
}
|
||||
|
||||
const virtualModuleMapping = await getVirtualModuleMapping(options);
|
||||
|
||||
Object.keys(virtualModuleMapping).forEach((key) => {
|
||||
entries.push(key);
|
||||
});
|
||||
|
||||
return {
|
||||
name: 'preview',
|
||||
mode: isProd ? 'production' : 'development',
|
||||
|
@ -10,6 +10,7 @@ export const createBabelLoader = (
|
||||
typescriptOptions: TypescriptOptions,
|
||||
excludes: string[] = []
|
||||
) => {
|
||||
logger.info(dedent`Using Babel compiler`);
|
||||
return {
|
||||
test: typescriptOptions.skipBabel ? /\.(mjs|jsx?)$/ : /\.(mjs|tsx?|jsx?)$/,
|
||||
use: [
|
||||
@ -24,9 +25,7 @@ export const createBabelLoader = (
|
||||
};
|
||||
|
||||
export const createSWCLoader = async (excludes: string[] = [], options: Options) => {
|
||||
logger.warn(dedent`
|
||||
The SWC loader is an experimental feature and may change or even be removed at any time.
|
||||
`);
|
||||
logger.info(dedent`Using SWC compiler`);
|
||||
|
||||
const swc = await options.presets.apply('swc', {}, options);
|
||||
const typescriptOptions = await options.presets.apply<{ skipCompiler?: boolean }>(
|
||||
@ -49,12 +48,8 @@ export const createSWCLoader = async (excludes: string[] = [], options: Options)
|
||||
};
|
||||
return {
|
||||
test: typescriptOptions.skipCompiler ? /\.(mjs|cjs|jsx?)$/ : /\.(mjs|cjs|tsx?|jsx?)$/,
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve('swc-loader'),
|
||||
options: config,
|
||||
},
|
||||
],
|
||||
loader: require.resolve('swc-loader'),
|
||||
options: config,
|
||||
include: [getProjectRoot()],
|
||||
exclude: [/node_modules/, ...excludes],
|
||||
};
|
||||
|
@ -31,18 +31,22 @@ test.describe('addon-controls', () => {
|
||||
);
|
||||
const toggle = sbPage.panelContent().locator('input[name=primary]');
|
||||
await toggle.click();
|
||||
await expect(sbPage.previewRoot().locator('button')).toHaveCSS(
|
||||
'background-color',
|
||||
'rgba(0, 0, 0, 0)'
|
||||
);
|
||||
await expect(async () => {
|
||||
await expect(sbPage.previewRoot().locator('button')).toHaveCSS(
|
||||
'background-color',
|
||||
'rgba(0, 0, 0, 0)'
|
||||
);
|
||||
}).toPass();
|
||||
|
||||
// Color picker: Background color
|
||||
const color = sbPage.panelContent().locator('input[placeholder="Choose color..."]');
|
||||
await color.fill('red');
|
||||
await expect(sbPage.previewRoot().locator('button')).toHaveCSS(
|
||||
'background-color',
|
||||
'rgb(255, 0, 0)'
|
||||
);
|
||||
await expect(async () => {
|
||||
await expect(sbPage.previewRoot().locator('button')).toHaveCSS(
|
||||
'background-color',
|
||||
'rgb(255, 0, 0)'
|
||||
);
|
||||
}).toPass();
|
||||
|
||||
// TODO: enable this once the controls for size are aligned in all CLI templates.
|
||||
// Radio buttons: Size
|
||||
|
@ -122,7 +122,12 @@ export default {
|
||||
framework: {
|
||||
// name: '@storybook/react-webpack5', // Remove this
|
||||
name: '@storybook/nextjs', // Add this
|
||||
options: {},
|
||||
options: {
|
||||
builder: {
|
||||
// Set useSWC to true if you want to try out the experimental SWC compiler in Next.js >= 14.0.0
|
||||
useSWC: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
@ -36,6 +36,11 @@
|
||||
"types": "./dist/preset.d.ts",
|
||||
"require": "./dist/preset.js"
|
||||
},
|
||||
"./font/webpack/loader/storybook-nextjs-font-loader": {
|
||||
"types": "./dist/font/webpack/loader/storybook-nextjs-font-loader.d.ts",
|
||||
"require": "./dist/font/webpack/loader/storybook-nextjs-font-loader.js",
|
||||
"import": "./dist/font/webpack/loader/storybook-nextjs-font-loader.mjs"
|
||||
},
|
||||
"./dist/preview.mjs": "./dist/preview.mjs",
|
||||
"./next-image-loader-stub.js": {
|
||||
"types": "./dist/next-image-loader-stub.d.ts",
|
||||
@ -83,10 +88,12 @@
|
||||
"@babel/preset-react": "^7.22.15",
|
||||
"@babel/preset-typescript": "^7.23.2",
|
||||
"@babel/runtime": "^7.23.2",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
|
||||
"@storybook/addon-actions": "workspace:*",
|
||||
"@storybook/builder-webpack5": "workspace:*",
|
||||
"@storybook/core-common": "workspace:*",
|
||||
"@storybook/core-events": "workspace:*",
|
||||
"@storybook/core-webpack": "workspace:*",
|
||||
"@storybook/node-logger": "workspace:*",
|
||||
"@storybook/preset-react-webpack": "workspace:*",
|
||||
"@storybook/preview-api": "workspace:*",
|
||||
@ -117,7 +124,7 @@
|
||||
"@types/babel__plugin-transform-runtime": "^7",
|
||||
"@types/babel__preset-env": "^7",
|
||||
"@types/loader-utils": "^2.0.5",
|
||||
"next": "^14.0.0",
|
||||
"next": "^14.0.2",
|
||||
"typescript": "^4.9.3",
|
||||
"webpack": "^5.65.0"
|
||||
},
|
||||
@ -156,7 +163,8 @@
|
||||
"./src/images/next-future-image.tsx",
|
||||
"./src/images/next-legacy-image.tsx",
|
||||
"./src/images/next-image.tsx",
|
||||
"./src/font/webpack/loader/storybook-nextjs-font-loader.ts"
|
||||
"./src/font/webpack/loader/storybook-nextjs-font-loader.ts",
|
||||
"./src/swc/next-swc-loader-patch.ts"
|
||||
],
|
||||
"externals": [
|
||||
"sb-original/next/image",
|
||||
|
@ -34,6 +34,9 @@ export const configureCss = (baseConfig: WebpackConfig, nextConfig: NextConfig):
|
||||
},
|
||||
require.resolve('postcss-loader'),
|
||||
],
|
||||
// We transform the "target.css" files from next.js into Javascript
|
||||
// for Next.js to support fonts, so it should be ignored by the css-loader.
|
||||
exclude: /next\/.*\/target.css$/,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
@ -1,14 +1,22 @@
|
||||
import type { Configuration } from 'webpack';
|
||||
|
||||
export function configureNextFont(baseConfig: Configuration) {
|
||||
baseConfig.plugins = [...(baseConfig.plugins || [])];
|
||||
baseConfig.resolveLoader = {
|
||||
...baseConfig.resolveLoader,
|
||||
alias: {
|
||||
...baseConfig.resolveLoader?.alias,
|
||||
'storybook-nextjs-font-loader': require.resolve(
|
||||
'./font/webpack/loader/storybook-nextjs-font-loader'
|
||||
),
|
||||
},
|
||||
};
|
||||
export function configureNextFont(baseConfig: Configuration, isSWC?: boolean) {
|
||||
const fontLoaderPath = require.resolve(
|
||||
'@storybook/nextjs/font/webpack/loader/storybook-nextjs-font-loader'
|
||||
);
|
||||
|
||||
if (isSWC) {
|
||||
baseConfig.module?.rules?.push({
|
||||
test: /next\/.*\/target.css$/,
|
||||
loader: fontLoaderPath,
|
||||
});
|
||||
} else {
|
||||
baseConfig.resolveLoader = {
|
||||
...baseConfig.resolveLoader,
|
||||
alias: {
|
||||
...baseConfig.resolveLoader?.alias,
|
||||
'storybook-nextjs-font-loader': fontLoaderPath,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
import loaderUtils from 'next/dist/compiled/loader-utils3';
|
||||
import { getProjectRoot } from '@storybook/core-common';
|
||||
import path from 'path';
|
||||
|
||||
import type { LoaderOptions } from '../types';
|
||||
@ -11,7 +12,9 @@ export async function getFontFaceDeclarations(options: LoaderOptions, rootContex
|
||||
const localFontSrc = options.props.src as LocalFontSrc;
|
||||
|
||||
// Parent folder relative to the root context
|
||||
const parentFolder = path.dirname(options.filename).replace(rootContext, '');
|
||||
const parentFolder = path
|
||||
.dirname(path.join(getProjectRoot(), options.filename))
|
||||
.replace(rootContext, '');
|
||||
|
||||
const { validateData } = require('../utils/local-font-utils');
|
||||
const { weight, style, variable } = validateData('', options.props);
|
||||
|
@ -14,18 +14,34 @@ type FontFaceDeclaration = {
|
||||
};
|
||||
|
||||
export default async function storybookNextjsFontLoader(this: any) {
|
||||
const options = this.getOptions() as LoaderOptions;
|
||||
const loaderOptions = this.getOptions() as LoaderOptions;
|
||||
let options;
|
||||
|
||||
if (Object.keys(loaderOptions).length > 0) {
|
||||
// handles Babel mode
|
||||
options = loaderOptions;
|
||||
} else {
|
||||
// handles SWC mode
|
||||
const importQuery = JSON.parse(this.resourceQuery.slice(1));
|
||||
|
||||
options = {
|
||||
filename: importQuery.path,
|
||||
fontFamily: importQuery.import,
|
||||
props: importQuery.arguments[0],
|
||||
source: this.context.replace(this.rootContext, ''),
|
||||
};
|
||||
}
|
||||
|
||||
// get execution context
|
||||
const rootCtx = this.rootContext;
|
||||
|
||||
let fontFaceDeclaration: FontFaceDeclaration | undefined;
|
||||
|
||||
if (options.source === 'next/font/google' || options.source === '@next/font/google') {
|
||||
if (options.source.endsWith('next/font/google') || options.source.endsWith('@next/font/google')) {
|
||||
fontFaceDeclaration = await getGoogleFontFaceDeclarations(options);
|
||||
}
|
||||
|
||||
if (options.source === 'next/font/local' || options.source === '@next/font/local') {
|
||||
if (options.source.endsWith('next/font/local') || options.source.endsWith('@next/font/local')) {
|
||||
fontFaceDeclaration = await getLocalFontFaceDeclarations(options, rootCtx);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import { configureNextFont } from './font/webpack/configureNextFont';
|
||||
import nextBabelPreset from './babel/preset';
|
||||
import { configureNodePolyfills } from './nodePolyfills/webpack';
|
||||
import { configureAliasing } from './dependency-map';
|
||||
import { configureSWCLoader } from './swc/loader';
|
||||
|
||||
export const addons: PresetProperty<'addons', StorybookConfig> = [
|
||||
dirname(require.resolve(join('@storybook/preset-react-webpack', 'package.json'))),
|
||||
@ -61,7 +62,9 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti
|
||||
name: dirname(
|
||||
require.resolve(join('@storybook/builder-webpack5', 'package.json'))
|
||||
) as '@storybook/builder-webpack5',
|
||||
options: typeof framework === 'string' ? {} : framework.options.builder || {},
|
||||
options: {
|
||||
...(typeof framework === 'string' ? {} : framework.options.builder || {}),
|
||||
},
|
||||
},
|
||||
renderer: dirname(require.resolve(join('@storybook/react', 'package.json'))),
|
||||
};
|
||||
@ -135,7 +138,7 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig,
|
||||
const frameworkOptions = await options.presets.apply<{ options: FrameworkOptions }>(
|
||||
'frameworkOptions'
|
||||
);
|
||||
const { options: { nextConfigPath } = {} } = frameworkOptions;
|
||||
const { options: { nextConfigPath, builder } = {} } = frameworkOptions;
|
||||
const nextConfig = await configureConfig({
|
||||
baseConfig,
|
||||
nextConfigPath,
|
||||
@ -143,7 +146,7 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig,
|
||||
});
|
||||
|
||||
configureAliasing(baseConfig);
|
||||
configureNextFont(baseConfig);
|
||||
configureNextFont(baseConfig, builder?.useSWC);
|
||||
configureNextImport(baseConfig);
|
||||
configureRuntimeNextjsVersionResolution(baseConfig);
|
||||
configureImports({ baseConfig, configDir: options.configDir });
|
||||
@ -152,5 +155,10 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig,
|
||||
configureStyledJsx(baseConfig);
|
||||
configureNodePolyfills(baseConfig);
|
||||
|
||||
// TODO: In Storybook 8.0, we have to check whether the babel-compiler addon is used. Otherwise, swc should be used.
|
||||
if (builder?.useSWC) {
|
||||
await configureSWCLoader(baseConfig, options, nextConfig);
|
||||
}
|
||||
|
||||
return baseConfig;
|
||||
};
|
||||
|
68
code/frameworks/nextjs/src/swc/loader.ts
Normal file
68
code/frameworks/nextjs/src/swc/loader.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { getProjectRoot } from '@storybook/core-common';
|
||||
import { getVirtualModuleMapping } from '@storybook/core-webpack';
|
||||
import type { Options } from '@storybook/types';
|
||||
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||
import type { NextConfig } from 'next';
|
||||
import path from 'path';
|
||||
import type { RuleSetRule } from 'webpack';
|
||||
import semver from 'semver';
|
||||
import { NextjsSWCNotSupportedError } from 'lib/core-events/src/errors/server-errors';
|
||||
import { getNextjsVersion } from '../utils';
|
||||
|
||||
export const configureSWCLoader = async (
|
||||
baseConfig: any,
|
||||
options: Options,
|
||||
nextConfig: NextConfig
|
||||
) => {
|
||||
const isDevelopment = options.configType !== 'PRODUCTION';
|
||||
const version = getNextjsVersion();
|
||||
|
||||
if (semver.lt(version, '14.0.0')) {
|
||||
throw new NextjsSWCNotSupportedError();
|
||||
}
|
||||
|
||||
const dir = getProjectRoot();
|
||||
|
||||
baseConfig.plugins = [
|
||||
...baseConfig.plugins,
|
||||
new ReactRefreshWebpackPlugin({
|
||||
overlay: {
|
||||
sockIntegration: 'whm',
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const virtualModules = await getVirtualModuleMapping(options);
|
||||
|
||||
baseConfig.module.rules = [
|
||||
// TODO: Remove filtering in Storybook 8.0
|
||||
...baseConfig.module.rules.filter((r: RuleSetRule) => {
|
||||
return !r.loader?.includes('swc-loader');
|
||||
}),
|
||||
{
|
||||
test: /\.(m?(j|t)sx?)$/,
|
||||
include: [getProjectRoot()],
|
||||
exclude: [/(node_modules)/, ...Object.keys(virtualModules)],
|
||||
enforce: 'post',
|
||||
use: {
|
||||
// we use our own patch because we need to remove tracing from the original code
|
||||
// which is not possible otherwise
|
||||
loader: require.resolve('./swc/next-swc-loader-patch.js'),
|
||||
options: {
|
||||
isServer: false,
|
||||
rootDir: dir,
|
||||
pagesDir: `${dir}/pages`,
|
||||
appDir: `${dir}/apps`,
|
||||
hasReactRefresh: isDevelopment,
|
||||
nextConfig,
|
||||
supportedBrowsers: require('next/dist/build/utils').getSupportedBrowsers(
|
||||
dir,
|
||||
isDevelopment
|
||||
),
|
||||
swcCacheDir: path.join(dir, nextConfig?.distDir ?? '.next', 'cache', 'swc'),
|
||||
bundleTarget: 'default',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
193
code/frameworks/nextjs/src/swc/next-swc-loader-patch.ts
Normal file
193
code/frameworks/nextjs/src/swc/next-swc-loader-patch.ts
Normal file
@ -0,0 +1,193 @@
|
||||
// THIS IS A PATCH over the original code from Next 14.0.0
|
||||
// we use our own patch because we need to remove tracing from the original code
|
||||
// which is not possible otherwise
|
||||
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
/*
|
||||
Copyright (c) 2017 The swc Project Developers
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import type { NextConfig } from 'next';
|
||||
import { isWasm, transform } from 'next/dist/build/swc';
|
||||
import { getLoaderSWCOptions } from 'next/dist/build/swc/options';
|
||||
import path, { isAbsolute } from 'path';
|
||||
|
||||
export interface SWCLoaderOptions {
|
||||
rootDir: string;
|
||||
isServer: boolean;
|
||||
pagesDir?: string;
|
||||
appDir?: string;
|
||||
hasReactRefresh: boolean;
|
||||
optimizeServerReact?: boolean;
|
||||
nextConfig: NextConfig;
|
||||
jsConfig: any;
|
||||
supportedBrowsers: string[] | undefined;
|
||||
swcCacheDir: string;
|
||||
serverComponents?: boolean;
|
||||
isReactServerLayer?: boolean;
|
||||
}
|
||||
|
||||
const mockCurrentTraceSpan = {
|
||||
traceChild: (name: string) => mockCurrentTraceSpan,
|
||||
traceAsyncFn: async (fn: any) => fn(),
|
||||
};
|
||||
|
||||
async function loaderTransform(this: any, parentTrace: any, source?: string, inputSourceMap?: any) {
|
||||
// Make the loader async
|
||||
const filename = this.resourcePath;
|
||||
|
||||
const loaderOptions: SWCLoaderOptions = this.getOptions() || {};
|
||||
|
||||
const {
|
||||
isServer,
|
||||
rootDir,
|
||||
pagesDir,
|
||||
appDir,
|
||||
hasReactRefresh,
|
||||
nextConfig,
|
||||
jsConfig,
|
||||
supportedBrowsers,
|
||||
swcCacheDir,
|
||||
serverComponents,
|
||||
isReactServerLayer,
|
||||
} = loaderOptions;
|
||||
const isPageFile = filename.startsWith(pagesDir);
|
||||
const relativeFilePathFromRoot = path.relative(rootDir, filename);
|
||||
|
||||
const swcOptions = getLoaderSWCOptions({
|
||||
pagesDir,
|
||||
appDir,
|
||||
filename,
|
||||
isServer,
|
||||
isPageFile,
|
||||
development: this.mode === 'development',
|
||||
hasReactRefresh,
|
||||
modularizeImports: nextConfig?.modularizeImports,
|
||||
optimizePackageImports: nextConfig?.experimental?.optimizePackageImports,
|
||||
swcPlugins: nextConfig?.experimental?.swcPlugins,
|
||||
compilerOptions: nextConfig?.compiler,
|
||||
optimizeServerReact: nextConfig?.experimental?.optimizeServerReact,
|
||||
jsConfig,
|
||||
supportedBrowsers,
|
||||
swcCacheDir,
|
||||
relativeFilePathFromRoot,
|
||||
serverComponents,
|
||||
isReactServerLayer,
|
||||
});
|
||||
|
||||
const programmaticOptions = {
|
||||
...swcOptions,
|
||||
filename,
|
||||
inputSourceMap: inputSourceMap ? JSON.stringify(inputSourceMap) : undefined,
|
||||
|
||||
// Set the default sourcemap behavior based on Webpack's mapping flag,
|
||||
sourceMaps: this.sourceMap,
|
||||
inlineSourcesContent: this.sourceMap,
|
||||
|
||||
// Ensure that Webpack will get a full absolute path in the sourcemap
|
||||
// so that it can properly map the module back to its internal cached
|
||||
// modules.
|
||||
sourceFileName: filename,
|
||||
};
|
||||
|
||||
if (!programmaticOptions.inputSourceMap) {
|
||||
delete programmaticOptions.inputSourceMap;
|
||||
}
|
||||
|
||||
// auto detect development mode
|
||||
if (
|
||||
this.mode &&
|
||||
programmaticOptions.jsc &&
|
||||
programmaticOptions.jsc.transform &&
|
||||
programmaticOptions.jsc.transform.react &&
|
||||
!Object.prototype.hasOwnProperty.call(programmaticOptions.jsc.transform.react, 'development')
|
||||
) {
|
||||
programmaticOptions.jsc.transform.react.development = this.mode === 'development';
|
||||
}
|
||||
|
||||
const swcSpan = parentTrace.traceChild('next-swc-transform');
|
||||
return swcSpan.traceAsyncFn(() =>
|
||||
transform(source as any, programmaticOptions).then((output) => {
|
||||
if (output.eliminatedPackages && this.eliminatedPackages) {
|
||||
for (const pkg of JSON.parse(output.eliminatedPackages)) {
|
||||
this.eliminatedPackages.add(pkg);
|
||||
}
|
||||
}
|
||||
return [output.code, output.map ? JSON.parse(output.map) : undefined];
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const EXCLUDED_PATHS = /[\\/](cache[\\/][^\\/]+\.zip[\\/]node_modules|__virtual__)[\\/]/g;
|
||||
|
||||
export function pitch(this: any) {
|
||||
const callback = this.async();
|
||||
(async () => {
|
||||
if (
|
||||
// TODO: investigate swc file reading in PnP mode?
|
||||
!process.versions.pnp &&
|
||||
!EXCLUDED_PATHS.test(this.resourcePath) &&
|
||||
this.loaders.length - 1 === this.loaderIndex &&
|
||||
isAbsolute(this.resourcePath) &&
|
||||
!(await isWasm())
|
||||
) {
|
||||
const loaderSpan = mockCurrentTraceSpan.traceChild('next-swc-loader');
|
||||
this.addDependency(this.resourcePath);
|
||||
return loaderSpan.traceAsyncFn(() => loaderTransform.call(this, loaderSpan));
|
||||
}
|
||||
|
||||
return null;
|
||||
})().then((r) => {
|
||||
if (r) return callback(null, ...r);
|
||||
callback();
|
||||
return null;
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function sanitizeSourceMap(rawSourceMap: any): any {
|
||||
const { sourcesContent, ...sourceMap } = rawSourceMap ?? {};
|
||||
|
||||
// JSON parse/stringify trick required for swc to accept the SourceMap
|
||||
return JSON.parse(JSON.stringify(sourceMap));
|
||||
}
|
||||
|
||||
export default function swcLoader(this: any, inputSource: string, inputSourceMap: any) {
|
||||
const loaderSpan = mockCurrentTraceSpan.traceChild('next-swc-loader');
|
||||
const callback = this.async();
|
||||
loaderSpan
|
||||
.traceAsyncFn(() =>
|
||||
loaderTransform.call(this, loaderSpan, inputSource, sanitizeSourceMap(inputSourceMap))
|
||||
)
|
||||
.then(
|
||||
([transformedSource, outputSourceMap]: any) => {
|
||||
callback(null, transformedSource, outputSourceMap || inputSourceMap);
|
||||
},
|
||||
(err: Error) => {
|
||||
callback(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// accept Buffers instead of strings
|
||||
export const raw = true;
|
@ -1,5 +1,4 @@
|
||||
import { join } from 'path';
|
||||
import semver from 'semver';
|
||||
import { baseGenerator } from '../baseGenerator';
|
||||
import type { Generator } from '../types';
|
||||
import { CoreBuilder } from '../../project_types';
|
||||
@ -13,10 +12,6 @@ const generator: Generator<{ projectName: string }> = async (
|
||||
options,
|
||||
commandOptions
|
||||
) => {
|
||||
const angularVersion = await packageManager.getPackageVersion('@angular/core');
|
||||
const isWebpack5 = angularVersion && semver.gte(angularVersion, '12.0.0');
|
||||
const updatedOptions = isWebpack5 ? { ...options, builder: CoreBuilder.Webpack5 } : options;
|
||||
|
||||
const angularJSON = new AngularJSON();
|
||||
|
||||
if (
|
||||
@ -62,7 +57,8 @@ const generator: Generator<{ projectName: string }> = async (
|
||||
packageManager,
|
||||
npmOptions,
|
||||
{
|
||||
...updatedOptions,
|
||||
...options,
|
||||
builder: CoreBuilder.Webpack5,
|
||||
...(useCompodoc && {
|
||||
frameworkPreviewParts: {
|
||||
prefix: compoDocPreviewPrefix,
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { CoreBuilder } from '../../project_types';
|
||||
import { baseGenerator } from '../baseGenerator';
|
||||
import type { Generator } from '../types';
|
||||
|
||||
const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
await baseGenerator(packageManager, npmOptions, options, 'html');
|
||||
await baseGenerator(packageManager, npmOptions, options, 'html', {
|
||||
useSWC: ({ builder }) => builder === CoreBuilder.Webpack5,
|
||||
});
|
||||
};
|
||||
|
||||
export default generator;
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { CoreBuilder } from '../../project_types';
|
||||
import { baseGenerator } from '../baseGenerator';
|
||||
import type { Generator } from '../types';
|
||||
|
||||
const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
await baseGenerator(packageManager, npmOptions, options, 'preact');
|
||||
await baseGenerator(packageManager, npmOptions, options, 'preact', {
|
||||
useSWC: ({ builder }) => builder === CoreBuilder.Webpack5,
|
||||
});
|
||||
};
|
||||
|
||||
export default generator;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { detectLanguage } from '../../detect';
|
||||
import { SupportedLanguage } from '../../project_types';
|
||||
import { CoreBuilder, SupportedLanguage } from '../../project_types';
|
||||
import { baseGenerator } from '../baseGenerator';
|
||||
import type { Generator } from '../types';
|
||||
|
||||
@ -10,6 +10,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
|
||||
await baseGenerator(packageManager, npmOptions, options, 'react', {
|
||||
extraPackages,
|
||||
useSWC: ({ builder }) => builder === CoreBuilder.Webpack5,
|
||||
extraAddons: ['@storybook/addon-onboarding'],
|
||||
});
|
||||
};
|
||||
|
@ -59,6 +59,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
{ ...options, builder: CoreBuilder.Webpack5 },
|
||||
'react',
|
||||
{
|
||||
useSWC: () => true,
|
||||
extraAddons,
|
||||
extraPackages,
|
||||
staticDir: fs.existsSync(path.resolve('./public')) ? 'public' : undefined,
|
||||
|
@ -9,6 +9,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
{ ...options, builder: CoreBuilder.Webpack5 },
|
||||
'server',
|
||||
{
|
||||
useSWC: () => true,
|
||||
extensions: ['json', 'yaml', 'yml'],
|
||||
}
|
||||
);
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { CoreBuilder } from '../../project_types';
|
||||
import { baseGenerator } from '../baseGenerator';
|
||||
import type { Generator } from '../types';
|
||||
|
||||
const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
await baseGenerator(packageManager, npmOptions, options, 'vue');
|
||||
await baseGenerator(packageManager, npmOptions, options, 'vue', {
|
||||
useSWC: ({ builder }) => builder === CoreBuilder.Webpack5,
|
||||
});
|
||||
};
|
||||
|
||||
export default generator;
|
||||
|
@ -7,6 +7,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
extraPackages: async ({ builder }) => {
|
||||
return builder === CoreBuilder.Webpack5 ? ['vue-loader@^15.7.0'] : [];
|
||||
},
|
||||
useSWC: ({ builder }) => builder === CoreBuilder.Webpack5,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
? ['vue-loader@^17.0.0', '@vue/compiler-sfc@^3.2.0']
|
||||
: [];
|
||||
},
|
||||
useSWC: ({ builder }) => builder === CoreBuilder.Webpack5,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { CoreBuilder } from '../../project_types';
|
||||
import { baseGenerator } from '../baseGenerator';
|
||||
import type { Generator } from '../types';
|
||||
|
||||
const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
return baseGenerator(packageManager, npmOptions, options, 'web-components', {
|
||||
extraPackages: ['lit'],
|
||||
useSWC: ({ builder }) => builder === CoreBuilder.Webpack5,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { CoreBuilder } from '../../project_types';
|
||||
import { baseGenerator } from '../baseGenerator';
|
||||
import type { Generator } from '../types';
|
||||
|
||||
const generator: Generator = async (packageManager, npmOptions, options) => {
|
||||
await baseGenerator(packageManager, npmOptions, options, 'react', {
|
||||
extraAddons: ['@storybook/addon-onboarding'],
|
||||
useSWC: ({ builder }) => builder === CoreBuilder.Webpack5,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,7 @@ const defaultOptions: FrameworkOptions = {
|
||||
addMainFile: true,
|
||||
addComponents: true,
|
||||
skipBabel: false,
|
||||
useSWC: () => false,
|
||||
extraMain: undefined,
|
||||
framework: undefined,
|
||||
extensions: undefined,
|
||||
@ -194,23 +195,6 @@ export async function baseGenerator(
|
||||
builder = await detectBuilder(packageManager, projectType);
|
||||
}
|
||||
|
||||
const {
|
||||
extraAddons: extraAddonPackages,
|
||||
extraPackages,
|
||||
staticDir,
|
||||
addScripts,
|
||||
addMainFile,
|
||||
addComponents,
|
||||
skipBabel,
|
||||
extraMain,
|
||||
extensions,
|
||||
storybookConfigFolder,
|
||||
componentsDestinationPath,
|
||||
} = {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
};
|
||||
|
||||
const {
|
||||
packages: frameworkPackages,
|
||||
type,
|
||||
@ -226,6 +210,34 @@ export async function baseGenerator(
|
||||
shouldApplyRequireWrapperOnPackageNames
|
||||
);
|
||||
|
||||
const {
|
||||
extraAddons: extraAddonPackages,
|
||||
extraPackages,
|
||||
staticDir,
|
||||
addScripts,
|
||||
addMainFile,
|
||||
addComponents,
|
||||
extraMain,
|
||||
extensions,
|
||||
storybookConfigFolder,
|
||||
componentsDestinationPath,
|
||||
useSWC,
|
||||
} = {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
};
|
||||
|
||||
let { skipBabel } = {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
};
|
||||
|
||||
const swc = useSWC({ builder });
|
||||
|
||||
if (swc) {
|
||||
skipBabel = true;
|
||||
}
|
||||
|
||||
const extraAddonsToInstall =
|
||||
typeof extraAddonPackages === 'function'
|
||||
? await extraAddonPackages({
|
||||
@ -401,7 +413,18 @@ export async function baseGenerator(
|
||||
: [];
|
||||
|
||||
await configureMain({
|
||||
framework: { name: frameworkInclude, options: options.framework || {} },
|
||||
framework: {
|
||||
name: frameworkInclude,
|
||||
options: swc
|
||||
? {
|
||||
...(options.framework ?? {}),
|
||||
builder: {
|
||||
...(options.framework?.builder ?? {}),
|
||||
useSWC: true,
|
||||
},
|
||||
}
|
||||
: options.framework || {},
|
||||
},
|
||||
prefixes,
|
||||
storybookConfigFolder,
|
||||
docs: { autodocs: 'tag' },
|
||||
|
@ -24,6 +24,7 @@ export interface FrameworkOptions {
|
||||
addMainFile?: boolean;
|
||||
addComponents?: boolean;
|
||||
skipBabel?: boolean;
|
||||
useSWC?: ({ builder }: { builder: Builder }) => boolean;
|
||||
extraMain?: any;
|
||||
extensions?: string[];
|
||||
framework?: Record<string, any>;
|
||||
|
@ -57,7 +57,7 @@ const installStorybook = async <Project extends ProjectType>(
|
||||
linkable: !!options.linkable,
|
||||
pnp: pnp || options.usePnp,
|
||||
yes: options.yes,
|
||||
projectType: options.type,
|
||||
projectType,
|
||||
};
|
||||
|
||||
const runGenerator: () => Promise<any> = async () => {
|
||||
|
@ -68,7 +68,7 @@
|
||||
"recast": "^0.23.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jscodeshift": "^0.11.6",
|
||||
"@types/jscodeshift": "^0.11.10",
|
||||
"ansi-regex": "^5.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-specific-snapshot": "^8.0.0",
|
||||
|
@ -368,3 +368,20 @@ export class GoogleFontsLoadingError extends StorybookError {
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export class NextjsSWCNotSupportedError extends StorybookError {
|
||||
readonly category = Category.FRAMEWORK_NEXTJS;
|
||||
|
||||
readonly code = 3;
|
||||
|
||||
public readonly documentation =
|
||||
'https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.md#manual-migration';
|
||||
|
||||
template() {
|
||||
return dedent`
|
||||
You have activated the SWC mode for Next.js, but you are not using Next.js 14.0.0 or higher.
|
||||
SWC is only supported in Next.js 14.0.0 and higher. Please go to your .storybook/main.<js|ts> file
|
||||
and remove the { framework: { options: { builder: { useSWC: true } } } } option or upgrade to Next.js v14 or later.
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,7 @@
|
||||
"ts-dedent": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"slash": "^5.1.0",
|
||||
"typescript": "~4.9.3",
|
||||
"webpack": "5"
|
||||
},
|
||||
|
@ -4,3 +4,4 @@ export * from './check-webpack-version';
|
||||
export * from './merge-webpack-config';
|
||||
export * from './to-importFn';
|
||||
export * from './to-require-context';
|
||||
export * from './virtual-module-mapping';
|
||||
|
@ -22,6 +22,12 @@ export interface WebpackConfiguration {
|
||||
devtool?: false | string;
|
||||
}
|
||||
|
||||
export type BuilderOptions = {
|
||||
fsCache?: boolean;
|
||||
useSWC?: boolean;
|
||||
lazyCompilation?: boolean;
|
||||
};
|
||||
|
||||
export type StorybookConfig<TWebpackConfiguration = WebpackConfiguration> = StorybookConfigBase & {
|
||||
/**
|
||||
* Modify or return a custom Webpack config after the Storybook's default configuration
|
||||
|
111
code/lib/core-webpack/src/virtual-module-mapping.ts
Normal file
111
code/lib/core-webpack/src/virtual-module-mapping.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import type { Options, PreviewAnnotation } from '@storybook/types';
|
||||
import { isAbsolute, join, resolve } from 'path';
|
||||
import {
|
||||
getBuilderOptions,
|
||||
getRendererName,
|
||||
handlebars,
|
||||
interpolate,
|
||||
loadPreviewOrConfigFile,
|
||||
normalizeStories,
|
||||
readTemplate,
|
||||
} from '@storybook/core-common';
|
||||
import slash from 'slash';
|
||||
import type { BuilderOptions } from './types';
|
||||
import { toImportFn } from './to-importFn';
|
||||
import { toRequireContextString } from './to-require-context';
|
||||
|
||||
export const getVirtualModuleMapping = async (options: Options) => {
|
||||
const virtualModuleMapping: Record<string, string> = {};
|
||||
const builderOptions = await getBuilderOptions<BuilderOptions>(options);
|
||||
const workingDir = process.cwd();
|
||||
const isProd = options.configType === 'PRODUCTION';
|
||||
const nonNormalizedStories = await options.presets.apply('stories', []);
|
||||
|
||||
const stories = normalizeStories(nonNormalizedStories, {
|
||||
configDir: options.configDir,
|
||||
workingDir,
|
||||
});
|
||||
|
||||
const previewAnnotations = [
|
||||
...(await options.presets.apply<PreviewAnnotation[]>('previewAnnotations', [], options)).map(
|
||||
(entry) => {
|
||||
// If entry is an object, use the absolute import specifier.
|
||||
// This is to maintain back-compat with community addons that bundle other addons
|
||||
// and package managers that "hide" sub dependencies (e.g. pnpm / yarn pnp)
|
||||
// The vite builder uses the bare import specifier.
|
||||
if (typeof entry === 'object') {
|
||||
return entry.absolute;
|
||||
}
|
||||
|
||||
// TODO: Remove as soon as we drop support for disabled StoryStoreV7
|
||||
if (isAbsolute(entry)) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
return slash(entry);
|
||||
}
|
||||
),
|
||||
loadPreviewOrConfigFile(options),
|
||||
].filter(Boolean);
|
||||
|
||||
if (options.features?.storyStoreV7) {
|
||||
const storiesFilename = 'storybook-stories.js';
|
||||
const storiesPath = resolve(join(workingDir, storiesFilename));
|
||||
|
||||
const needPipelinedImport = !!builderOptions.lazyCompilation && !isProd;
|
||||
virtualModuleMapping[storiesPath] = toImportFn(stories, { needPipelinedImport });
|
||||
const configEntryPath = resolve(join(workingDir, 'storybook-config-entry.js'));
|
||||
virtualModuleMapping[configEntryPath] = handlebars(
|
||||
await readTemplate(
|
||||
require.resolve(
|
||||
'@storybook/builder-webpack5/templates/virtualModuleModernEntry.js.handlebars'
|
||||
)
|
||||
),
|
||||
{
|
||||
storiesFilename,
|
||||
previewAnnotations,
|
||||
}
|
||||
// We need to double escape `\` for webpack. We may have some in windows paths
|
||||
).replace(/\\/g, '\\\\');
|
||||
} else {
|
||||
const rendererName = await getRendererName(options);
|
||||
|
||||
const rendererInitEntry = resolve(join(workingDir, 'storybook-init-renderer-entry.js'));
|
||||
virtualModuleMapping[rendererInitEntry] = `import '${slash(rendererName)}';`;
|
||||
|
||||
const entryTemplate = await readTemplate(
|
||||
join(__dirname, '..', 'templates', 'virtualModuleEntry.template.js')
|
||||
);
|
||||
|
||||
previewAnnotations.forEach((previewAnnotationFilename: string | undefined) => {
|
||||
if (!previewAnnotationFilename) return;
|
||||
|
||||
// Ensure that relative paths end up mapped to a filename in the cwd, so a later import
|
||||
// of the `previewAnnotationFilename` in the template works.
|
||||
const entryFilename = previewAnnotationFilename.startsWith('.')
|
||||
? `${previewAnnotationFilename.replace(/(\w)(\/|\\)/g, '$1-')}-generated-config-entry.js`
|
||||
: `${previewAnnotationFilename}-generated-config-entry.js`;
|
||||
// NOTE: although this file is also from the `dist/cjs` directory, it is actually a ESM
|
||||
// file, see https://github.com/storybookjs/storybook/pull/16727#issuecomment-986485173
|
||||
virtualModuleMapping[entryFilename] = interpolate(entryTemplate, {
|
||||
previewAnnotationFilename,
|
||||
});
|
||||
});
|
||||
if (stories.length > 0) {
|
||||
const storyTemplate = await readTemplate(
|
||||
join(__dirname, '..', 'templates', 'virtualModuleStory.template.js')
|
||||
);
|
||||
// NOTE: this file has a `.cjs` extension as it is a CJS file (from `dist/cjs`) and runs
|
||||
// in the user's webpack mode, which may be strict about the use of require/import.
|
||||
// See https://github.com/storybookjs/storybook/issues/14877
|
||||
const storiesFilename = resolve(join(workingDir, `generated-stories-entry.cjs`));
|
||||
virtualModuleMapping[storiesFilename] = interpolate(storyTemplate, {
|
||||
rendererName,
|
||||
})
|
||||
// Make sure we also replace quotes for this one
|
||||
.replace("'{{stories}}'", stories.map(toRequireContextString).join(','));
|
||||
}
|
||||
}
|
||||
|
||||
return virtualModuleMapping;
|
||||
};
|
107
code/yarn.lock
107
code/yarn.lock
@ -4031,72 +4031,72 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/env@npm:14.0.0"
|
||||
checksum: c43e81dbd162a29a4b380342e416209d69d731e8ced7688d09668ec8196f543e358ed65adad81a26e943c63a293d7a018552f8389b6b1ac95cd0f63f4ef257c0
|
||||
"@next/env@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/env@npm:14.0.2"
|
||||
checksum: 9fad703ce13b7b7fecf898d3c239f8976f2ec7f3c7c461c06da70898a0221775c48e1a2e2c76740216c4093c2db9bd7adaacd196586cd4283e09eb89de4c1db6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-arm64@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-darwin-arm64@npm:14.0.0"
|
||||
"@next/swc-darwin-arm64@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-darwin-arm64@npm:14.0.2"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-x64@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-darwin-x64@npm:14.0.0"
|
||||
"@next/swc-darwin-x64@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-darwin-x64@npm:14.0.2"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-gnu@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:14.0.0"
|
||||
"@next/swc-linux-arm64-gnu@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:14.0.2"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-musl@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:14.0.0"
|
||||
"@next/swc-linux-arm64-musl@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:14.0.2"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-gnu@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:14.0.0"
|
||||
"@next/swc-linux-x64-gnu@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:14.0.2"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-musl@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-linux-x64-musl@npm:14.0.0"
|
||||
"@next/swc-linux-x64-musl@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-linux-x64-musl@npm:14.0.2"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-arm64-msvc@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:14.0.0"
|
||||
"@next/swc-win32-arm64-msvc@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:14.0.2"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-ia32-msvc@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-win32-ia32-msvc@npm:14.0.0"
|
||||
"@next/swc-win32-ia32-msvc@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-win32-ia32-msvc@npm:14.0.2"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-x64-msvc@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:14.0.0"
|
||||
"@next/swc-win32-x64-msvc@npm:14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:14.0.2"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -6311,7 +6311,7 @@ __metadata:
|
||||
"@storybook/node-logger": "workspace:*"
|
||||
"@storybook/types": "workspace:*"
|
||||
"@types/cross-spawn": "npm:^6.0.2"
|
||||
"@types/jscodeshift": "npm:^0.11.6"
|
||||
"@types/jscodeshift": "npm:^0.11.10"
|
||||
ansi-regex: "npm:^5.0.1"
|
||||
cross-spawn: "npm:^7.0.3"
|
||||
globby: "npm:^11.0.2"
|
||||
@ -6490,6 +6490,7 @@ __metadata:
|
||||
"@storybook/node-logger": "workspace:*"
|
||||
"@storybook/types": "workspace:*"
|
||||
"@types/node": "npm:^18.0.0"
|
||||
slash: "npm:^5.1.0"
|
||||
ts-dedent: "npm:^2.0.0"
|
||||
typescript: "npm:~4.9.3"
|
||||
webpack: "npm:5"
|
||||
@ -6853,10 +6854,12 @@ __metadata:
|
||||
"@babel/preset-typescript": "npm:^7.23.2"
|
||||
"@babel/runtime": "npm:^7.23.2"
|
||||
"@babel/types": "npm:^7.23.0"
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "npm:^0.5.11"
|
||||
"@storybook/addon-actions": "workspace:*"
|
||||
"@storybook/builder-webpack5": "workspace:*"
|
||||
"@storybook/core-common": "workspace:*"
|
||||
"@storybook/core-events": "workspace:*"
|
||||
"@storybook/core-webpack": "workspace:*"
|
||||
"@storybook/node-logger": "workspace:*"
|
||||
"@storybook/preset-react-webpack": "workspace:*"
|
||||
"@storybook/preview-api": "workspace:*"
|
||||
@ -6871,7 +6874,7 @@ __metadata:
|
||||
fs-extra: "npm:^11.1.0"
|
||||
image-size: "npm:^1.0.0"
|
||||
loader-utils: "npm:^3.2.1"
|
||||
next: "npm:^14.0.0"
|
||||
next: "npm:^14.0.2"
|
||||
node-polyfill-webpack-plugin: "npm:^2.0.1"
|
||||
pnp-webpack-plugin: "npm:^1.7.0"
|
||||
postcss: "npm:^8.4.21"
|
||||
@ -8936,13 +8939,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/jscodeshift@npm:^0.11.6":
|
||||
version: 0.11.7
|
||||
resolution: "@types/jscodeshift@npm:0.11.7"
|
||||
"@types/jscodeshift@npm:^0.11.10":
|
||||
version: 0.11.10
|
||||
resolution: "@types/jscodeshift@npm:0.11.10"
|
||||
dependencies:
|
||||
ast-types: "npm:^0.14.1"
|
||||
recast: "npm:^0.20.3"
|
||||
checksum: a2c26f8e64950296bae6176c52e832e1f5c5eb3672adad3c1cdc63e23b8bd3de47890ac8eaae7eb0788feea7628ce540513ff5189379f79e882ddcfa1c855cfc
|
||||
checksum: 1d477ea1addd62a5949f028ef16bac3226341d65052e4f51d61e51789c6c7aa17e953dac34eb6d1e5a2b761fc4c7920df875e20e85cdf4122fc08836e7da547a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -22737,20 +22740,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:^14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "next@npm:14.0.0"
|
||||
"next@npm:^14.0.2":
|
||||
version: 14.0.2
|
||||
resolution: "next@npm:14.0.2"
|
||||
dependencies:
|
||||
"@next/env": "npm:14.0.0"
|
||||
"@next/swc-darwin-arm64": "npm:14.0.0"
|
||||
"@next/swc-darwin-x64": "npm:14.0.0"
|
||||
"@next/swc-linux-arm64-gnu": "npm:14.0.0"
|
||||
"@next/swc-linux-arm64-musl": "npm:14.0.0"
|
||||
"@next/swc-linux-x64-gnu": "npm:14.0.0"
|
||||
"@next/swc-linux-x64-musl": "npm:14.0.0"
|
||||
"@next/swc-win32-arm64-msvc": "npm:14.0.0"
|
||||
"@next/swc-win32-ia32-msvc": "npm:14.0.0"
|
||||
"@next/swc-win32-x64-msvc": "npm:14.0.0"
|
||||
"@next/env": "npm:14.0.2"
|
||||
"@next/swc-darwin-arm64": "npm:14.0.2"
|
||||
"@next/swc-darwin-x64": "npm:14.0.2"
|
||||
"@next/swc-linux-arm64-gnu": "npm:14.0.2"
|
||||
"@next/swc-linux-arm64-musl": "npm:14.0.2"
|
||||
"@next/swc-linux-x64-gnu": "npm:14.0.2"
|
||||
"@next/swc-linux-x64-musl": "npm:14.0.2"
|
||||
"@next/swc-win32-arm64-msvc": "npm:14.0.2"
|
||||
"@next/swc-win32-ia32-msvc": "npm:14.0.2"
|
||||
"@next/swc-win32-x64-msvc": "npm:14.0.2"
|
||||
"@swc/helpers": "npm:0.5.2"
|
||||
busboy: "npm:1.6.0"
|
||||
caniuse-lite: "npm:^1.0.30001406"
|
||||
@ -22788,7 +22791,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
next: dist/bin/next
|
||||
checksum: cfb18a72d6e1d875efb1bb3806f9a06551f482c5cb87231e77e179a71d26f3d43700290988ad27e739302bfa7ff8ac8081aafd5456c39a2819fdd315617e5acf
|
||||
checksum: 65ae7a09f1643bc3deafdbdae9ce0c02326346c4a60a7c739f8f6b154b2226b8fcc5efb984cdcb4ef100116910d4c1013089135800d30c7a50cf98c9d22e5a26
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -27467,7 +27470,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"slash@npm:^5.0.0":
|
||||
"slash@npm:^5.0.0, slash@npm:^5.1.0":
|
||||
version: 5.1.0
|
||||
resolution: "slash@npm:5.1.0"
|
||||
checksum: eb48b815caf0bdc390d0519d41b9e0556a14380f6799c72ba35caf03544d501d18befdeeef074bc9c052acf69654bc9e0d79d7f1de0866284137a40805299eb3
|
||||
|
Loading…
x
Reference in New Issue
Block a user