[Bug]: Storybook 7, storybook构建失败,入口点必须在Vite根目录内,

ewm0tg9j  于 3个月前  发布在  其他
关注(0)|答案(4)|浏览(55)

描述bug

在工作中,我尝试升级到Storybook 7。尽管我通过补丁修复了storybook-server-channel url固定为localhost的HMR问题,但我仍然无法构建。
我正在使用以下配置的vite应用程序:

import react from '@vitejs/plugin-react';
import browserslistToEsbuild from 'browserslist-to-esbuild';
import * as dotenv from 'dotenv';
import { defineConfig } from 'vite';
import { chunkSplitPlugin } from 'vite-plugin-chunk-split';
import symfonyPlugin from 'vite-plugin-symfony';
import viteRestart from 'vite-plugin-restart';
import fs from 'fs';
import i18nHotReload from './assets/vite-plugins/i18n-hot-reload';

dotenv.config();

export default defineConfig(({ command }) => ({
  plugins: [
    chunkSplitPlugin({
      customChunk: ({ file }) => {
        // Extract each node_modules package into a separate chunk in "js/npm/(user-)package".
        // Regex taken from: https://github.com/npm/validate-npm-package-name/blob/main/lib/index.js#L3
        const match = file.match(/node_modules\/(?:@([^\/]+?)[\/])?([^\/]+)/);
        if (match) {
          const name = match[1] ? `${match[1]}-${match[2]}` : match[2];
          return `npm/${name}`;
        }
        return null;
      },
    }),
    react(),
    symfonyPlugin({
      viteDevServerHostname: 'localhost',
    }),
    viteRestart({
      reload: ['templates/**/*'],
    }),
    i18nHotReload(),
  ],
  base: '/build/',
  build: {
    target: browserslistToEsbuild(),
    outDir: './public/build',
    rollupOptions: {
      input: {
        main: './assets/main.tsx',
      },
      output: {
        assetFileNames: (assetInfo) => {
          // Place asset in each corresponding folder "build/{img,font,etc.}/*".
          const info = assetInfo.name.split('.');
          let extType = info[info.length - 1];
          if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
            extType = 'img';
          } else if (/woff2?|otf|ttf|eot/.test(extType)) {
            extType = 'font';
          }
          return `${extType}/[name].[hash][extname]`;
        },
        chunkFileNames: 'js/[name].[hash].js',
        entryFileNames: 'js/[name].[hash].js',
      },
    },
    manifest: true,
  },
  server: {
    host: '0.0.0.0',
    port: 3000,
    strictPort: true,
    https: {
      // Get certificates if we are not building (CI has no certificates)
      key: command === 'build' ? null : fs.readFileSync('docker/run/certificates/key.pem'),
      cert: command === 'build' ? null : fs.readFileSync('docker/run/certificates/cert.pem'),
    },
    watch: {
      ignored: ['**/.idea/**', '**/tests/**', '**/var/**', '**/vendor/**'],
    },
    origin: `https://${process.env.APP_URL}:3000`,
  },
  // Needed for antd
  css: {
    preprocessorOptions: {
      less: {
        javascriptEnabled: true,
      },
    },
  },
}));

这是我的 .storybook/main.ts

import type { StorybookConfig } from '@storybook/react-vite';
import * as dotenv from 'dotenv';
import {mergeConfig} from 'vite';

dotenv.config({path: '../.env'});

const config: StorybookConfig = {
  stories: [
    '../assets/**/*.mdx',
    '../assets/**/*.stories.@(js|jsx|ts|tsx)',
  ],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
  ],
  framework: '@storybook/react-vite',
  docs: {
    autodocs: 'tag',
  },
  async viteFinal(config, options) {
    if (options.configType === 'PRODUCTION') {
      // TODO: While "rendering chunks", Vite will error out with "Entry points must be inside Vite root directory"
      return mergeConfig(config, {
        base: '/storybook/',
      });
    }
    return mergeConfig(config, {
      server: {
        watch: {
          ignored: ['**/.idea/**', '**/tests/**', '**/var/**', '**/vendor/**'],
        },
      },
    });
  },
};

export default config;

