Razzle: CI 中的 Webpack 性能插件将使构建失败

创建于 2018-06-19  ·  9评论  ·  资料来源: jaredpalmer/razzle

问题

目前,Webpack 的性能默认值为 244KiB(未压缩),如果设置process.env.CI = true ,则构建将失败并抱怨性能下降。

Razzle,没有任何添加,已经是 192KiB(未压缩),不包括任何 CSS(上面也包括 CSS)。

如果您在 CI 中运行它,对基础 Razzle 项目的任何合理添加基本​​上都会导致构建失败。

entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
  client (248 KiB)
      static/css/bundle.c91c1092.css
      static/js/bundle.5bcffbdf.js

webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

重现步骤

  1. 添加一些小 2.99kB 的 CSS: https ://gist.github.com/annez/ad5c49932358a871eb340c6773b9f4bb
  2. 向浏览器添加一些core-js polyfills 不要破坏 - assign, find, from, promise
  3. 添加一些合理的 React 包 - 例如react-autosuggest
  4. 运行CI=true npm run build并观察它掉下来

建议

我认为未压缩时的包大小错误令人困惑,但如果构建成功,我们会显示压缩大小。 此外,244KiB 的未压缩 JavaScript 从来都不是性能下降的指标——人们应该使用性能监控和预算来了解什么时候会降低用户体验。

这里有几个选项:

  • 从默认的 Razzle 配置中完全删除webpack.performance
  • 设置一个更大的上限,例如 512KiB(如果我们测量实际性能,这也是任意的)
stale

最有用的评论

我也经历过@mrmartineau所说的。

我认为有一个默认的资产大小限制是一件好事; 它让您对您的入门捆绑包中包含的内容保持敏锐。

但是,我希望使用 CI 环境变量设置_with_ 和_without_ 相同的块。 我知道 CI 上的警告和错误之间存在差异,但我不明白为什么在本地构建而不是在 CI 中构建时会有更多的块。

所有9条评论

遇到同样的问题。 虽然我认为删除似乎有点伤害。 您可以根据需要使用razzle.config.js进行配置。 也许你会这样做:

module.exports = {
  // ...
  modify(defaultConfig, { target, dev }, webpack) {
      if (!dev) {
        config.performance = Object.assign({}, {
          maxAssetSize: 100000,
          maxEntrypointSize: 300000,
          hints: false
        })
      }

    return config
  }
}

你好! 所以这就是开源与我的日常工作和生活之间的交易,我有很多事情要管理,所以我使用 GitHub 机器人在这里和那里自动化一些事情。 这个特定的 GitHub 机器人将把它标记为陈旧,因为它有一段时间没有最近的活动。 如果几天内没有进一步的活动,它将关闭。 不要把这当成个人 - 说真的 - 这是一个完全自动化的操作。 如果这是一个错误,请发表评论、私信我、发送航母 pidgeon 或烟雾信号。

ProBot 由于不活动而自动关闭它。 如果这是一个错误,请大声喊叫,我们将重新打开它。

我也遇到过这个问题,并认为应该在未来的版本中对其进行审查。 我喜欢内置性能预算的姿态,但 52KiB 的限额相当小。

我同意,但我发现有问题的是performance.hints设置会在文件完全压缩之前触发警告(如果在 CI 上,则会触发完全错误)。 在我的例子中,在 CI 上运行razzle build如下所示:

$ razzle build
Creating an optimized production build...
Compiling client...
Starting type checking and linting service...
Using 1 worker with 2048MB memory limit

Treating warnings as errors because process.env.CI = true.
Most CI servers set it automatically.

Failed to compile.

asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
  static/js/bundle.99af500d.js (634 KiB)

entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
  client (634 KiB)
      static/js/bundle.99af500d.js

error Command failed with exit code 1.

在我的本地机器上,它看起来像这样:

$ razzle build
Creating an optimized production build...
Compiling client...
Starting type checking and linting service...
Using 1 worker with 2048MB memory limit
Compiled client successfully.
Compiling server...
Compiled server successfully.
Compiled successfully.

File sizes after gzip:

  181.77 KB  build/static/js/bundle.99af500d.js
  10.04 KB   build/static/js/2.945fb472.chunk.js
  4.87 KB    build/static/js/3.c9f99c02.chunk.js
  1.9 KB     build/static/js/6.a430e3d3.chunk.js
  1.74 KB    build/static/js/4.ee533cb7.chunk.js
  1.04 KB    build/static/js/0.aec4785f.chunk.js
  574 B      build/static/js/5.11154537.chunk.js

✨  Done in 10.95s.

您可以看到最终构建远小于 webpack 的performance.hints设置默认设置的 244KiB 限制。

我已将@rohidee的建议添加到我们的razzle.config.js中,但我宁愿以一种更简洁的方式来解决这个问题。

仅供参考,您可以测试您的 CI 如何构建您的应用程序,但在构建命令之前添加env CI=true ,在我的情况下是: env CI=true yarn build

我也经历过@mrmartineau所说的。

我认为有一个默认的资产大小限制是一件好事; 它让您对您的入门捆绑包中包含的内容保持敏锐。

但是,我希望使用 CI 环境变量设置_with_ 和_without_ 相同的块。 我知道 CI 上的警告和错误之间存在差异,但我不明白为什么在本地构建而不是在 CI 中构建时会有更多的块。

