storybook-builder-rsbuild 2.0.4 → 2.1.0

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.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as rsbuildReal from '@rsbuild/core';
2
2
  import { RsbuildConfig } from '@rsbuild/core';
3
- import { TypescriptOptions as TypescriptOptions$1, Builder, Options, StorybookConfigRaw, BuilderResult as BuilderResult$1, NormalizedStoriesSpecifier } from 'storybook/internal/types';
3
+ import { TypescriptOptions as TypescriptOptions$1, Builder, Options, StorybookConfigRaw, BuilderResult as BuilderResult$1 } from 'storybook/internal/types';
4
4
  import { PluginTypeCheckerOptions } from '@rsbuild/plugin-type-check';
5
5
 
6
6
  type RsbuildStats = {
@@ -52,12 +52,6 @@ declare const getVirtualModules: (options: Options) => Promise<{
52
52
  virtualModules: Record<string, string>;
53
53
  entries: string[];
54
54
  }>;
55
- declare function toImportFnPart(specifier: NormalizedStoriesSpecifier): string;
56
- declare function toImportFn(stories: NormalizedStoriesSpecifier[], relativeOffset: string, { needPipelinedImport }?: {
57
- needPipelinedImport?: boolean;
58
- }): string;
59
- type ModuleExports = Record<string, any>;
60
- declare function importPipeline(): (importFn: () => Promise<ModuleExports>) => Promise<ModuleExports>;
61
55
 
62
56
  type StatsOrMultiStats = Parameters<rsbuildReal.OnAfterBuildFn>[0]['stats'];
63
57
  type Stats = NonNullable<Exclude<StatsOrMultiStats, {
@@ -75,4 +69,4 @@ declare const build: ({ options }: BuilderStartOptions) => Promise<Stats>;
75
69
  declare const corePresets: string[];
76
70
  declare const previewMainTemplate: () => string;
77
71
 
78
- export { BuilderOptions, BuilderResult, RsbuildBuilder, RsbuildFinal, Stats, StorybookConfigRsbuild, TypescriptOptions, bail, build, corePresets, executor, getConfig, getVirtualModules, importPipeline, previewMainTemplate, printDuration, start, toImportFn, toImportFnPart };
72
+ export { BuilderOptions, BuilderResult, RsbuildBuilder, RsbuildFinal, Stats, StorybookConfigRsbuild, TypescriptOptions, bail, build, corePresets, executor, getConfig, getVirtualModules, previewMainTemplate, printDuration, start };
package/dist/index.js CHANGED
@@ -102,41 +102,6 @@ var require_pretty_hrtime = __commonJS({
102
102
  }
103
103
  });
104
104
 
105
- // ../../node_modules/.pnpm/common-path-prefix@3.0.0/node_modules/common-path-prefix/index.js
106
- var require_common_path_prefix = __commonJS({
107
- "../../node_modules/.pnpm/common-path-prefix@3.0.0/node_modules/common-path-prefix/index.js"(exports, module2) {
108
- "use strict";
109
- var { sep: DEFAULT_SEPARATOR } = require("path");
110
- var determineSeparator = (paths) => {
111
- for (const path6 of paths) {
112
- const match = /(\/|\\)/.exec(path6);
113
- if (match !== null)
114
- return match[0];
115
- }
116
- return DEFAULT_SEPARATOR;
117
- };
118
- module2.exports = function commonPathPrefix2(paths, sep = determineSeparator(paths)) {
119
- const [first = "", ...remaining] = paths;
120
- if (first === "" || remaining.length === 0)
121
- return "";
122
- const parts = first.split(sep);
123
- let endOfPrefix = parts.length;
124
- for (const path6 of remaining) {
125
- const compare = path6.split(sep);
126
- for (let i = 0; i < endOfPrefix; i++) {
127
- if (compare[i] !== parts[i]) {
128
- endOfPrefix = i;
129
- }
130
- }
131
- if (endOfPrefix === 0)
132
- return "";
133
- }
134
- const prefix = parts.slice(0, endOfPrefix).join(sep);
135
- return prefix.endsWith(sep) ? prefix : prefix + sep;
136
- };
137
- }
138
- });
139
-
140
105
  // src/index.ts
141
106
  var src_exports = {};
142
107
  __export(src_exports, {
@@ -146,16 +111,13 @@ __export(src_exports, {
146
111
  executor: () => executor,
147
112
  getConfig: () => getConfig,
148
113
  getVirtualModules: () => getVirtualModules,
149
- importPipeline: () => importPipeline,
150
114
  previewMainTemplate: () => previewMainTemplate,
151
115
  printDuration: () => printDuration,
152
- start: () => start,
153
- toImportFn: () => toImportFn,
154
- toImportFnPart: () => toImportFnPart
116
+ start: () => start
155
117
  });
156
118
  module.exports = __toCommonJS(src_exports);
157
119
  var import_node_net = require("net");
158
- var import_node_path9 = require("path");
120
+ var import_node_path4 = require("path");
159
121
  var rsbuildReal = __toESM(require("@rsbuild/core"));
160
122
  var import_fs_extra = __toESM(require("fs-extra"));
161
123
  var import_pretty_hrtime = __toESM(require_pretty_hrtime());
@@ -164,7 +126,7 @@ var import_common3 = require("storybook/internal/common");
164
126
  var import_server_errors = require("storybook/internal/server-errors");
165
127
 
166
128
  // src/preview/iframe-rsbuild.config.ts
167
- var import_node_path7 = require("path");
129
+ var import_node_path2 = require("path");
168
130
  var import_core = require("@rsbuild/core");
169
131
  var import_plugin_type_check = require("@rsbuild/plugin-type-check");
170
132
  var import_preset = require("@storybook/addon-docs/preset");
@@ -172,188 +134,27 @@ var import_case_sensitive_paths_webpack_plugin = __toESM(require("case-sensitive
172
134
  var import_rsbuild_plugin_html_minifier_terser = require("rsbuild-plugin-html-minifier-terser");
173
135
  var import_common2 = require("storybook/internal/common");
174
136
  var import_globals = require("storybook/internal/preview/globals");
175
- var import_ts_dedent2 = require("ts-dedent");
137
+ var import_ts_dedent = require("ts-dedent");
176
138
 
177
139
  // src/preview/virtual-module-mapping.ts
178
- var import_node_fs4 = __toESM(require("fs"));
179
- var import_node_path5 = __toESM(require("path"));
180
- var import_node_path6 = require("path");
140
+ var import_node_path = require("path");
181
141
  var import_core_webpack = require("@storybook/core-webpack");
182
142
 
183
- // ../../node_modules/.pnpm/find-cache-dir@5.0.0/node_modules/find-cache-dir/index.js
184
- var import_node_process2 = __toESM(require("process"), 1);
185
- var import_node_path4 = __toESM(require("path"), 1);
186
- var import_node_fs3 = __toESM(require("fs"), 1);
187
- var import_common_path_prefix = __toESM(require_common_path_prefix(), 1);
188
-
189
- // ../../node_modules/.pnpm/pkg-dir@7.0.0/node_modules/pkg-dir/index.js
190
- var import_node_path3 = __toESM(require("path"), 1);
191
-
192
- // ../../node_modules/.pnpm/find-up@6.3.0/node_modules/find-up/index.js
193
- var import_node_path2 = __toESM(require("path"), 1);
194
- var import_node_url2 = require("url");
195
-
196
- // ../../node_modules/.pnpm/locate-path@7.2.0/node_modules/locate-path/index.js
197
- var import_node_process = __toESM(require("process"), 1);
198
- var import_node_path = __toESM(require("path"), 1);
199
- var import_node_fs = __toESM(require("fs"), 1);
200
- var import_node_url = require("url");
201
- var typeMappings = {
202
- directory: "isDirectory",
203
- file: "isFile"
204
- };
205
- function checkType(type) {
206
- if (Object.hasOwnProperty.call(typeMappings, type)) {
207
- return;
208
- }
209
- throw new Error(`Invalid type specified: ${type}`);
210
- }
211
- var matchType = (type, stat) => stat[typeMappings[type]]();
212
- var toPath = (urlOrPath) => urlOrPath instanceof URL ? (0, import_node_url.fileURLToPath)(urlOrPath) : urlOrPath;
213
- function locatePathSync(paths, {
214
- cwd: cwd2 = import_node_process.default.cwd(),
215
- type = "file",
216
- allowSymlinks = true
217
- } = {}) {
218
- checkType(type);
219
- cwd2 = toPath(cwd2);
220
- const statFunction = allowSymlinks ? import_node_fs.default.statSync : import_node_fs.default.lstatSync;
221
- for (const path_ of paths) {
222
- try {
223
- const stat = statFunction(import_node_path.default.resolve(cwd2, path_), {
224
- throwIfNoEntry: false
225
- });
226
- if (!stat) {
227
- continue;
228
- }
229
- if (matchType(type, stat)) {
230
- return path_;
231
- }
232
- } catch {
233
- }
234
- }
235
- }
236
-
237
- // ../../node_modules/.pnpm/path-exists@5.0.0/node_modules/path-exists/index.js
238
- var import_node_fs2 = __toESM(require("fs"), 1);
239
-
240
- // ../../node_modules/.pnpm/find-up@6.3.0/node_modules/find-up/index.js
241
- var toPath2 = (urlOrPath) => urlOrPath instanceof URL ? (0, import_node_url2.fileURLToPath)(urlOrPath) : urlOrPath;
242
- var findUpStop = Symbol("findUpStop");
243
- function findUpMultipleSync(name, options = {}) {
244
- let directory = import_node_path2.default.resolve(toPath2(options.cwd) || "");
245
- const { root } = import_node_path2.default.parse(directory);
246
- const stopAt = options.stopAt || root;
247
- const limit = options.limit || Number.POSITIVE_INFINITY;
248
- const paths = [name].flat();
249
- const runMatcher = (locateOptions) => {
250
- if (typeof name !== "function") {
251
- return locatePathSync(paths, locateOptions);
252
- }
253
- const foundPath = name(locateOptions.cwd);
254
- if (typeof foundPath === "string") {
255
- return locatePathSync([foundPath], locateOptions);
256
- }
257
- return foundPath;
258
- };
259
- const matches = [];
260
- while (true) {
261
- const foundPath = runMatcher({ ...options, cwd: directory });
262
- if (foundPath === findUpStop) {
263
- break;
264
- }
265
- if (foundPath) {
266
- matches.push(import_node_path2.default.resolve(directory, foundPath));
267
- }
268
- if (directory === stopAt || matches.length >= limit) {
269
- break;
270
- }
271
- directory = import_node_path2.default.dirname(directory);
272
- }
273
- return matches;
274
- }
275
- function findUpSync(name, options = {}) {
276
- const matches = findUpMultipleSync(name, { ...options, limit: 1 });
277
- return matches[0];
278
- }
279
-
280
- // ../../node_modules/.pnpm/pkg-dir@7.0.0/node_modules/pkg-dir/index.js
281
- function packageDirectorySync({ cwd: cwd2 } = {}) {
282
- const filePath = findUpSync("package.json", { cwd: cwd2 });
283
- return filePath && import_node_path3.default.dirname(filePath);
284
- }
285
-
286
- // ../../node_modules/.pnpm/find-cache-dir@5.0.0/node_modules/find-cache-dir/index.js
287
- var { env, cwd } = import_node_process2.default;
288
- var isWritable = (path6) => {
289
- try {
290
- import_node_fs3.default.accessSync(path6, import_node_fs3.default.constants.W_OK);
291
- return true;
292
- } catch {
293
- return false;
294
- }
295
- };
296
- function useDirectory(directory, options) {
297
- if (options.create) {
298
- import_node_fs3.default.mkdirSync(directory, { recursive: true });
299
- }
300
- return directory;
301
- }
302
- function getNodeModuleDirectory(directory) {
303
- const nodeModules = import_node_path4.default.join(directory, "node_modules");
304
- if (!isWritable(nodeModules) && (import_node_fs3.default.existsSync(nodeModules) || !isWritable(import_node_path4.default.join(directory)))) {
305
- return;
306
- }
307
- return nodeModules;
308
- }
309
- function findCacheDirectory(options = {}) {
310
- if (env.CACHE_DIR && !["true", "false", "1", "0"].includes(env.CACHE_DIR)) {
311
- return useDirectory(import_node_path4.default.join(env.CACHE_DIR, options.name), options);
312
- }
313
- let { cwd: directory = cwd(), files } = options;
314
- if (files) {
315
- if (!Array.isArray(files)) {
316
- throw new TypeError(`Expected \`files\` option to be an array, got \`${typeof files}\`.`);
317
- }
318
- directory = (0, import_common_path_prefix.default)(files.map((file) => import_node_path4.default.resolve(directory, file)));
319
- }
320
- directory = packageDirectorySync({ cwd: directory });
321
- if (!directory) {
322
- return;
323
- }
324
- const nodeModules = getNodeModuleDirectory(directory);
325
- if (!nodeModules) {
326
- return;
327
- }
328
- return useDirectory(import_node_path4.default.join(directory, "node_modules", ".cache", options.name), options);
329
- }
330
-
331
143
  // ../../node_modules/.pnpm/slash@5.1.0/node_modules/slash/index.js
332
- function slash(path6) {
333
- const isExtendedLengthPath = path6.startsWith("\\\\?\\");
144
+ function slash(path) {
145
+ const isExtendedLengthPath = path.startsWith("\\\\?\\");
334
146
  if (isExtendedLengthPath) {
335
- return path6;
147
+ return path;
336
148
  }
337
- return path6.replace(/\\/g, "/");
149
+ return path.replace(/\\/g, "/");
338
150
  }
339
151
 
340
152
  // src/preview/virtual-module-mapping.ts
341
153
  var import_common = require("storybook/internal/common");
342
- var import_ts_dedent = require("ts-dedent");
343
154
  var getVirtualModules = async (options) => {
344
155
  const virtualModules = {};
345
- const cwd2 = process.cwd();
346
- const workingDir = options.cache ? (
347
- // TODO: This is a hard code cache dir, as Rspack doesn't support virtual modules now.
348
- // Remove this when Rspack supports virtual modules.
349
- findCacheDirectory({
350
- name: "storybook-rsbuild-builder",
351
- create: true
352
- })
353
- ) : process.cwd();
354
- if (!import_node_fs4.default.existsSync(workingDir)) {
355
- import_node_fs4.default.mkdirSync(workingDir, { recursive: true });
356
- }
156
+ const builderOptions = await (0, import_common.getBuilderOptions)(options);
157
+ const workingDir = process.cwd();
357
158
  const isProd = options.configType === "PRODUCTION";
358
159
  const nonNormalizedStories = await options.presets.apply("stories", []);
359
160
  const entries = [];
@@ -361,7 +162,6 @@ var getVirtualModules = async (options) => {
361
162
  configDir: options.configDir,
362
163
  workingDir
363
164
  });
364
- const realPathRelativeToCwd = import_node_path5.default.relative(workingDir, cwd2).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep);
365
165
  const previewAnnotations = [
366
166
  ...(await options.presets.apply(
367
167
  "previewAnnotations",
@@ -376,13 +176,12 @@ var getVirtualModules = async (options) => {
376
176
  (0, import_common.loadPreviewOrConfigFile)(options)
377
177
  ].filter(Boolean);
378
178
  const storiesFilename = "storybook-stories.js";
379
- const storiesPath = (0, import_node_path6.resolve)((0, import_node_path6.join)(workingDir, storiesFilename));
380
- const builderOptions = await (0, import_common.getBuilderOptions)(options);
179
+ const storiesPath = (0, import_node_path.resolve)((0, import_node_path.join)(workingDir, storiesFilename));
381
180
  const needPipelinedImport = !!builderOptions.lazyCompilation && !isProd;
382
- virtualModules[storiesPath] = toImportFn(stories, realPathRelativeToCwd, {
181
+ virtualModules[storiesPath] = (0, import_core_webpack.toImportFn)(stories, {
383
182
  needPipelinedImport
384
183
  });
385
- const configEntryPath = (0, import_node_path6.resolve)((0, import_node_path6.join)(workingDir, "storybook-config-entry.js"));
184
+ const configEntryPath = (0, import_node_path.resolve)((0, import_node_path.join)(workingDir, "storybook-config-entry.js"));
386
185
  virtualModules[configEntryPath] = (await (0, import_common.readTemplate)(
387
186
  require.resolve("storybook-builder-rsbuild/templates/virtualModuleModernEntry.js")
388
187
  )).replaceAll(`'{{storiesFilename}}'`, `'./${storiesFilename}'`).replaceAll(
@@ -393,83 +192,14 @@ var getVirtualModules = async (options) => {
393
192
  previewAnnotations.filter(Boolean).map((entry) => `require('${entry}')`).join(",")
394
193
  ).replace(/\\/g, "\\\\");
395
194
  entries.push(configEntryPath);
396
- for (const [key, value] of Object.entries(virtualModules)) {
397
- import_node_fs4.default.writeFileSync(key, value);
398
- }
399
195
  return {
400
196
  virtualModules,
401
197
  entries
402
198
  };
403
199
  };
404
- function toImportFnPart(specifier) {
405
- const { directory, importPathMatcher } = specifier;
406
- return import_ts_dedent.dedent`
407
- async (path) => {
408
- if (!${importPathMatcher}.exec(path)) {
409
- return;
410
- }
411
-
412
- const pathRemainder = path.substring(${directory.length + 1});
413
- return import(
414
- /* webpackChunkName: "[request]" */
415
- /* webpackInclude: ${(0, import_core_webpack.webpackIncludeRegexp)(specifier)} */
416
- '${directory}/' + pathRemainder
417
- );
418
- }
419
-
420
- `;
421
- }
422
- function toImportFn(stories, relativeOffset, { needPipelinedImport } = {}) {
423
- let pipelinedImport = "const pipeline = (x) => x();";
424
- if (needPipelinedImport) {
425
- pipelinedImport = `
426
- const importPipeline = ${importPipeline};
427
- const pipeline = importPipeline();
428
- `;
429
- }
430
- return import_ts_dedent.dedent`
431
- ${pipelinedImport}
432
-
433
- const importers = [
434
- ${stories.map(toImportFnPart).join(",\n")}
435
- ];
436
-
437
- export async function importFn(path) {
438
- const offset = '${relativeOffset}';
439
-
440
- for (let i = 0; i < importers.length; i++) {
441
- const pathWithOffset = buildPath(offset, path)
442
-
443
- const moduleExports = await pipeline(() => importers[i](pathWithOffset));
444
- if (moduleExports) {
445
- return moduleExports;
446
- }
447
- }
448
- }
449
-
450
- function buildPath(offset, path) {
451
- if(path.startsWith('./')) {
452
- return offset + '/' + path.substring(2);
453
- } else {
454
- return offset + '/' + path;
455
- }
456
- }
457
- `;
458
- }
459
- function importPipeline() {
460
- let importGate = Promise.resolve();
461
- return async (importFn) => {
462
- await importGate;
463
- const moduleExportsPromise = importFn();
464
- importGate = importGate.then(async () => {
465
- await moduleExportsPromise;
466
- });
467
- return moduleExportsPromise;
468
- };
469
- }
470
200
 
471
201
  // src/preview/iframe-rsbuild.config.ts
472
- var getAbsolutePath = (input) => (0, import_node_path7.dirname)(require.resolve((0, import_node_path7.join)(input, "package.json")));
202
+ var getAbsolutePath = (input) => (0, import_node_path2.dirname)(require.resolve((0, import_node_path2.join)(input, "package.json")));
473
203
  var maybeGetAbsolutePath = (input) => {
474
204
  try {
475
205
  return getAbsolutePath(input);
@@ -495,7 +225,7 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
495
225
  const { rsbuildConfigPath, addonDocs } = await (0, import_common2.getBuilderOptions)(options);
496
226
  const appliedDocsWebpack = await (0, import_preset.webpack)({}, { ...options, ...addonDocs });
497
227
  const {
498
- outputDir = (0, import_node_path7.join)(".", "public"),
228
+ outputDir = (0, import_node_path2.join)(".", "public"),
499
229
  quiet,
500
230
  packageJson,
501
231
  configType,
@@ -547,7 +277,7 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
547
277
  lazyCompilation: { entries: false }
548
278
  } : {};
549
279
  if (!template) {
550
- throw new Error(import_ts_dedent2.dedent`
280
+ throw new Error(import_ts_dedent.dedent`
551
281
  Storybook's Webpack5 builder requires a template to be specified.
552
282
  Somehow you've ended up with a falsy value for the template option.
553
283
 
@@ -558,7 +288,7 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
558
288
  if (build2?.test?.disableBlocks) {
559
289
  externals["@storybook/blocks"] = "__STORYBOOK_BLOCKS_EMPTY_MODULE__";
560
290
  }
561
- const { virtualModules: _virtualModules, entries: dynamicEntries } = await getVirtualModules(options);
291
+ const { virtualModules: virtualModuleMapping, entries: dynamicEntries } = await getVirtualModules(options);
562
292
  if (!options.cache) {
563
293
  throw new Error("Cache is required");
564
294
  }
@@ -611,7 +341,7 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
611
341
  css: !options.build?.test?.disableSourcemaps
612
342
  },
613
343
  distPath: {
614
- root: (0, import_node_path7.resolve)(process.cwd(), outputDir)
344
+ root: (0, import_node_path2.resolve)(process.cwd(), outputDir)
615
345
  },
616
346
  filename: {
617
347
  js: isProd ? "[name].[contenthash:8].iframe.bundle.js" : "[name].iframe.bundle.js",
@@ -699,7 +429,7 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
699
429
  }
700
430
  ].filter(Boolean),
701
431
  tools: {
702
- rspack: (config, { addRules, appendPlugins, rspack, mergeConfig }) => {
432
+ rspack: (config, { addRules, appendPlugins, rspack: rspack2, mergeConfig }) => {
703
433
  addRules({
704
434
  test: /\.stories\.([tj])sx?$|(stories|story)\.mdx$/,
705
435
  exclude: /node_modules/,
@@ -710,6 +440,10 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
710
440
  }
711
441
  ]
712
442
  });
443
+ config.module ??= {};
444
+ config.module.parser ??= {};
445
+ config.module.parser.javascript ??= {};
446
+ config.module.parser.javascript.unknownContextCritical = false;
713
447
  config.resolve ??= {};
714
448
  config.resolve.symlinks = !(0, import_common2.isPreservingSymlinks)();
715
449
  config.resolve.extensions = Array.from(
@@ -744,9 +478,17 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
744
478
  config.module.parser ??= {};
745
479
  config.module.parser.javascript ??= {};
746
480
  config.module.parser.javascript.exportsPresence = false;
481
+ if (!rspack2.experiments?.VirtualModulesPlugin) {
482
+ throw new Error(
483
+ "rspack.experiments.VirtualModulesPlugin requires at least 1.5.0 version of @rsbuild/core, please upgrade or downgrade storybook-rsbuild-builder to lower version."
484
+ );
485
+ }
747
486
  appendPlugins(
748
487
  [
749
- new rspack.ProvidePlugin({
488
+ Object.keys(virtualModuleMapping).length > 0 ? new rspack2.experiments.VirtualModulesPlugin(
489
+ virtualModuleMapping
490
+ ) : null,
491
+ new rspack2.ProvidePlugin({
750
492
  process: require.resolve("process/browser.js")
751
493
  }),
752
494
  new import_case_sensitive_paths_webpack_plugin.default()
@@ -794,7 +536,7 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
794
536
 
795
537
  // src/react-shims.ts
796
538
  var import_promises = require("fs/promises");
797
- var import_node_path8 = require("path");
539
+ var import_node_path3 = require("path");
798
540
  var getIsReactVersion18or19 = async (options) => {
799
541
  const { legacyRootApi } = await options.presets.apply(
800
542
  "frameworkOptions"
@@ -807,12 +549,12 @@ var getIsReactVersion18or19 = async (options) => {
807
549
  {}
808
550
  );
809
551
  let reactDom = "";
810
- reactDom = resolvedReact.reactDom || (0, import_node_path8.dirname)(require.resolve("react-dom/package.json"));
811
- if (!(0, import_node_path8.isAbsolute)(reactDom)) {
552
+ reactDom = resolvedReact.reactDom || (0, import_node_path3.dirname)(require.resolve("react-dom/package.json"));
553
+ if (!(0, import_node_path3.isAbsolute)(reactDom)) {
812
554
  return false;
813
555
  }
814
556
  const { version } = JSON.parse(
815
- await (0, import_promises.readFile)((0, import_node_path8.join)(reactDom, "package.json"), "utf-8")
557
+ await (0, import_promises.readFile)((0, import_node_path3.join)(reactDom, "package.json"), "utf-8")
816
558
  );
817
559
  return version.startsWith("18") || version.startsWith("19") || version.startsWith("0.0.0");
818
560
  };
@@ -831,7 +573,7 @@ var applyReactShims = async (config, options) => {
831
573
  };
832
574
 
833
575
  // src/index.ts
834
- var corePath = (0, import_node_path9.dirname)(require.resolve("storybook/package.json"));
576
+ var corePath = (0, import_node_path4.dirname)(require.resolve("storybook/package.json"));
835
577
  var printDuration = (startTime) => (0, import_pretty_hrtime.default)(process.hrtime(startTime)).replace(" ms", " milliseconds").replace(" s", " seconds").replace(" m", " minutes");
836
578
  var executor = {
837
579
  get: async (options) => {
@@ -939,7 +681,7 @@ var start = async ({
939
681
  error: new Error("Missing Rsbuild build instance at runtime!")
940
682
  });
941
683
  }
942
- const previewResolvedDir = (0, import_node_path9.join)(corePath, "dist/preview");
684
+ const previewResolvedDir = (0, import_node_path4.join)(corePath, "dist/preview");
943
685
  const previewDirOrigin = previewResolvedDir;
944
686
  router.use(
945
687
  "/sb-preview",
@@ -962,16 +704,16 @@ var build = async ({ options }) => {
962
704
  cwd: process.cwd(),
963
705
  rsbuildConfig: config
964
706
  });
965
- const previewResolvedDir = (0, import_node_path9.join)(corePath, "dist/preview");
707
+ const previewResolvedDir = (0, import_node_path4.join)(corePath, "dist/preview");
966
708
  const previewDirOrigin = previewResolvedDir;
967
- const previewDirTarget = (0, import_node_path9.join)(options.outputDir || "", "sb-preview");
709
+ const previewDirTarget = (0, import_node_path4.join)(options.outputDir || "", "sb-preview");
968
710
  let stats;
969
711
  rsbuildBuild.onAfterBuild((params) => {
970
712
  stats = params.stats;
971
713
  });
972
714
  const previewFiles = import_fs_extra.default.copy(previewDirOrigin, previewDirTarget, {
973
715
  filter: (src) => {
974
- const { ext } = (0, import_node_path9.parse)(src);
716
+ const { ext } = (0, import_node_path4.parse)(src);
975
717
  if (ext) {
976
718
  return ext === ".js";
977
719
  }
@@ -985,7 +727,7 @@ var build = async ({ options }) => {
985
727
  await close();
986
728
  return stats;
987
729
  };
988
- var corePresets = [(0, import_node_path9.join)(__dirname, "./preview-preset.js")];
730
+ var corePresets = [(0, import_node_path4.join)(__dirname, "./preview-preset.js")];
989
731
  var previewMainTemplate = () => require.resolve("storybook-builder-rsbuild/templates/preview.ejs");
990
732
  function getRandomPort(host) {
991
733
  return new Promise((resolve3, reject) => {
@@ -1008,10 +750,7 @@ function getRandomPort(host) {
1008
750
  executor,
1009
751
  getConfig,
1010
752
  getVirtualModules,
1011
- importPipeline,
1012
753
  previewMainTemplate,
1013
754
  printDuration,
1014
- start,
1015
- toImportFn,
1016
- toImportFnPart
755
+ start
1017
756
  });
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import { __commonJS, __require, __toESM } from './chunk-TTFRSOOU.mjs';
1
+ import { __commonJS, __toESM, __require } from './chunk-TTFRSOOU.mjs';
2
2
  import { createServer } from 'net';
3
- import path4, { dirname, join, resolve, parse, isAbsolute } from 'path';
3
+ import { dirname, join, resolve, parse, isAbsolute } from 'path';
4
4
  import * as rsbuildReal from '@rsbuild/core';
5
5
  import { loadConfig, mergeRsbuildConfig } from '@rsbuild/core';
6
- import fs4 from 'fs-extra';
6
+ import fs from 'fs-extra';
7
7
  import sirv from 'sirv';
8
- import { normalizeStories, loadPreviewOrConfigFile, getBuilderOptions, readTemplate, resolveAddonName, getPresets, stringifyProcessEnvs, isPreservingSymlinks } from 'storybook/internal/common';
8
+ import { getBuilderOptions, normalizeStories, loadPreviewOrConfigFile, readTemplate, resolveAddonName, getPresets, stringifyProcessEnvs, isPreservingSymlinks } from 'storybook/internal/common';
9
9
  import { WebpackInvocationError } from 'storybook/internal/server-errors';
10
10
  import { pluginTypeCheck } from '@rsbuild/plugin-type-check';
11
11
  import { webpack } from '@storybook/addon-docs/preset';
@@ -13,10 +13,7 @@ import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';
13
13
  import { pluginHtmlMinifierTerser } from 'rsbuild-plugin-html-minifier-terser';
14
14
  import { globalsNameReferenceMap } from 'storybook/internal/preview/globals';
15
15
  import { dedent } from 'ts-dedent';
16
- import fs2 from 'fs';
17
- import { webpackIncludeRegexp } from '@storybook/core-webpack';
18
- import process2 from 'process';
19
- import { fileURLToPath } from 'url';
16
+ import { toImportFn } from '@storybook/core-webpack';
20
17
  import { readFile } from 'fs/promises';
21
18
 
22
19
  // ../../node_modules/.pnpm/pretty-hrtime@1.0.3/node_modules/pretty-hrtime/index.js
@@ -90,194 +87,21 @@ var require_pretty_hrtime = __commonJS({
90
87
  }
91
88
  });
92
89
 
93
- // ../../node_modules/.pnpm/common-path-prefix@3.0.0/node_modules/common-path-prefix/index.js
94
- var require_common_path_prefix = __commonJS({
95
- "../../node_modules/.pnpm/common-path-prefix@3.0.0/node_modules/common-path-prefix/index.js"(exports, module) {
96
- var { sep: DEFAULT_SEPARATOR } = __require("path");
97
- var determineSeparator = (paths) => {
98
- for (const path6 of paths) {
99
- const match = /(\/|\\)/.exec(path6);
100
- if (match !== null)
101
- return match[0];
102
- }
103
- return DEFAULT_SEPARATOR;
104
- };
105
- module.exports = function commonPathPrefix2(paths, sep = determineSeparator(paths)) {
106
- const [first = "", ...remaining] = paths;
107
- if (first === "" || remaining.length === 0)
108
- return "";
109
- const parts = first.split(sep);
110
- let endOfPrefix = parts.length;
111
- for (const path6 of remaining) {
112
- const compare = path6.split(sep);
113
- for (let i = 0; i < endOfPrefix; i++) {
114
- if (compare[i] !== parts[i]) {
115
- endOfPrefix = i;
116
- }
117
- }
118
- if (endOfPrefix === 0)
119
- return "";
120
- }
121
- const prefix = parts.slice(0, endOfPrefix).join(sep);
122
- return prefix.endsWith(sep) ? prefix : prefix + sep;
123
- };
124
- }
125
- });
126
-
127
90
  // src/index.ts
128
91
  var import_pretty_hrtime = __toESM(require_pretty_hrtime());
129
92
 
130
- // ../../node_modules/.pnpm/find-cache-dir@5.0.0/node_modules/find-cache-dir/index.js
131
- var import_common_path_prefix = __toESM(require_common_path_prefix(), 1);
132
- var typeMappings = {
133
- directory: "isDirectory",
134
- file: "isFile"
135
- };
136
- function checkType(type) {
137
- if (Object.hasOwnProperty.call(typeMappings, type)) {
138
- return;
139
- }
140
- throw new Error(`Invalid type specified: ${type}`);
141
- }
142
- var matchType = (type, stat) => stat[typeMappings[type]]();
143
- var toPath = (urlOrPath) => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
144
- function locatePathSync(paths, {
145
- cwd: cwd2 = process2.cwd(),
146
- type = "file",
147
- allowSymlinks = true
148
- } = {}) {
149
- checkType(type);
150
- cwd2 = toPath(cwd2);
151
- const statFunction = allowSymlinks ? fs2.statSync : fs2.lstatSync;
152
- for (const path_ of paths) {
153
- try {
154
- const stat = statFunction(path4.resolve(cwd2, path_), {
155
- throwIfNoEntry: false
156
- });
157
- if (!stat) {
158
- continue;
159
- }
160
- if (matchType(type, stat)) {
161
- return path_;
162
- }
163
- } catch {
164
- }
165
- }
166
- }
167
-
168
- // ../../node_modules/.pnpm/find-up@6.3.0/node_modules/find-up/index.js
169
- var toPath2 = (urlOrPath) => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
170
- var findUpStop = Symbol("findUpStop");
171
- function findUpMultipleSync(name, options = {}) {
172
- let directory = path4.resolve(toPath2(options.cwd) || "");
173
- const { root } = path4.parse(directory);
174
- const stopAt = options.stopAt || root;
175
- const limit = options.limit || Number.POSITIVE_INFINITY;
176
- const paths = [name].flat();
177
- const runMatcher = (locateOptions) => {
178
- if (typeof name !== "function") {
179
- return locatePathSync(paths, locateOptions);
180
- }
181
- const foundPath = name(locateOptions.cwd);
182
- if (typeof foundPath === "string") {
183
- return locatePathSync([foundPath], locateOptions);
184
- }
185
- return foundPath;
186
- };
187
- const matches = [];
188
- while (true) {
189
- const foundPath = runMatcher({ ...options, cwd: directory });
190
- if (foundPath === findUpStop) {
191
- break;
192
- }
193
- if (foundPath) {
194
- matches.push(path4.resolve(directory, foundPath));
195
- }
196
- if (directory === stopAt || matches.length >= limit) {
197
- break;
198
- }
199
- directory = path4.dirname(directory);
200
- }
201
- return matches;
202
- }
203
- function findUpSync(name, options = {}) {
204
- const matches = findUpMultipleSync(name, { ...options, limit: 1 });
205
- return matches[0];
206
- }
207
-
208
- // ../../node_modules/.pnpm/pkg-dir@7.0.0/node_modules/pkg-dir/index.js
209
- function packageDirectorySync({ cwd: cwd2 } = {}) {
210
- const filePath = findUpSync("package.json", { cwd: cwd2 });
211
- return filePath && path4.dirname(filePath);
212
- }
213
-
214
- // ../../node_modules/.pnpm/find-cache-dir@5.0.0/node_modules/find-cache-dir/index.js
215
- var { env, cwd } = process2;
216
- var isWritable = (path6) => {
217
- try {
218
- fs2.accessSync(path6, fs2.constants.W_OK);
219
- return true;
220
- } catch {
221
- return false;
222
- }
223
- };
224
- function useDirectory(directory, options) {
225
- if (options.create) {
226
- fs2.mkdirSync(directory, { recursive: true });
227
- }
228
- return directory;
229
- }
230
- function getNodeModuleDirectory(directory) {
231
- const nodeModules = path4.join(directory, "node_modules");
232
- if (!isWritable(nodeModules) && (fs2.existsSync(nodeModules) || !isWritable(path4.join(directory)))) {
233
- return;
234
- }
235
- return nodeModules;
236
- }
237
- function findCacheDirectory(options = {}) {
238
- if (env.CACHE_DIR && !["true", "false", "1", "0"].includes(env.CACHE_DIR)) {
239
- return useDirectory(path4.join(env.CACHE_DIR, options.name), options);
240
- }
241
- let { cwd: directory = cwd(), files } = options;
242
- if (files) {
243
- if (!Array.isArray(files)) {
244
- throw new TypeError(`Expected \`files\` option to be an array, got \`${typeof files}\`.`);
245
- }
246
- directory = (0, import_common_path_prefix.default)(files.map((file) => path4.resolve(directory, file)));
247
- }
248
- directory = packageDirectorySync({ cwd: directory });
249
- if (!directory) {
250
- return;
251
- }
252
- const nodeModules = getNodeModuleDirectory(directory);
253
- if (!nodeModules) {
254
- return;
255
- }
256
- return useDirectory(path4.join(directory, "node_modules", ".cache", options.name), options);
257
- }
258
-
259
93
  // ../../node_modules/.pnpm/slash@5.1.0/node_modules/slash/index.js
260
- function slash(path6) {
261
- const isExtendedLengthPath = path6.startsWith("\\\\?\\");
94
+ function slash(path) {
95
+ const isExtendedLengthPath = path.startsWith("\\\\?\\");
262
96
  if (isExtendedLengthPath) {
263
- return path6;
97
+ return path;
264
98
  }
265
- return path6.replace(/\\/g, "/");
99
+ return path.replace(/\\/g, "/");
266
100
  }
267
101
  var getVirtualModules = async (options) => {
268
102
  const virtualModules = {};
269
- const cwd2 = process.cwd();
270
- const workingDir = options.cache ? (
271
- // TODO: This is a hard code cache dir, as Rspack doesn't support virtual modules now.
272
- // Remove this when Rspack supports virtual modules.
273
- findCacheDirectory({
274
- name: "storybook-rsbuild-builder",
275
- create: true
276
- })
277
- ) : process.cwd();
278
- if (!fs2.existsSync(workingDir)) {
279
- fs2.mkdirSync(workingDir, { recursive: true });
280
- }
103
+ const builderOptions = await getBuilderOptions(options);
104
+ const workingDir = process.cwd();
281
105
  const isProd = options.configType === "PRODUCTION";
282
106
  const nonNormalizedStories = await options.presets.apply("stories", []);
283
107
  const entries = [];
@@ -285,7 +109,6 @@ var getVirtualModules = async (options) => {
285
109
  configDir: options.configDir,
286
110
  workingDir
287
111
  });
288
- const realPathRelativeToCwd = path4.relative(workingDir, cwd2).split(path4.sep).join(path4.posix.sep);
289
112
  const previewAnnotations = [
290
113
  ...(await options.presets.apply(
291
114
  "previewAnnotations",
@@ -301,9 +124,8 @@ var getVirtualModules = async (options) => {
301
124
  ].filter(Boolean);
302
125
  const storiesFilename = "storybook-stories.js";
303
126
  const storiesPath = resolve(join(workingDir, storiesFilename));
304
- const builderOptions = await getBuilderOptions(options);
305
127
  const needPipelinedImport = !!builderOptions.lazyCompilation && !isProd;
306
- virtualModules[storiesPath] = toImportFn(stories, realPathRelativeToCwd, {
128
+ virtualModules[storiesPath] = toImportFn(stories, {
307
129
  needPipelinedImport
308
130
  });
309
131
  const configEntryPath = resolve(join(workingDir, "storybook-config-entry.js"));
@@ -319,80 +141,11 @@ var getVirtualModules = async (options) => {
319
141
  previewAnnotations.filter(Boolean).map((entry) => `require('${entry}')`).join(",")
320
142
  ).replace(/\\/g, "\\\\");
321
143
  entries.push(configEntryPath);
322
- for (const [key, value] of Object.entries(virtualModules)) {
323
- fs2.writeFileSync(key, value);
324
- }
325
144
  return {
326
145
  virtualModules,
327
146
  entries
328
147
  };
329
148
  };
330
- function toImportFnPart(specifier) {
331
- const { directory, importPathMatcher } = specifier;
332
- return dedent`
333
- async (path) => {
334
- if (!${importPathMatcher}.exec(path)) {
335
- return;
336
- }
337
-
338
- const pathRemainder = path.substring(${directory.length + 1});
339
- return import(
340
- /* webpackChunkName: "[request]" */
341
- /* webpackInclude: ${webpackIncludeRegexp(specifier)} */
342
- '${directory}/' + pathRemainder
343
- );
344
- }
345
-
346
- `;
347
- }
348
- function toImportFn(stories, relativeOffset, { needPipelinedImport } = {}) {
349
- let pipelinedImport = "const pipeline = (x) => x();";
350
- if (needPipelinedImport) {
351
- pipelinedImport = `
352
- const importPipeline = ${importPipeline};
353
- const pipeline = importPipeline();
354
- `;
355
- }
356
- return dedent`
357
- ${pipelinedImport}
358
-
359
- const importers = [
360
- ${stories.map(toImportFnPart).join(",\n")}
361
- ];
362
-
363
- export async function importFn(path) {
364
- const offset = '${relativeOffset}';
365
-
366
- for (let i = 0; i < importers.length; i++) {
367
- const pathWithOffset = buildPath(offset, path)
368
-
369
- const moduleExports = await pipeline(() => importers[i](pathWithOffset));
370
- if (moduleExports) {
371
- return moduleExports;
372
- }
373
- }
374
- }
375
-
376
- function buildPath(offset, path) {
377
- if(path.startsWith('./')) {
378
- return offset + '/' + path.substring(2);
379
- } else {
380
- return offset + '/' + path;
381
- }
382
- }
383
- `;
384
- }
385
- function importPipeline() {
386
- let importGate = Promise.resolve();
387
- return async (importFn) => {
388
- await importGate;
389
- const moduleExportsPromise = importFn();
390
- importGate = importGate.then(async () => {
391
- await moduleExportsPromise;
392
- });
393
- return moduleExportsPromise;
394
- };
395
- }
396
149
 
397
150
  // src/preview/iframe-rsbuild.config.ts
398
151
  var getAbsolutePath = (input) => dirname(__require.resolve(join(input, "package.json")));
@@ -484,7 +237,7 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
484
237
  if (build2?.test?.disableBlocks) {
485
238
  externals["@storybook/blocks"] = "__STORYBOOK_BLOCKS_EMPTY_MODULE__";
486
239
  }
487
- const { virtualModules: _virtualModules, entries: dynamicEntries } = await getVirtualModules(options);
240
+ const { virtualModules: virtualModuleMapping, entries: dynamicEntries } = await getVirtualModules(options);
488
241
  if (!options.cache) {
489
242
  throw new Error("Cache is required");
490
243
  }
@@ -625,7 +378,7 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
625
378
  }
626
379
  ].filter(Boolean),
627
380
  tools: {
628
- rspack: (config, { addRules, appendPlugins, rspack, mergeConfig }) => {
381
+ rspack: (config, { addRules, appendPlugins, rspack: rspack2, mergeConfig }) => {
629
382
  addRules({
630
383
  test: /\.stories\.([tj])sx?$|(stories|story)\.mdx$/,
631
384
  exclude: /node_modules/,
@@ -638,6 +391,10 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
638
391
  }
639
392
  ]
640
393
  });
394
+ config.module ??= {};
395
+ config.module.parser ??= {};
396
+ config.module.parser.javascript ??= {};
397
+ config.module.parser.javascript.unknownContextCritical = false;
641
398
  config.resolve ??= {};
642
399
  config.resolve.symlinks = !isPreservingSymlinks();
643
400
  config.resolve.extensions = Array.from(
@@ -672,9 +429,17 @@ var iframe_rsbuild_config_default = async (options, extraWebpackConfig) => {
672
429
  config.module.parser ??= {};
673
430
  config.module.parser.javascript ??= {};
674
431
  config.module.parser.javascript.exportsPresence = false;
432
+ if (!rspack2.experiments?.VirtualModulesPlugin) {
433
+ throw new Error(
434
+ "rspack.experiments.VirtualModulesPlugin requires at least 1.5.0 version of @rsbuild/core, please upgrade or downgrade storybook-rsbuild-builder to lower version."
435
+ );
436
+ }
675
437
  appendPlugins(
676
438
  [
677
- new rspack.ProvidePlugin({
439
+ Object.keys(virtualModuleMapping).length > 0 ? new rspack2.experiments.VirtualModulesPlugin(
440
+ virtualModuleMapping
441
+ ) : null,
442
+ new rspack2.ProvidePlugin({
678
443
  process: __require.resolve("process/browser.js")
679
444
  }),
680
445
  new CaseSensitivePathsPlugin()
@@ -893,7 +658,7 @@ var build = async ({ options }) => {
893
658
  rsbuildBuild.onAfterBuild((params) => {
894
659
  stats = params.stats;
895
660
  });
896
- const previewFiles = fs4.copy(previewDirOrigin, previewDirTarget, {
661
+ const previewFiles = fs.copy(previewDirOrigin, previewDirTarget, {
897
662
  filter: (src) => {
898
663
  const { ext } = parse(src);
899
664
  if (ext) {
@@ -925,4 +690,4 @@ function getRandomPort(host) {
925
690
  });
926
691
  }
927
692
 
928
- export { bail, build, corePresets, executor, getConfig, getVirtualModules, importPipeline, previewMainTemplate, printDuration, start, toImportFn, toImportFnPart };
693
+ export { bail, build, corePresets, executor, getConfig, getVirtualModules, previewMainTemplate, printDuration, start };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-builder-rsbuild",
3
- "version": "2.0.4",
3
+ "version": "2.1.0",
4
4
  "description": "Rsbuild builder for Storybook",
5
5
  "keywords": [
6
6
  "storybook",
@@ -57,19 +57,19 @@
57
57
  "!src/**/*"
58
58
  ],
59
59
  "dependencies": {
60
- "@rsbuild/plugin-type-check": "^1.2.3",
61
- "@storybook/addon-docs": "^9.0.18",
62
- "@storybook/core-webpack": "^9.0.18",
60
+ "@rsbuild/plugin-type-check": "^1.2.4",
61
+ "@storybook/addon-docs": "^9.1.2",
62
+ "@storybook/core-webpack": "^9.1.2",
63
63
  "browser-assert": "^1.2.1",
64
64
  "case-sensitive-paths-webpack-plugin": "^2.4.0",
65
65
  "cjs-module-lexer": "^1.4.3",
66
66
  "constants-browserify": "^1.0.0",
67
67
  "es-module-lexer": "^1.7.0",
68
- "fs-extra": "^11.3.0",
68
+ "fs-extra": "^11.3.1",
69
69
  "magic-string": "^0.30.17",
70
70
  "path-browserify": "^1.0.1",
71
71
  "process": "^0.11.10",
72
- "rsbuild-plugin-html-minifier-terser": "^1.1.1",
72
+ "rsbuild-plugin-html-minifier-terser": "^1.1.2",
73
73
  "sirv": "^2.0.4",
74
74
  "ts-dedent": "^2.2.0",
75
75
  "url": "^0.11.4",
@@ -77,7 +77,7 @@
77
77
  "util-deprecate": "^1.0.2"
78
78
  },
79
79
  "devDependencies": {
80
- "@rsbuild/core": "^1.4.11",
80
+ "@rsbuild/core": "^1.5.0",
81
81
  "@types/find-cache-dir": "^5.0.2",
82
82
  "@types/fs-extra": "^11.0.4",
83
83
  "@types/node": "^18.19.110",
@@ -86,10 +86,10 @@
86
86
  "pretty-hrtime": "^1.0.3",
87
87
  "slash": "^5.1.0",
88
88
  "storybook": "9.1.2",
89
- "typescript": "^5.8.3"
89
+ "typescript": "^5.9.2"
90
90
  },
91
91
  "peerDependencies": {
92
- "@rsbuild/core": "^1.0.1",
92
+ "@rsbuild/core": "^1.5.0",
93
93
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta",
94
94
  "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta",
95
95
  "storybook": "^9.0.0"
@@ -1,16 +1,23 @@
1
1
  import { createBrowserChannel } from 'storybook/internal/channels'
2
- import {
3
- PreviewWeb,
4
- addons,
5
- composeConfigs,
6
- } from 'storybook/internal/preview-api'
2
+ import { STORY_HOT_UPDATED } from 'storybook/internal/core-events'
3
+ import { isPreview } from 'storybook/internal/csf'
7
4
 
8
5
  import { global } from '@storybook/global'
9
6
 
7
+ import { PreviewWeb, addons, composeConfigs } from 'storybook/preview-api'
10
8
  import { importFn } from '{{storiesFilename}}'
11
9
 
12
- const getProjectAnnotations = () =>
13
- composeConfigs(['{{previewAnnotations_requires}}'])
10
+ const getProjectAnnotations = () => {
11
+ const previewAnnotations = ['{{previewAnnotations_requires}}']
12
+ // the last one in this array is the user preview
13
+ const userPreview = previewAnnotations[previewAnnotations.length - 1]?.default
14
+
15
+ if (isPreview(userPreview)) {
16
+ return userPreview.composed
17
+ }
18
+
19
+ return composeConfigs(previewAnnotations)
20
+ }
14
21
 
15
22
  const channel = createBrowserChannel({ page: 'preview' })
16
23
  addons.setChannel(channel)
@@ -26,6 +33,12 @@ window.__STORYBOOK_STORY_STORE__ = preview.storyStore
26
33
  window.__STORYBOOK_ADDONS_CHANNEL__ = channel
27
34
 
28
35
  if (import.meta.webpackHot) {
36
+ import.meta.webpackHot.addStatusHandler((status) => {
37
+ if (status === 'idle') {
38
+ preview.channel.emit(STORY_HOT_UPDATED)
39
+ }
40
+ })
41
+
29
42
  import.meta.webpackHot.accept('{{storiesFilename}}', () => {
30
43
  // importFn has changed so we need to patch the new one in
31
44
  preview.onStoriesChanged({ importFn })