storybook [Bug]:在生产模式下,动态导入触发无限预览重新加载

ecbunoof  于 4个月前  发布在  其他
关注(0)|答案(1)|浏览(95)

描述bug

你好,Storybook社区!
我们在公司使用Storybook服务器将Symfony应用程序中的Twig组件显示在Storybook中。
自从v7版本以来,组件中的动态导入似乎破坏了Storybook预览。仅在生产模式下,预览会无限次重新加载。以下视频捕捉到了无限次预览重新加载的情况。
Screen.Recording.2024-07-03.at.16.27.40.mov
在开发模式下,JavaScript上下文设置为iframe(组件预览)的DevTools(控制台选项卡)显示以下错误。动态导入没有执行。

组件本身在独立模式下(没有Storybook)的工作正常(即使是动态导入)。
这两个错误是否相关?开发模式下的错误是否会触发生产模式下的无限重新加载?我们如何解决这个错误?
注意:我在其他故事书中测试了一个React应用程序上的动态导入(没有Storybook服务器/Twig/Symfony),动态导入可以正常工作。
与此问题相关的可复现仓库已链接到该问题,并附有关于如何重现此问题中描述的错误的说明。
谢谢!

可复现链接

https://github.com/yoriiis/storybook-server-dynamic-import

可复现步骤

  1. 克隆可复现仓库
  2. 使用 .nvmrc 文件中的Node.js版本
  3. 使用 npm install 安装依赖项

要复现生产模式下的无限预览重新加载

  1. 用命令 npm run build:webpack 启动终端1
  2. 用命令 npm run build:storybook 启动终端2
  3. 用命令 npm run start:server:app 启动终端3
  4. 用命令 npm run start:server:storybook 启动终端4
  5. 打开 http://127.0.0.1:3001 以查看Storybook公共构建
  6. Storybook预览像上面的视频一样无限次重新加载

要在开发模式下复现错误

  1. 用命令 npm run start:webpack 启动终端1
  2. 用命令 npm run start:server:app 启动终端2
  3. 用命令 npm run start:storybook 启动终端3
  4. 打开 http://localhost:6006 以查看处于开发模式的Storybook
  5. Storybook预览在DevTools控制台中显示错误,如下图所示

要在独立模式下测试组件本身

  1. 用命令 npm run start:webpack 启动终端1
  2. 用命令 npm run start:server:app 启动终端2
  3. 打开 http://127.0.0.1:3000/demo 以查看独立模式下的组件本身
  4. 组件预览在使用动态导入时工作正常
qlckcl4x

qlckcl4x1#

要解决动态导入在生产模式下导致无限重新加载的问题,请按照以下步骤操作:

  1. 更新Webpack配置:
    修改Webpack配置以正确处理动态导入。在文件/code/builders/builder-webpack5/src/preview/iframe-webpack.config.ts中,确保optimization部分包含对动态导入的适当处理。
optimization: {
  splitChunks: {
    chunks: 'all',
  },
  runtimeChunk: true,
  sideEffects: true,
  usedExports: options.build?.test?.disableTreeShaking ? false : isProd,
  moduleIds: 'named',
  minimize: true,
  minimizer: [
    new TerserWebpackPlugin({
      parallel: true,
      terserOptions: {
        sourceMap: !options.build?.test?.disableSourcemaps,
        mangle: false,
        keep_fnames: true,
      },
    }),
  ],
},
  1. Babel插件用于动态导入:
    确保正确配置了处理动态导入的Babel插件。在文件/code/frameworks/nextjs/src/babel/plugins/react-loadable-plugin.ts中,验证插件是否正确处理动态导入。
if (loader.isCallExpression()) {
  const arrowFunction = t.arrowFunctionExpression([], loader.node);
  loader.replaceWith(arrowFunction);
}
  1. ESM导入的错误处理:
    确保优雅地处理与ESM导入相关的错误。在文件/code/core/src/server-errors.ts中,验证MainFileESMOnlyImportError类是否提供了明确的指导来解决ESM导入问题。
export class MainFileESMOnlyImportError extends StorybookError {
  readonly category = Category.CORE_SERVER;
  readonly code = 5;
  public documentation = 'https://github.com/storybookjs/storybook/issues/23972#issuecomment-1948534058';
  constructor(public data: { location: string; line: string | undefined; num: number | undefined }) {
    super();
  }
  template() {
    const message = [
      `Storybook failed to load ${this.data.location}`,
      '',
      `It looks like the file tried to load/import an ESM only module.`,
      `Support for this is currently limited in ${this.data.location}`,
      `You can import ESM modules in your main file, but only as dynamic import.`,
      '',
    ];
    if (this.data.line) {
      message.push(
        chalk.white(
          `In your ${chalk.yellow(this.data.location)} file, line ${chalk.bold.cyan(this.data.num)} threw an error:`
        ),
        chalk.grey(this.data.line)
      );
    }
    message.push(
      '',
      chalk.white(
        `Convert the static import to a dynamic import ${chalk.underline('where they are used')}.`
      ),
      chalk.white(`Example:`) + ' ' + chalk.gray(`await import(<your ESM only module>);`),
      ''
    );
    return message.join('\n');
  }
}

这些步骤应该有助于解决生产模式下由动态导入引起的无限重新加载问题。

参考资料

/code/core/src/server-errors.ts
/code/frameworks/nextjs/src/babel/plugins/react-loadable-plugin.ts
/code/builders/builder-webpack5/src/preview/iframe-webpack.config.ts
/code/builders/builder-webpack5/templates
/code/presets/server-webpack/src/index.ts

关于Greptile

此响应为您提供研究的起点,而非精确解决方案。
帮助我们改进!如果这有帮助,请留下一个👍,如果无关紧要,请留下一个👎。

相关问题