我们可以重新打开这个问题吗? 根据 CI env 变量,我仍然会得到不同的包大小。 我尝试在这里查看默认配置,但没有发现任何感兴趣的内容。

我的解决方法是将 CI 构建脚本设置为CI=false yarn build ,因此生成的包与我通常在本地运行yarn build时得到的包相同,而无需禁用包大小警告。

我通过以下方式解决了这个问题:

  • 启用 webpack split chunks 插件为所有 node_modules 依赖项创建一个“供应商块”,因此它们与我的应用程序代码分开
  • 禁用供应商块的 webpack 性能提示(但为其他我不希望很大的块启用它)

在这样做的过程中,我意识到期望 razzle 根据 gzip 文件大小计算这些提示并不是很合理。 这一切都是由 webpack 性能提示插件完成的,该插件在非 gzip 上运行。
https://webpack.js.org/configuration/performance/

我的 razzle.config.js:

const logger = require('razzle-dev-utils/logger')

module.exports = {
  plugins: [
    useRuntimePortEnvironmentVariable,
    WebpackSplitChunksRazzlePlugin({
      // include both initial and async imports for chunking, not just initial
      chunks: 'all',
      // default is 3
      maxInitialRequests: Infinity,
      // default is 30000
      minSize: 0,
    }),
    WebpackPerformanceHintsRazzlePlugin({
      // Use a custom assetFilter to not warn about big source maps or vendor bundle
      assetFilter: function(assetFilename) {
        const isSrcMap = /\.map$/.test(assetFilename)
        const isVendorBundle = /vendor/.test(assetFilename)
        return ! (isSrcMap || isVendorBundle)
      }
    }),
    'typescript',
  ],
}

function NoopRazzlePlugin() {
  return function NoopRazzlePluginFunc(config) {
    return config
  }
}

function WebpackPerformanceHintsRazzlePlugin(pluginOptions) {
  return function WebpackPerformanceHintsRazzlePluginFunc(config) {
    return {
      ...config,
      performance: {
        ...config.performance,
        assetFilter: function(assetFilename) {
          const isSrcMap = /\.map$/.test(assetFilename)
          const isVendorBundle = /vendor/.test(assetFilename)
          return ! (isSrcMap || isVendorBundle)
        }
      }
    }
  }
}

/**
 * Update config to use process.env.PORT provided at *runtime*, not build-time, which is the default behavior
 */
// https://github.com/jaredpalmer/razzle/issues/906#issuecomment-467046269
function useRuntimePortEnvironmentVariable(config, { target, dev }, webpack) {
  const appConfig = Object.assign({}, config);

  // <strong i="13">@BUG</strong>: Do not inline certain env vars; https://github.com/jaredpalmer/razzle/issues/356
  if (target === 'node') {
    const idx = appConfig.plugins.findIndex(plugin => plugin.constructor.name === 'DefinePlugin');
    const { definitions } = appConfig.plugins[idx];
    const newDefs = Object.assign({}, definitions);

    delete newDefs['process.env.PORT'];
    delete newDefs['process.env.HOST'];
    delete newDefs['process.env.PUBLIC_PATH'];

    appConfig.plugins = [].concat(appConfig.plugins);
    appConfig.plugins[idx] = new webpack.DefinePlugin(newDefs)
  }

  return appConfig;
}

/**
 * Razzle Plugin to split common libraries into a chunk named 'vendor'.
 * The idea is that this bundle will change way less often than the src code
 * of this app, so will mean less average download size because vendor can be cached.
 * Taken from https://github.com/jaredpalmer/razzle/tree/master/examples/with-vendor-bundle
 */
function WebpackSplitChunksRazzlePlugin(pluginOptions={}) {
  return function WebpackSplitChunksRazzlePluginFunc (razzleConfigBefore, { target, dev }, webpack) {
    const config = Object.assign({}, razzleConfigBefore);

    // Change the name of the server output file in production
    if (target === 'web') {
      // modify filenaming to account for multiple entry files
      config.output.filename = dev
        ? 'static/js/[name].js'
        : 'static/js/[name].[hash:8].js';

      // I think these are the default that webpack sets
      // https://webpack.js.org/plugins/split-chunks-plugin/#optimizationsplitchunks
      const defaultSplitChunksConfig = {
        chunks: 'async',
        minSize: 30000,
        maxSize: 0,
        minChunks: 1,
        maxAsyncRequests: 5,
        maxInitialRequests: 3,
        automaticNameDelimiter: '~',
        automaticNameMaxLength: 30,
        name: true,
        cacheGroups: {
          vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10
          },
          default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
          }
        }
      }
      config.optimization.splitChunks = {
        ...defaultSplitChunksConfig,
        ...config.optimization.splitChunks,
        ...pluginOptions,
      }
    }

    return config;
  }
}

对任何在这里绊倒的人的警告:无论出于何种原因,上面提出的使用useRuntimePortEnvironmentVariableWebpackSplitChunksRazzlePluginWebpackPerformanceHintsRazzlePlugin的解决方案在开发模式下都可以很好地工作,但可能会破坏客户端在生产模式下渲染。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

charlie632 picture charlie632  ·  4评论

ewolfe picture ewolfe  ·  4评论

gabimor picture gabimor  ·  3评论

krazyjakee picture krazyjakee  ·  3评论

dizzyn picture dizzyn  ·  3评论