diff --git a/packages/builder/builder-rspack-provider/src/index.ts b/packages/builder/builder-rspack-provider/src/index.ts index 4a787cdca49e..785e5eabe2e4 100644 --- a/packages/builder/builder-rspack-provider/src/index.ts +++ b/packages/builder/builder-rspack-provider/src/index.ts @@ -15,4 +15,6 @@ export type { // Rspack Rspack, + Compiler as RspackCompiler, + MultiCompiler as RspackMultiCompiler, } from './types'; diff --git a/packages/builder/builder-webpack-provider/src/types/thirdParty/index.ts b/packages/builder/builder-webpack-provider/src/types/thirdParty/index.ts index 8de997bc260c..e592820d065e 100644 --- a/packages/builder/builder-webpack-provider/src/types/thirdParty/index.ts +++ b/packages/builder/builder-webpack-provider/src/types/thirdParty/index.ts @@ -1,6 +1,10 @@ import type WebpackChain from '@modern-js/utils/webpack-chain'; import type webpack from 'webpack'; -import type { Configuration as WebpackConfig } from 'webpack'; +import type { + Configuration as WebpackConfig, + Compiler as WebpackCompiler, + Compiler as WebpackMultiCompiler, +} from 'webpack'; import type CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; import type { Options as RawTSLoaderOptions } from 'ts-loader'; @@ -19,7 +23,13 @@ export type { BabelConfigUtils } from '@modern-js/babel-preset-app'; export type TSLoaderOptions = Partial; -export type { webpack, WebpackChain, WebpackConfig }; +export type { + webpack, + WebpackChain, + WebpackConfig, + WebpackCompiler, + WebpackMultiCompiler, +}; export type { CSSExtractOptions, diff --git a/packages/cli/core/src/createCli.ts b/packages/cli/core/src/createCli.ts index c0b807a6ba62..afdb67d26319 100644 --- a/packages/cli/core/src/createCli.ts +++ b/packages/cli/core/src/createCli.ts @@ -193,5 +193,6 @@ export const createCli = () => { test, runCommand, getPrevInitOptions: () => initOptions, + getRunner: () => hooksRunner, }; }; diff --git a/packages/cli/core/src/index.ts b/packages/cli/core/src/index.ts index 82ef6fab1399..04f5306597c9 100644 --- a/packages/cli/core/src/index.ts +++ b/packages/cli/core/src/index.ts @@ -1,8 +1,11 @@ import { createCli } from './createCli'; export * from './types'; +export * from './config'; +export * from './loadEnv'; +export * from './loadPlugins'; export * from '@modern-js/plugin'; -export { mergeConfig, initAppDir } from './utils'; +export { mergeConfig, initAppDir, checkIsDuplicationPlugin } from './utils'; export { manager, createPlugin, registerHook } from './manager'; export { AppContext, diff --git a/packages/solutions/app-tools/src/builder/builder-webpack/index.ts b/packages/solutions/app-tools/src/builder/builder-webpack/index.ts index 038aebc5abd5..ff7287d42099 100644 --- a/packages/solutions/app-tools/src/builder/builder-webpack/index.ts +++ b/packages/solutions/app-tools/src/builder/builder-webpack/index.ts @@ -23,6 +23,5 @@ export async function createWebpackBuilderForModern( } builder.addPlugins([builderPluginAdapterModern(options)]); - return builder; } diff --git a/packages/storybook/builder/.eslintrc.js b/packages/storybook/builder/.eslintrc.js new file mode 100644 index 000000000000..c9f48501e25a --- /dev/null +++ b/packages/storybook/builder/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + extends: ['@modern-js'], + ignorePatterns: ['compiled/', 'fixtures/**', 'tests/**', 'vitest.config.ts'], + parserOptions: { + project: require.resolve('./tsconfig.json'), + }, +}; diff --git a/packages/storybook/builder/package.json b/packages/storybook/builder/package.json new file mode 100644 index 000000000000..63948deb9575 --- /dev/null +++ b/packages/storybook/builder/package.json @@ -0,0 +1,59 @@ +{ + "name": "@modern-js/storybook-builder", + "version": "2.31.2", + "description": "modern.js support for storybook", + "repository": { + "type": "git", + "url": "https://github.com/web-infra-dev/modern.js", + "directory": "packages/storybook/builder" + }, + "jsnext:source": "./src/index.ts", + "main": "./dist/index.js", + "types": "./src/index.ts", + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "test": "vitest run" + }, + "exports": { + ".": { + "jsnext:source": "./src/index.ts", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + }, + "./preset": { + "default": "./dist/preset.js", + "jsnext:source": "./src/preset.ts", + "types": "./dist/preset.d.ts" + }, + "./package.json": "./package.json" + }, + "engines": { + "node": ">=16.0.0" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "@modern-js/builder": "workspace:*", + "@modern-js/builder-rspack-provider": "workspace:*", + "@modern-js/builder-shared": "workspace:*", + "@modern-js/builder-webpack-provider": "workspace:*", + "@modern-js/core": "workspace:*", + "@modern-js/utils": "workspace:*", + "@types/webpack-hot-middleware": "^2.25.6", + "glob-promise": "^6.0.3", + "@storybook/core-common": "7.3.2", + "webpack-dev-middleware": "6.0.1", + "webpack-hot-middleware": "^2.25.4" + }, + "devDependencies": { + "@storybook/types": "^7.3.2" + }, + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public", + "provenance": true, + "types": "./dist/index.d.ts" + } +} diff --git a/packages/storybook/builder/src/build.ts b/packages/storybook/builder/src/build.ts new file mode 100644 index 000000000000..3f3103880e8b --- /dev/null +++ b/packages/storybook/builder/src/build.ts @@ -0,0 +1,110 @@ +import { dirname, join, parse } from 'path'; +import webpackDevMiddleware from 'webpack-dev-middleware'; +import webpackHotMiddleware from 'webpack-hot-middleware'; + +import type { Builder as RawStorybookBuilder, Stats } from '@storybook/types'; +import { fs } from '@modern-js/utils'; +import { createCompiler } from './provider'; +import type { BuilderOptions } from './types'; + +export type StorybookBuilder = RawStorybookBuilder; + +export const getConfig: StorybookBuilder['getConfig'] = async options => { + const { presets } = options; + + const frameworkOptions = await presets.apply('frameworkOptions'); + + return presets.apply( + 'modern', + {}, + { + ...options, + frameworkOptions, + }, + ) as any; +}; + +// export `build` is used by storybook core +export const build: StorybookBuilder['build'] = async ({ options }) => { + const config = await getConfig(options); + + const compiler = await createCompiler( + config.bundler || 'webpack', + config.builderConfig, + ); + + const previewResolvedDir = dirname( + require.resolve('@storybook/preview/package.json'), + ); + const previewDirOrigin = join(previewResolvedDir, 'dist'); + const previewDirTarget = join(options.outputDir || '', `sb-preview`); + + const previewFiles = fs.copy(previewDirOrigin, previewDirTarget, { + filter: src => { + const { ext } = parse(src); + if (ext) { + return ext === '.js'; + } + return true; + }, + }); + + const compilation: Promise = new Promise((resolve, reject) => { + compiler.run((err, stats) => { + if (err) { + reject(err); + } else { + resolve(stats as Stats); + } + }); + }); + + const [stats] = await Promise.all([compilation, previewFiles]); + + return stats; +}; + +// export `start` is used by storybook core +export const start: StorybookBuilder['start'] = async ({ + options, + router, + startTime, +}) => { + const { bundler, builderConfig } = await getConfig(options); + + const compiler = await createCompiler(bundler || 'webpack', builderConfig); + + const middleware = webpackDevMiddleware(compiler, { + writeToDisk: + // @ts-expect-error + builderConfig.tools?.devServer?.devMiddleware?.writeToDisk || true, + }); + router.use(middleware); + router.use(webpackHotMiddleware(compiler, { log: false })); + + const stats: Stats = await new Promise(resolve => { + // @ts-expect-error + middleware.waitUntilValid(resolve); + }); + + if (!stats) { + throw new Error('build failed'); + } + + const statsJson = stats.toJson(); + + if (statsJson.errors.length > 1) { + throw stats; + } + + return { + bail, + stats, + totalTime: process.hrtime(startTime), + }; +}; + +export const bail = async () => { + // TODO + console.log('todo'); +}; diff --git a/packages/storybook/builder/src/core.ts b/packages/storybook/builder/src/core.ts new file mode 100644 index 000000000000..65ddfcedff3a --- /dev/null +++ b/packages/storybook/builder/src/core.ts @@ -0,0 +1,198 @@ +import path, { join, resolve } from 'path'; +import { createBuilder } from '@modern-js/builder'; +import { createLoadedConfig } from '@modern-js/core'; +import { builderWebpackProvider } from '@modern-js/builder-webpack-provider'; +import { lodash, slash, fs } from '@modern-js/utils'; +import { SharedBuilderConfig, logger } from '@modern-js/builder-shared'; +import { builderRspackProvider } from '@modern-js/builder-rspack-provider'; +import type { + Options, + PreviewAnnotation, + StoriesEntry, +} from '@storybook/types'; +import { + normalizeStories, + handlebars, + readTemplate, + loadPreviewOrConfigFile, +} from '@storybook/core-common'; +import { promise as glob } from 'glob-promise'; +import { + AllBuilderConfig, + FrameworkOptions, + RspackBuilderConfig, + WebpackBuilderConfig, +} from './types'; + +const VIRTUAL_MODULE_BASE = '.MODERN_STORYBOOK'; +const STORIES_ENTRY = 'STORIES_ENTRY'; +const STORIES_FILENAME = 'storybook-stories.js'; +const STORYBOOK_CONFIG_ENTRY = 'storybook-config-entry.js'; + +export const getCompiler = async ( + cwd: string, + stories: StoriesEntry[], + frameworkConfig: FrameworkOptions, + options: Options, + configPath?: string, +) => { + const bundler = frameworkConfig.bundler || 'webpack'; + + const { config: loadedConfig } = await createLoadedConfig(cwd, configPath); + + const userConfig = lodash.merge( + {}, + loadedConfig, + frameworkConfig.builderConfig, + ) as SharedBuilderConfig; + + const builder = await createBuilder(getProvider(bundler, userConfig), { + cwd, + target: 'web', + }); + + builder.createCompiler(); +}; + +function getProvider( + bundler: 'webpack' | 'rspack', + builderConfig: AllBuilderConfig, +) { + if (bundler === 'webpack') { + return builderWebpackProvider({ + builderConfig: builderConfig as WebpackBuilderConfig, + }); + } else { + return builderRspackProvider({ + builderConfig: builderConfig as RspackBuilderConfig, + }); + } +} + +async function createStorybookModules(cwd: string, options: Options) { + const virtualModuleMappings: Record = {}; + + const { presets } = options; + const storiesEntry = await createStoriesEntry(cwd, options); + virtualModuleMappings[STORIES_ENTRY] = storiesEntry; + + const configEntryPath = resolve(join(cwd, STORYBOOK_CONFIG_ENTRY)); + const previewAnnotations = [ + ...( + await presets.apply( + '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; + } + return path.resolve(cwd, slash(entry)); + }), + loadPreviewOrConfigFile(options), + ].filter(Boolean); + virtualModuleMappings[configEntryPath] = handlebars( + await readTemplate( + require.resolve( + '@modern-js/storybook-builder/templates/virtualModuleModernEntry.js.handlebars', + ), + ), + { + storiesFilename: STORIES_FILENAME, + previewAnnotations, + }, + ); + + return virtualModule(cwd, virtualModuleMappings); +} + +async function createStoriesEntry(cwd: string, options: Options) { + const matchers: StoriesEntry[] = await options.presets.apply( + 'stories', + [], + options, + ); + + const stories = ( + await Promise.all( + normalizeStories(matchers, { + configDir: options.configDir, + workingDir: options.configDir, + }).map(({ directory, files }) => { + const pattern = path.join(directory, files); + const absolutePattern = path.isAbsolute(pattern) + ? pattern + : path.join(options.configDir, pattern); + + return glob(slash(absolutePattern), { follow: true }); + }), + ) + ).reduce((carry, stories) => carry.concat(stories), []); + + return await toImportFn(cwd, stories); +} + +async function toImportFn(cwd: string, stories: string[]) { + const objectEntries = stories.map(file => { + const ext = path.extname(file); + const relativePath = path.relative(cwd, file); + if (!['.js', '.jsx', '.ts', '.tsx', '.mdx'].includes(ext)) { + logger.warn( + `Cannot process ${ext} file with storyStoreV7: ${relativePath}`, + ); + } + + return ` '${toImportPath(relativePath)}': async () => import('${file}')`; + }); + + return ` + const importers = { + ${objectEntries.join(',\n')} + }; + + export async function importFn(path) { + return importers[path](); + } + `; +} + +function toImportPath(relativePath: string) { + return relativePath.startsWith('../') ? relativePath : `./${relativePath}`; +} + +// use this instead of virtualModuleWebpackPlugin for rspack compatibility +async function virtualModule( + cwd: string, + virtualModuleMap: Record, +): Promise<{ + alias: Record; + writeModule: (p: string, content: string) => void; +}> { + const tempDir = path.join(cwd, 'node_modules', VIRTUAL_MODULE_BASE); + fs.ensureDirSync(tempDir); + const alias: Record = {}; + + await Promise.all( + Reflect.ownKeys(virtualModuleMap).map(k => { + const virtualPath = k as string; + const relativePath = path.relative(cwd, virtualPath); + const realPath = path.join(tempDir, relativePath); + alias[virtualPath] = realPath; + return fs.writeFile(realPath, virtualModuleMap[virtualPath]); + }), + ); + + return { + writeModule(virtualPath: string, content: string) { + const relativePath = path.relative(cwd, virtualPath); + const realPath = path.join(tempDir, relativePath); + fs.writeFileSync(realPath, content); + }, + alias, + }; +} diff --git a/packages/storybook/builder/src/index.ts b/packages/storybook/builder/src/index.ts new file mode 100644 index 000000000000..035dcc42cafb --- /dev/null +++ b/packages/storybook/builder/src/index.ts @@ -0,0 +1 @@ +export { start, build, bail } from './build'; diff --git a/packages/storybook/builder/src/presets.ts b/packages/storybook/builder/src/presets.ts new file mode 100644 index 000000000000..b14a9911e394 --- /dev/null +++ b/packages/storybook/builder/src/presets.ts @@ -0,0 +1,5 @@ +import { Options } from '@storybook/types'; + +export async function modern(options: Options) { + +} diff --git a/packages/storybook/builder/src/provider.ts b/packages/storybook/builder/src/provider.ts new file mode 100644 index 000000000000..949b2a8b1058 --- /dev/null +++ b/packages/storybook/builder/src/provider.ts @@ -0,0 +1,38 @@ +import { createBuilder } from '@modern-js/builder'; +import { + builderRspackProvider, + type BuilderConfig as RspackBuilderConfig, +} from '@modern-js/builder-rspack-provider'; +import { + builderWebpackProvider, + type BuilderConfig as WebpackBuilderConfig, +} from '@modern-js/builder-webpack-provider'; +import type { ProviderInstance } from '@modern-js/builder-shared'; +import { BundlerType } from './types'; + +type ReturnPromiseType any> = T extends ( + ...args: any +) => Promise + ? R + : any; + +type Compiler = ReturnPromiseType; + +export async function createCompiler( + bundler: BundlerType, + builderConfig: WebpackBuilderConfig | RspackBuilderConfig, +): Promise { + const builder = await createBuilder( + bundler === 'webpack' + ? builderWebpackProvider({ + builderConfig: builderConfig as WebpackBuilderConfig, + }) + : builderRspackProvider({ + builderConfig: builderConfig as RspackBuilderConfig, + }), + {}, + ); + + const compiler = await builder.createCompiler(); + return compiler; +} diff --git a/packages/storybook/builder/src/types.ts b/packages/storybook/builder/src/types.ts new file mode 100644 index 000000000000..7738d5af0fa7 --- /dev/null +++ b/packages/storybook/builder/src/types.ts @@ -0,0 +1,13 @@ +import type { BuilderConfig as WebpackBuilderConfig } from '@modern-js/builder-webpack-provider'; +import type { BuilderConfig as RspackBuilderConfig } from '@modern-js/builder-rspack-provider'; + +export type BundlerType = 'webpack' | 'rspack'; + +export type { WebpackBuilderConfig, RspackBuilderConfig }; + +export type AllBuilderConfig = WebpackBuilderConfig | RspackBuilderConfig; + +export type FrameworkOptions = { + bundler: BundlerType; + builderConfig: AllBuilderConfig; +}; diff --git a/packages/storybook/builder/templates/preview.ejs b/packages/storybook/builder/templates/preview.ejs new file mode 100644 index 000000000000..1010170cd5ea --- /dev/null +++ b/packages/storybook/builder/templates/preview.ejs @@ -0,0 +1,57 @@ + + + + + + Storybook + + <% if (htmlWebpackPlugin.files.favicon) { %> + + <% } %> + + + + + + + + + + <% if (typeof headHtmlSnippet !== 'undefined') { %> <%= headHtmlSnippet %> <% } %> <% + htmlWebpackPlugin.files.css.forEach(file => { %> + + <% }); %> + + + + + + <% if (typeof bodyHtmlSnippet !== 'undefined') { %> <%= bodyHtmlSnippet %> <% } %> + +
+
+ + <% if (typeof globals !== 'undefined' && Object.keys(globals).length) { %> + + <% } %> + + + + \ No newline at end of file diff --git a/packages/storybook/builder/templates/virtualModuleEntry.template.js b/packages/storybook/builder/templates/virtualModuleEntry.template.js new file mode 100644 index 000000000000..072cbbfc78ec --- /dev/null +++ b/packages/storybook/builder/templates/virtualModuleEntry.template.js @@ -0,0 +1,64 @@ +import { + addDecorator, + addParameters, + addLoader, + addArgs, + addArgTypes, + addStepRunner, + addArgsEnhancer, + addArgTypesEnhancer, + setGlobalRender, +} from '@storybook/preview-api'; +import * as previewAnnotations from '{{previewAnnotationFilename}}'; + +const config = previewAnnotations.default ?? previewAnnotations; + +Object.keys(config).forEach(key => { + const value = config[key]; + switch (key) { + case 'args': { + return addArgs(value); + } + case 'argTypes': { + return addArgTypes(value); + } + case 'decorators': { + return value.forEach(decorator => addDecorator(decorator, false)); + } + case 'loaders': { + return value.forEach(loader => addLoader(loader, false)); + } + case 'parameters': { + return addParameters({ ...value }, false); + } + case 'argTypesEnhancers': { + return value.forEach(enhancer => addArgTypesEnhancer(enhancer)); + } + case 'argsEnhancers': { + return value.forEach(enhancer => addArgsEnhancer(enhancer)); + } + case 'render': { + return setGlobalRender(value); + } + case 'globals': + case 'globalTypes': { + const v = {}; + v[key] = value; + return addParameters(v, false); + } + case '__namedExportsOrder': + case 'decorateStory': + case 'renderToDOM': // deprecated + case 'renderToCanvas': { + return null; // This key is not handled directly in v6 mode. + } + case 'runStep': { + return addStepRunner(value); + } + default: { + return console.log( + `Unknown key '${key}' exported by preview annotation file '{{previewAnnotationFilename}}'`, + ); + } + } +}); diff --git a/packages/storybook/builder/templates/virtualModuleModernEntry.js.handlebars b/packages/storybook/builder/templates/virtualModuleModernEntry.js.handlebars new file mode 100644 index 000000000000..d7e578e55cc7 --- /dev/null +++ b/packages/storybook/builder/templates/virtualModuleModernEntry.js.handlebars @@ -0,0 +1,42 @@ +import { global } from '@storybook/global'; + +import { ClientApi, PreviewWeb, addons, composeConfigs } from '@storybook/preview-api'; +import { createChannel as createPostMessageChannel } from '@storybook/channel-postmessage'; +import { createChannel as createWebSocketChannel } from '@storybook/channel-websocket'; + +import { importFn } from './{{storiesFilename}}'; + +const { SERVER_CHANNEL_URL } = global; + +const getProjectAnnotations = () => + composeConfigs([{{#each previewAnnotations}}require('{{this}}'),{{/each}}]); + +const channel = createPostMessageChannel({ page: 'preview' }); +addons.setChannel(channel); + +if (SERVER_CHANNEL_URL) { + const serverChannel = createWebSocketChannel({ url: SERVER_CHANNEL_URL, }); + addons.setServerChannel(serverChannel); + window.__STORYBOOK_SERVER_CHANNEL__ = serverChannel; +} + +const preview = new PreviewWeb(); + +window.__STORYBOOK_PREVIEW__ = preview; +window.__STORYBOOK_STORY_STORE__ = preview.storyStore; +window.__STORYBOOK_ADDONS_CHANNEL__ = channel; +window.__STORYBOOK_CLIENT_API__ = new ClientApi({ storyStore: preview.storyStore }); + +preview.initialize({ importFn, getProjectAnnotations }); + +if (import.meta.hot) { + import.meta.hot.accept('./{{storiesFilename}}', () => { + // importFn has changed so we need to patch the new one in + preview.onStoriesChanged({ importFn }); + }); + + import.meta.hot.accept([{{#each previewAnnotations}}'{{this}}',{{/each}}], () => { + // getProjectAnnotations has changed so we need to patch the new one in + preview.onGetProjectAnnotationsChanged({ getProjectAnnotations }); + }); +} diff --git a/packages/storybook/builder/templates/virtualModuleStory.template.js b/packages/storybook/builder/templates/virtualModuleStory.template.js new file mode 100644 index 000000000000..f7a668cab55f --- /dev/null +++ b/packages/storybook/builder/templates/virtualModuleStory.template.js @@ -0,0 +1,3 @@ +const { configure } = require('{{rendererName}}'); + +configure(['{{stories}}'], module, false); diff --git a/packages/storybook/builder/tsconfig.json b/packages/storybook/builder/tsconfig.json new file mode 100644 index 000000000000..bae394a0c2f0 --- /dev/null +++ b/packages/storybook/builder/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@modern-js/tsconfig/base", + "compilerOptions": { + "target": "ES2019", + "declaration": true, + "outDir": "dist", + "isolatedModules": true, + "noImplicitAny": true, + "skipLibCheck": true, + "sourceMap": true, + }, + "include": ["./src"], + "exclude": ["./tests/fixtures"] +} diff --git a/packages/storybook/framework/package.json b/packages/storybook/framework/package.json new file mode 100644 index 000000000000..3c85f6fc70ab --- /dev/null +++ b/packages/storybook/framework/package.json @@ -0,0 +1,48 @@ +{ + "name": "@modern-js/storybook", + "version": "2.31.2", + "description": "modern.js support for storybook", + "repository": { + "type": "git", + "url": "https://github.com/web-infra-dev/modern.js", + "directory": "packages/storybook/builder" + }, + "jsnext:source": "./src/index.ts", + "main": "./dist/index.js", + "types": "./src/index.ts", + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "test": "vitest run" + }, + "exports": { + ".": { + "jsnext:source": "./src/index.ts", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + }, + "./preset": { + "default": "./dist/preset.js", + "jsnext:source": "./src/preset.ts", + "types": "./dist/preset.d.ts" + }, + "./package.json": "./package.json" + }, + "engines": { + "node": ">=16.0.0" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "@modern-js/builder-shared": "workspace:*", + "@modern-js/utils": "workspace:*" + }, + "devDependencies": {}, + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public", + "provenance": true, + "types": "./dist/index.d.ts" + } +} diff --git a/packages/storybook/framework/src/index.ts b/packages/storybook/framework/src/index.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/storybook/framework/src/preset.ts b/packages/storybook/framework/src/preset.ts new file mode 100644 index 000000000000..101e99cc2692 --- /dev/null +++ b/packages/storybook/framework/src/preset.ts @@ -0,0 +1,12 @@ +export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { + const framework = await options.presets.apply('framework'); + + return { + ...config, + builder: { + name: wrapForPnP('storybook-builder-rspack') as 'storybook-builder-rspack', + options: typeof framework === 'string' ? {} : framework.options.builder || {}, + }, + renderer: wrapForPnP('@storybook/react'), + }; +}; diff --git a/packages/storybook/framework/tsconfig.json b/packages/storybook/framework/tsconfig.json new file mode 100644 index 000000000000..bae394a0c2f0 --- /dev/null +++ b/packages/storybook/framework/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@modern-js/tsconfig/base", + "compilerOptions": { + "target": "ES2019", + "declaration": true, + "outDir": "dist", + "isolatedModules": true, + "noImplicitAny": true, + "skipLibCheck": true, + "sourceMap": true, + }, + "include": ["./src"], + "exclude": ["./tests/fixtures"] +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 01a0cfe94653..61f1d3f0fbe8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -15,6 +15,7 @@ packages: - 'packages/solutions/*' - 'packages/toolkit/*' - 'packages/toolkit/compiler/*' + - 'packages/storybook/*' - 'scripts/*' - 'tests' - 'tests/integration/**/*'