@modern-js/storybook-builder 0.0.0-next-20230913035856

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/.eslintrc.js +7 -0
  2. package/.turbo/turbo-build.log +6 -0
  3. package/CHANGELOG.md +24 -0
  4. package/LICENSE +21 -0
  5. package/dist/cjs/addons/components/modern.js +65 -0
  6. package/dist/cjs/addons/constants.js +11 -0
  7. package/dist/cjs/addons/index.js +20 -0
  8. package/dist/cjs/addons/preset/preview.js +14 -0
  9. package/dist/cjs/addons/type.js +4 -0
  10. package/dist/cjs/addons/withPluginRuntime.js +20 -0
  11. package/dist/cjs/build.js +109 -0
  12. package/dist/cjs/core.js +40 -0
  13. package/dist/cjs/docgen/actualNameHandler.js +34 -0
  14. package/dist/cjs/docgen/index.js +74 -0
  15. package/dist/cjs/docgen/loader.js +37 -0
  16. package/dist/cjs/docgen/process.js +39 -0
  17. package/dist/cjs/index.js +35 -0
  18. package/dist/cjs/plugin-storybook.js +316 -0
  19. package/dist/cjs/preset.js +61 -0
  20. package/dist/cjs/types.js +11 -0
  21. package/dist/cjs/utils.js +142 -0
  22. package/dist/esm/addons/components/modern.js +44 -0
  23. package/dist/esm/addons/constants.js +1 -0
  24. package/dist/esm/addons/index.js +5 -0
  25. package/dist/esm/addons/preset/preview.js +4 -0
  26. package/dist/esm/addons/type.js +1 -0
  27. package/dist/esm/addons/withPluginRuntime.js +10 -0
  28. package/dist/esm/build.js +83 -0
  29. package/dist/esm/core.js +30 -0
  30. package/dist/esm/docgen/actualNameHandler.js +24 -0
  31. package/dist/esm/docgen/index.js +54 -0
  32. package/dist/esm/docgen/loader.js +26 -0
  33. package/dist/esm/docgen/process.js +28 -0
  34. package/dist/esm/index.js +6 -0
  35. package/dist/esm/plugin-storybook.js +296 -0
  36. package/dist/esm/preset.js +36 -0
  37. package/dist/esm/types.js +1 -0
  38. package/dist/esm/utils.js +95 -0
  39. package/dist/types/addons/components/modern.d.ts +5 -0
  40. package/dist/types/addons/constants.d.ts +1 -0
  41. package/dist/types/addons/index.d.ts +2 -0
  42. package/dist/types/addons/preset/preview.d.ts +1 -0
  43. package/dist/types/addons/type.d.ts +4 -0
  44. package/dist/types/addons/withPluginRuntime.d.ts +2 -0
  45. package/dist/types/build.d.ts +7 -0
  46. package/dist/types/core.d.ts +4 -0
  47. package/dist/types/docgen/actualNameHandler.d.ts +14 -0
  48. package/dist/types/docgen/index.d.ts +9 -0
  49. package/dist/types/docgen/loader.d.ts +2 -0
  50. package/dist/types/docgen/process.d.ts +10 -0
  51. package/dist/types/index.d.ts +3 -0
  52. package/dist/types/plugin-storybook.d.ts +6 -0
  53. package/dist/types/preset.d.ts +6 -0
  54. package/dist/types/types.d.ts +15 -0
  55. package/dist/types/utils.d.ts +12 -0
  56. package/index.js +24 -0
  57. package/modern.config.js +5 -0
  58. package/package.json +96 -0
  59. package/src/addons/components/modern.tsx +52 -0
  60. package/src/addons/constants.ts +1 -0
  61. package/src/addons/index.ts +8 -0
  62. package/src/addons/preset/preview.ts +3 -0
  63. package/src/addons/type.ts +4 -0
  64. package/src/addons/withPluginRuntime.ts +18 -0
  65. package/src/build.ts +119 -0
  66. package/src/core.ts +51 -0
  67. package/src/docgen/actualNameHandler.ts +57 -0
  68. package/src/docgen/index.ts +100 -0
  69. package/src/docgen/loader.ts +34 -0
  70. package/src/docgen/process.ts +44 -0
  71. package/src/index.ts +7 -0
  72. package/src/plugin-storybook.ts +462 -0
  73. package/src/preset.ts +59 -0
  74. package/src/types.ts +21 -0
  75. package/src/utils.ts +131 -0
  76. package/templates/preview.ejs +54 -0
  77. package/templates/virtualModuleModernEntry.js.handlebars +43 -0
  78. package/tsconfig.json +16 -0