我的所有故事都在 assets/stories/* 中。我将它们从 src/ 移动,那里的init脚本将它们放在那里。
构建的完整输出如下:

www-data@b4a1870105af:/app$ yarn build:storybook
yarn run v1.22.19
$ storybook build --output-dir ./public/storybook
@storybook/cli v7.0.0-rc.10

info => Cleaning outputDir: /public/storybook
info => Loading presets
info => Building manager..
info => Manager built (1.82 s)
info => Copying static files: /app/node_modules/@storybook/manager/static at /app/public/storybook/sb-common-assets
vite v4.2.1 building for production...

./sb-common-assets/fonts.css doesn't exist at build time, it will remain unchanged to be resolved at runtime
transforming (2334) node_modules/rc-virtual-list/es/Item.jsUse of eval in "node_modules/telejson/dist/index.mjs" is strongly discouraged as it poses security risks and may cause issues with minification.
Use of eval in "node_modules/telejson/dist/index.mjs" is strongly discouraged as it poses security risks and may cause issues with minification.
✓ 2341 modules transformed.
Generated an empty chunk: "npm/copy-to-clipboard".
Generated an empty chunk: "npm/html-parse-stringify".
Generated an empty chunk: "npm/json2mq".
Generated an empty chunk: "npm/moment".
Generated an empty chunk: "npm/shallowequal".
Generated an empty chunk: "npm/string-convert".
Generated an empty chunk: "npm/toggle-selection".
Generated an empty chunk: "npm/void-elements".
rendering chunks (181)...Entry points must be inside Vite root directory
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

我还有一个控制台日志,显示传递给 configviteFinal 参数,看起来像这样:

{
  plugins: [
    {
      name: 'storybook:react-docgen-plugin',
      enforce: 'pre',
      transform: [AsyncFunction: transform]
    },
    {
      name: 'vite-plugin-chunk-split',
      config: [Function: config],
      renderChunk: [Function: renderChunk]
    },
    [
      {
        name: 'vite:react-babel',
        enforce: 'pre',
        config: [Function: config],
        configResolved: [Function: configResolved],
        transform: [AsyncFunction: transform]
      },
      {
        name: 'vite:react-refresh',
        enforce: 'pre',
        config: [Function: config],
        resolveId: [Function: resolveId],
        load: [Function: load],
        transformIndexHtml: [Function: transformIndexHtml]
      },
      {
        name: 'vite:react-jsx',
        enforce: 'pre',
        config: [Function: config],
        resolveId: [Function: resolveId],
        load: [Function: load]
      }
    ],
    {
      name: 'symfony',
      enforce: 'post',
      config: [Function: config],
      configResolved: [Function: configResolved],
      configureServer: [Function: configureServer],
      renderChunk: [AsyncFunction: renderChunk],
      generateBundle: [Function: generateBundle]
    },
    {
      name: 'vite-plugin-restart:0',
      apply: 'serve',
      config: [Function: config],
      configResolved: [Function: configResolved],
      configureServer: [Function: configureServer]
    },
    {
      name: 'i18n-hot-reload',
      handleHotUpdate: [Function: handleHotUpdate]
    },
    {
      name: 'storybook:code-generator-plugin',
      enforce: 'pre',
      configureServer: [Function: configureServer],
      config: [Function: config],
      configResolved: [Function: configResolved],
      resolveId: [Function: resolveId],
      load: [AsyncFunction: load],
      transformIndexHtml: [AsyncFunction: transformIndexHtml]
    },
    {
      name: 'unplugin-csf',
      transformInclude: [Function: transformInclude],
      transform: [Function (anonymous)],
      vite: { enforce: 'pre' },
      enforce: 'pre'
    },
    {
      name: 'storybook:mdx-plugin',
      enforce: 'pre',
      transform: [AsyncFunction: transform]
    },
    {
      name: 'storybook:inject-export-order-plugin',
      enforce: 'post',
      transform: [AsyncFunction: transform]
    },
    {
      name: 'storybook:strip-hmr-boundary-plugin',
      enforce: 'post',
      transform: [AsyncFunction: transform]
    },
    {
      name: 'storybook:allow-storybook-dir',
      enforce: 'post',
      config: [Function: config]
    },
    {
      name: 'storybook:external-globals-plugin',
      enforce: 'post',
      config: [AsyncFunction: config],
      transform: [AsyncFunction: transform]
    },
    {
      name: 'vite:react-docgen-typescript',
      transform: [AsyncFunction: transform]
    }
  ],
  base: './',
  server: {
    host: '0.0.0.0',
    port: 3000,
    strictPort: true,
    https: { key: null, cert: null },
    watch: {
      ignored: [ '**/.idea/**', '**/tests/**', '**/var/**', '**/vendor/**' ]
    },
    origin: 'https://<my-custom-url>.test:3000'
  },
  css: { preprocessorOptions: { less: { javascriptEnabled: true } } },
  configFile: false,
  cacheDir: 'node_modules/.cache/.vite-storybook',
  root: '/app',
  resolve: {
    preserveSymlinks: false,
    alias: {
      assert: '/app/node_modules/browser-assert/lib/assert.js',
      '@storybook/react-dom-shim': '@storybook/react-dom-shim/dist/react-18'
    }
  },
  envPrefix: [ 'VITE_', 'STORYBOOK_' ],
  build: {
    outDir: '/app/public/storybook',
    emptyOutDir: false,
    sourcemap: true,
    rollupOptions: { external: [ './sb-preview/runtime.mjs' ] }
  }
}

我不知道是否配置错误或者实际上是否有问题,这就是为什么我来到这里的原因。

重现bug

无法简单地解释,只是运行了 npx sb@next init --builder=vite 并添加了自定义配置

系统信息

Environment Info:

  System:
    OS: Linux 5.10 Debian GNU/Linux 10 (buster) 10 (buster)
    CPU: (2) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  Binaries:
    Node: 18.15.0 - /usr/bin/node
    Yarn: 1.22.19 - /usr/bin/yarn
    npm: 9.5.0 - /usr/bin/npm
  npmPackages:
    @storybook/addon-essentials: ^7.0.0-rc.10 => 7.0.0-rc.10
    @storybook/addon-interactions: ^7.0.0-rc.10 => 7.0.0-rc.10
    @storybook/addon-links: ^7.0.0-rc.10 => 7.0.0-rc.10
    @storybook/blocks: ^7.0.0-rc.10 => 7.0.0-rc.10
    @storybook/react: ^7.0.0-rc.10 => 7.0.0-rc.10
    @storybook/react-vite: ^7.0.0-rc.10 => 7.0.0-rc.10
    @storybook/testing-library: ^0.0.14-next.1 => 0.0.14-next.1

其他上下文

  • 无响应*
exdqitrt

exdqitrt1#

我怀疑这与指定 base: "/storybook/" 有关。

ecr0jaav

ecr0jaav2#

@JorisAerts i commented out that line, and still get the same error. Also i do still need it, since it will be accessible from myurl.com/storybook/index.html.
I can even comment out the entire viteFinal function, and still get the error.
My app (inside container) is at /app and all the storybook output must go in /app/public/storybook whereas /app/public is the public root, which is why i said i need the base set to /storybook

rwqw0loc

rwqw0loc3#

到目前为止,我已经发现问题是由 symfonyPlugin ( Source code ) 引起的。如果我在 viteFinal 中排除它,它就可以正常运行。

import {defineConfig} from 'vite';
import symfonyPlugin from 'vite-plugin-symfony';

export default defineConfig(({command}) => ({
  plugins: [
    symfonyPlugin({
      viteDevServerHostname: 'localhost',
    }),
  ],
}));
import {mergeConfig} from 'vite';
import symfonyPlugin from 'vite-plugin-symfony';

const config = {
  async viteFinal(config, options) {
    // While "rendering chunks", Vite will error out with "Entry points must be inside Vite root directory"
    if (options.configType === 'PRODUCTION') {
      for (let i = 0; i < config.plugins.length; i++) {
        if (config.plugins[i].name === symfonyPlugin.name) {
          config.plugins.splice(i, 1);
        }
      }
    }
    return mergeConfig(config, {});
  },
};
export default config;

我不知道是什么原因导致了这个问题,通过查看源代码对我来说可能太多了,因为我目前的知识有限。

insrf1ej

insrf1ej4#

版本6.3.0+需要对这个解决方法进行调整,以便任何人在这里寻求帮助。Symfony插件现在导出2个插件,所以我们只需要提取我们需要的插件名称,即"symfony-entrypoints"。

import type { StorybookConfig } from '@storybook/react-vite';
import { mergeConfig } from 'vite';
import symfonyPlugin from 'vite-plugin-symfony';

const config: StorybookConfig = {
  [...]
  async viteFinal(config, options) {
    // While "rendering chunks", Vite will error out with "Entry points must be inside Vite root directory"
    if (options.configType === 'PRODUCTION' && config.plugins) {
      for (let i = 0; i < config.plugins.length; i++) {
        const pluginOrArrayOf = config.plugins[i];
        if (Array.isArray(pluginOrArrayOf)) {
          for (let j = 0; j < pluginOrArrayOf.length; j++) {
            // @ts-ignore TODO: Name exists, fix type?
            if (pluginOrArrayOf[j]?.name === symfonyPlugin()[0].name) {
              config.plugins.splice(i, 1);
            }
          }
        }
      }
    }
    return mergeConfig(config, {
      [...]
    });
  },
};

Storybook团队不需要处理这个问题,应该由SymfonyPlugin创建者处理。

相关问题