@@ -0,0 +1,44 @@
1
+ import { importers, resolver, handlers, parse } from 'react-docgen';
2
+ import type { DocumentationObject } from 'react-docgen/dist/Documentation';
3
+ import actualNameHandler from './actualNameHandler';
4
+
5
+ const defaultHandlers = Object.values(handlers).map(handler => handler);
6
+ const importer = importers.makeFsImporter();
7
+
8
+ export default ({
9
+ source,
10
+ map,
11
+ filename,
12
+ }: {
13
+ source: string;
14
+ map: string;
15
+ filename: string;
16
+ }) => {
17
+ try {
18
+ const results = parse(
19
+ source,
20
+ resolver.findAllExportedComponentDefinitions,
21
+ [...defaultHandlers, actualNameHandler],
22
+ {
23
+ filename,
24
+ importer,
25
+ },
26
+ ) as DocumentationObject[];
27
+
28
+ const docgen = results
29
+ .map(result => {
30
+ // @ts-expect-error we know actualName is added by actualNameHandler, so it exist
31
+ const { actualName, ...docgenInfo } = result;
32
+ if (actualName) {
33
+ return `${actualName}.__docgenInfo=${JSON.stringify(docgenInfo)}`;
34
+ }
35
+ return '';
36
+ })
37
+ .filter(Boolean)
38
+ .join(';');
39
+
40
+ return [docgen, map];
41
+ } catch (e) {
42
+ return null;
43
+ }
44
+ };
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { join } from 'path';
2
+
3
+ export { start, build, bail, getConfig } from './build';
4
+
5
+ export * from './types';
6
+
7
+ export const corePresets = [join(__dirname, './preset.js')];
@@ -0,0 +1,462 @@
1
+ /* eslint-disable max-lines */
2
+ import { isAbsolute, join, resolve } from 'path';
3
+ import { slash, watch, globby } from '@modern-js/utils';
4
+ import {
5
+ BuilderPlugin,
6
+ SharedBuilderConfig,
7
+ mergeBuilderConfig,
8
+ } from '@modern-js/builder-shared';
9
+ import { CompileOptions } from '@storybook/mdx2-csf';
10
+ import type {
11
+ CoreConfig,
12
+ DocsOptions,
13
+ Options,
14
+ PreviewAnnotation,
15
+ StoriesEntry,
16
+ } from '@storybook/types';
17
+ import {
18
+ normalizeStories,
19
+ stringifyProcessEnvs,
20
+ handlebars,
21
+ readTemplate,
22
+ loadPreviewOrConfigFile,
23
+ } from '@storybook/core-common';
24
+ import { globals } from '@storybook/preview/globals';
25
+
26
+ import type {
27
+ BuilderPluginAPI as WebpackAPI,
28
+ WebpackConfig,
29
+ } from '@modern-js/builder-webpack-provider';
30
+ import type {
31
+ BuilderPluginAPI as RspackAPI,
32
+ RspackConfig,
33
+ } from '@modern-js/builder-rspack-provider';
34
+ import { unplugin as csfPlugin } from '@storybook/csf-plugin';
35
+ import { minimatch } from 'minimatch';
36
+ import { AllBuilderConfig, FrameworkOptions } from './types';
37
+ import { toImportFn, virtualModule, maybeGetAbsolutePath } from './utils';
38
+ import { applyDocgenRspack, applyDocgenWebpack } from './docgen';
39
+
40
+ const STORIES_FILENAME = 'storybook-stories.js';
41
+ const STORYBOOK_CONFIG_ENTRY = 'storybook-config-entry.js';
42
+
43
+ const closeFn: (() => void | Promise<void>)[] = [];
44
+ const onClose = (f: () => void | Promise<void>) => {
45
+ closeFn.push(f);
46
+ };
47
+
48
+ export async function finalize() {
49
+ await Promise.all([closeFn.map(close => close())]);
50
+ }
51
+
52
+ export const pluginStorybook: (
53
+ cwd: string,
54
+ options: Options,
55
+ ) => BuilderPlugin<WebpackAPI | RspackAPI> = (cwd, options) => {
56
+ return {
57
+ name: 'builder-plugin-storybook',
58
+
59
+ remove: ['builder-plugin-inline'],
60
+
61
+ async setup(api) {
62
+ const matchers: StoriesEntry[] = await options.presets.apply(
63
+ 'stories',
64
+ [],
65
+ options,
66
+ );
67
+
68
+ const storyPatterns = normalizeStories(matchers, {
69
+ configDir: options.configDir,
70
+ workingDir: options.configDir,
71
+ }).map(({ directory, files }) => {
72
+ const pattern = join(directory, files);
73
+ const absolutePattern = isAbsolute(pattern)
74
+ ? pattern
75
+ : join(options.configDir, pattern);
76
+
77
+ return absolutePattern;
78
+ });
79
+
80
+ api.modifyBuilderConfig(async builderConfig => {
81
+ // storybook needs a virtual entry,
82
+ // when new stories get created, the
83
+ // entry needs to be recauculated
84
+ await prepareStorybookModules(
85
+ api.context.cachePath,
86
+ cwd,
87
+ options,
88
+ builderConfig,
89
+ storyPatterns,
90
+ );
91
+
92
+ // storybook predefined process.env
93
+ await applyDefines(builderConfig, options);
94
+
95
+ // render storybook entry template
96
+ await applyHTML(builderConfig, options);
97
+
98
+ // storybook dom shim
99
+ await applyReact(builderConfig, options);
100
+
101
+ applyExternals(builderConfig);
102
+ });
103
+
104
+ const modifyConfig = async (config: WebpackConfig | RspackConfig) => {
105
+ config.resolve ??= {};
106
+ config.resolve.conditionNames = [
107
+ 'require',
108
+ 'node',
109
+ ...(config.resolve.conditionNames || []),
110
+ ];
111
+ config.resolve.fullySpecified = false;
112
+ await applyMdxLoader(config, options);
113
+ await applyCsfPlugin(config, options);
114
+ };
115
+
116
+ if ('modifyWebpackConfig' in api) {
117
+ api.modifyWebpackConfig(modifyConfig);
118
+ api.modifyWebpackChain(async chain => {
119
+ await applyDocgenWebpack(chain, options);
120
+ });
121
+ } else if ('modifyRspackConfig' in api) {
122
+ api.modifyRspackConfig(async config => {
123
+ await modifyConfig(config);
124
+ await applyDocgenRspack(config, options);
125
+ });
126
+ }
127
+ },
128
+ };
129
+ };
130
+
131
+ async function applyCsfPlugin(
132
+ config: WebpackConfig | RspackConfig,
133
+ options: Options,
134
+ ) {
135
+ const { presets } = options;
136
+
137
+ const addons = await presets.apply('addons', []);
138
+ const {
139
+ options: { bundler },
140
+ } = await presets.apply<{
141
+ name: string;
142
+ options: FrameworkOptions;
143
+ }>('frameworkOptions');
144
+
145
+ const docsOptions =
146
+ // @ts-expect-error - not sure what type to use here
147
+ addons.find(a => [a, a.name].includes('@storybook/addon-docs'))?.options ??
148
+ {};
149
+
150
+ config.plugins ??= [];
151
+ config.plugins.push(
152
+ bundler === 'rspack'
153
+ ? csfPlugin.rspack(docsOptions)
154
+ : (csfPlugin.webpack(docsOptions) as any),
155
+ );
156
+ }
157
+
158
+ async function prepareStorybookModules(
159
+ tempDir: string,
160
+ cwd: string,
161
+ options: Options,
162
+ builderConfig: SharedBuilderConfig,
163
+ storyPatterns: string[],
164
+ ) {
165
+ const mappings = await createStorybookModules(cwd, options, storyPatterns);
166
+
167
+ const componentsPath = maybeGetAbsolutePath(`@storybook/components`);
168
+ const routerPath = maybeGetAbsolutePath(`@storybook/router`);
169
+ const themingPath = maybeGetAbsolutePath(`@storybook/theming`);
170
+
171
+ const storybookPaths: Record<string, string> = {
172
+ ...(componentsPath
173
+ ? {
174
+ [`@storybook/components`]: componentsPath,
175
+ }
176
+ : {}),
177
+ ...(routerPath ? { [`@storybook/router`]: routerPath } : {}),
178
+ ...(themingPath ? { [`@storybook/theming`]: themingPath } : {}),
179
+ };
180
+
181
+ const [mappingsAlias, write] = await virtualModule(tempDir, cwd, mappings);
182
+
183
+ builderConfig.source ??= {};
184
+ builderConfig.source.alias = {
185
+ ...builderConfig.source.alias,
186
+ ...storybookPaths,
187
+ ...mappingsAlias,
188
+ };
189
+
190
+ const watcher = await watchStories(storyPatterns, cwd, write);
191
+ onClose(async () => {
192
+ await watcher.close();
193
+ });
194
+ }
195
+
196
+ async function applyDefines(builderConfig: AllBuilderConfig, options: Options) {
197
+ const { presets } = options;
198
+ const envs = await presets.apply<Record<string, string>>('env');
199
+
200
+ builderConfig.source ??= {};
201
+ builderConfig.source.define = {
202
+ ...builderConfig.source.define,
203
+ ...stringifyProcessEnvs(envs),
204
+ 'process.env': JSON.stringify(envs),
205
+ NODE_ENV: JSON.stringify(process.env.NODE_ENV),
206
+ };
207
+ }
208
+
209
+ async function applyHTML(builderConfig: AllBuilderConfig, options: Options) {
210
+ const {
211
+ presets,
212
+ packageJson,
213
+ configType,
214
+ features,
215
+ previewUrl,
216
+ serverChannelUrl,
217
+ } = options;
218
+
219
+ const [
220
+ coreOptions,
221
+ frameworkOptions,
222
+ logLevel,
223
+ headHtmlSnippet,
224
+ bodyHtmlSnippet,
225
+ template,
226
+ docsOptions,
227
+ ] = await Promise.all([
228
+ presets.apply<CoreConfig>('core'),
229
+ presets.apply('frameworkOptions'),
230
+ presets.apply('logLevel', undefined),
231
+ presets.apply('previewHead'),
232
+ presets.apply('previewBody'),
233
+ presets.apply<string>('previewMainTemplate'),
234
+ presets.apply<DocsOptions>('docs'),
235
+ ]);
236
+
237
+ builderConfig.tools ??= {};
238
+ builderConfig.tools.htmlPlugin = {
239
+ ...builderConfig.tools.htmlPlugin,
240
+ template,
241
+ filename: 'iframe.html',
242
+ templateParameters: {
243
+ ...(builderConfig.tools.htmlPlugin
244
+ ? // @ts-expect-error
245
+ builderConfig.tools.htmlPlugin.templateParameters || {}
246
+ : {}),
247
+ version: packageJson.version || '',
248
+ globals: {
249
+ CONFIG_TYPE: configType,
250
+ LOGLEVEL: logLevel,
251
+ FRAMEWORK_OPTIONS: frameworkOptions,
252
+ CHANNEL_OPTIONS: coreOptions.channelOptions,
253
+ FEATURES: features,
254
+ PREVIEW_URL: previewUrl,
255
+ DOCS_OPTIONS: docsOptions,
256
+ SERVER_CHANNEL_URL: serverChannelUrl,
257
+ },
258
+ headHtmlSnippet,
259
+ bodyHtmlSnippet,
260
+ },
261
+ inject: false,
262
+ };
263
+ }
264
+
265
+ async function applyMdxLoader(
266
+ config: { module?: { rules?: any[] } },
267
+ options: Options & {
268
+ mdxPluginOptions?: CompileOptions;
269
+ },
270
+ ) {
271
+ const { presets, mdxPluginOptions } = options;
272
+
273
+ const remarkExternalLinks = await import('remark-external-links');
274
+ const remarkSlug = await import('remark-slug');
275
+
276
+ const mdxLoaderOptions = await presets.apply('mdxLoaderOptions', {
277
+ skipCsf: true,
278
+ mdxCompileOptions: {
279
+ providerImportSource: '@storybook/addon-docs/mdx-react-shim',
280
+ ...mdxPluginOptions?.mdxCompileOptions,
281
+ remarkPlugins: [
282
+ remarkSlug,
283
+ remarkExternalLinks,
284
+ ...(mdxPluginOptions?.mdxCompileOptions?.remarkPlugins ?? []),
285
+ ],
286
+ },
287
+ });
288
+ const mdxLoader = options.features?.legacyMdx1
289
+ ? require.resolve('@storybook/mdx1-csf/loader')
290
+ : require.resolve('@storybook/mdx2-csf/loader');
291
+
292
+ config.module ??= {};
293
+ config.module.rules ??= [];
294
+ config.module.rules.push(
295
+ {
296
+ test: /(stories|story)\.mdx$/,
297
+ use: [
298
+ {
299
+ loader: mdxLoader,
300
+ options: {
301
+ ...mdxLoaderOptions,
302
+ skipCsf: false,
303
+ },
304
+ },
305
+ ],
306
+ },
307
+ {
308
+ test: /\.mdx$/,
309
+ exclude: /(stories|story)\.mdx$/,
310
+ use: [
311
+ {
312
+ loader: mdxLoader,
313
+ options: mdxLoaderOptions,
314
+ },
315
+ ],
316
+ },
317
+ );
318
+ }
319
+
320
+ function applyExternals(builderConfig: AllBuilderConfig) {
321
+ const config = mergeBuilderConfig(
322
+ {
323
+ output: {
324
+ externals: builderConfig.output?.externals,
325
+ },
326
+ },
327
+ {
328
+ output: {
329
+ externals: globals,
330
+ },
331
+ },
332
+ );
333
+
334
+ builderConfig.output = config.output;
335
+ }
336
+
337
+ function getStoriesEntryPath(cwd: string) {
338
+ return resolve(join(cwd, STORIES_FILENAME));
339
+ }
340
+
341
+ function getStoriesConfigPath(cwd: string) {
342
+ return resolve(join(cwd, STORYBOOK_CONFIG_ENTRY));
343
+ }
344
+
345
+ async function createStorybookModules(
346
+ cwd: string,
347
+ options: Options,
348
+ storyPatterns: string[],
349
+ ) {
350
+ const virtualModuleMappings: Record<string, string> = {};
351
+
352
+ const { presets } = options;
353
+ const storiesEntry = await createStoriesEntry(cwd, storyPatterns);
354
+ virtualModuleMappings[getStoriesEntryPath(cwd)] = storiesEntry;
355
+
356
+ const configEntryPath = getStoriesConfigPath(cwd);
357
+ const previewAnnotations = [
358
+ ...(
359
+ await presets.apply<PreviewAnnotation[]>(
360
+ 'previewAnnotations',
361
+ [],
362
+ options,
363
+ )
364
+ ).map(entry => {
365
+ // If entry is an object, use the absolute import specifier.
366
+ // This is to maintain back-compat with community addons that bundle other addons
367
+ // and package managers that "hide" sub dependencies (e.g. pnpm / yarn pnp)
368
+ // The vite builder uses the bare import specifier.
369
+ if (typeof entry === 'object') {
370
+ return entry.absolute;
371
+ }
372
+ return resolve(cwd, slash(entry));
373
+ }),
374
+ loadPreviewOrConfigFile(options),
375
+ ].filter(Boolean);
376
+ virtualModuleMappings[configEntryPath] = handlebars(
377
+ await readTemplate(
378
+ require.resolve(
379
+ '@modern-js/storybook-builder/templates/virtualModuleModernEntry.js.handlebars',
380
+ ),
381
+ ),
382
+ {
383
+ storiesFilename: STORIES_FILENAME,
384
+ previewAnnotations,
385
+ },
386
+ ).replace(/\\/g, '\\\\');
387
+
388
+ return virtualModuleMappings;
389
+ }
390
+
391
+ async function createStoriesEntry(cwd: string, storyPatterns: string[]) {
392
+ const stories = (
393
+ await Promise.all(
394
+ storyPatterns.map(pattern => {
395
+ return globby(slash(pattern), { followSymbolicLinks: true });
396
+ }),
397
+ )
398
+ ).reduce((carry, stories) => carry.concat(stories), []);
399
+
400
+ return await toImportFn(cwd, stories);
401
+ }
402
+
403
+ async function applyReact(config: AllBuilderConfig, options: Options) {
404
+ let version = '18.0.0';
405
+ try {
406
+ // @ts-expect-error
407
+ ({ version } = await import('react-dom/package.json'));
408
+ } catch (_) {}
409
+
410
+ const { legacyRootApi } =
411
+ (await options.presets.apply<{ legacyRootApi?: boolean } | null>(
412
+ 'frameworkOptions',
413
+ )) || {};
414
+
415
+ const isReact18 = version.startsWith('18') || version.startsWith('0.0.0');
416
+ const useReact17 = legacyRootApi ?? !isReact18;
417
+ if (!useReact17) {
418
+ config.source ??= {};
419
+ config.source.alias ??= {};
420
+ // @ts-expect-error
421
+ config.source.alias['@storybook/react-dom-shim'] =
422
+ '@storybook/react-dom-shim/dist/react-18';
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Storybook scans all stories in the folder and place them in one module.
428
+ * We need to detect new stories ourself, and regenerate new entry for that
429
+ * story.
430
+ *
431
+ * When `require.context` is usable, we can use that instead.
432
+ */
433
+ async function watchStories(
434
+ patterns: string[],
435
+ cwd: string,
436
+ writeModule: (p: string, content: string) => void,
437
+ ) {
438
+ const watcher = watch(
439
+ cwd,
440
+ async ({ changeType, changedFilePath }) => {
441
+ if (changeType !== 'add' && changeType !== 'unlink') {
442
+ return;
443
+ }
444
+
445
+ if (patterns.some(entry => minimatch(changedFilePath, entry))) {
446
+ // recalculate stories
447
+ const stories = (
448
+ await Promise.all(
449
+ patterns.map(pattern => {
450
+ return globby(slash(pattern), { followSymbolicLinks: true });
451
+ }),
452
+ )
453
+ ).reduce((carry, stories) => carry.concat(stories), []);
454
+
455
+ const newStories = await toImportFn(cwd, stories);
456
+ writeModule(getStoriesEntryPath(cwd), newStories);
457
+ }
458
+ },
459
+ [/node_modules/],
460
+ );
461
+ return watcher;
462
+ }
package/src/preset.ts ADDED
@@ -0,0 +1,59 @@
1
+ import { join, resolve } from 'path';
2
+ import type { Options } from '@storybook/types';
3
+ import { getConfig } from './build';
4
+ import { STORYBOOK_CONFIG_ENTRY } from './utils';
5
+ import { BuilderConfig } from './types';
6
+
7
+ export const previewMainTemplate = () => {
8
+ return require.resolve('@modern-js/storybook-builder/templates/preview.ejs');
9
+ };
10
+
11
+ function getStoriesConfigPath(cwd: string) {
12
+ return resolve(join(cwd, STORYBOOK_CONFIG_ENTRY));
13
+ }
14
+
15
+ export const entries = async (_: unknown, options: Options) => {
16
+ const result: string[] = [];
17
+ const { bundler } = await getConfig(options);
18
+
19
+ if (options.configType === 'DEVELOPMENT') {
20
+ // Suppress informational messages when --quiet is specified. webpack-hot-middleware's quiet
21
+ // parameter would also suppress warnings.
22
+ result.push(
23
+ ...([
24
+ `${require.resolve(
25
+ 'webpack-hot-middleware/client',
26
+ )}?reload=true&quiet=false&noInfo=${options.quiet}`,
27
+
28
+ bundler === 'rspack'
29
+ ? require.resolve('@rspack/dev-client/react-refresh-entry')
30
+ : null,
31
+ ].filter(Boolean) as string[]),
32
+ );
33
+ }
34
+
35
+ result.push(getStoriesConfigPath(process.cwd()));
36
+
37
+ return result;
38
+ };
39
+
40
+ export const modern = (
41
+ builderConfig: BuilderConfig,
42
+ options: Options,
43
+ ): BuilderConfig => {
44
+ // @ts-expect-error
45
+ return {
46
+ ...builderConfig,
47
+
48
+ output: {
49
+ ...builderConfig.output,
50
+ disableInlineRuntimeChunk: true,
51
+ distPath: {
52
+ ...builderConfig.output?.distPath,
53
+ root: options.outputDir,
54
+ },
55
+ },
56
+ };
57
+ };
58
+
59
+ export { decorators } from './addons/preset/preview';
package/src/types.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { BuilderConfig as WebpackBuilderConfig } from '@modern-js/builder-webpack-provider';
2
+ import type { BuilderConfig as RspackBuilderConfig } from '@modern-js/builder-rspack-provider';
3
+ import { BuilderPlugin } from '@modern-js/builder-shared';
4
+
5
+ export type BundlerType = 'webpack' | 'rspack';
6
+
7
+ export type { WebpackBuilderConfig, RspackBuilderConfig };
8
+
9
+ export type AllBuilderConfig = WebpackBuilderConfig | RspackBuilderConfig;
10
+
11
+ export type FrameworkOptions = {
12
+ bundler?: BundlerType;
13
+ builderConfig?: AllBuilderConfig;
14
+ configPath?: string;
15
+ };
16
+
17
+ export type BuilderConfig = AllBuilderConfig & {
18
+ builderPlugins?: BuilderPlugin[];
19
+ };
20
+
21
+ export { defineConfig } from '@modern-js/builder/cli';