如何在 Webpack 中拆分代码 require.sure for production



我正在使用 Webpack,我想将我的客户端代码分成几部分,并在用户需要时加载它们。

这是我的文件结构:

app.js       <-- Entry point as introduced to Webpack
Module.js    <-- To be loaded dynamically

app.jsModule.js 之间没有直接连接,而是第二个文件由第一个文件加载,如下所示:

require.ensure([], (require) => {
    let path = "Module";
    let module = require("./" + path).default;
});

我使用"./" + path只是为了确保 Webpack 不会对我变聪明并尝试静态解析路径。无论如何,这段代码在 webpack-dev-server 的开发模式下工作。我的意思是,在我触发事件以运行上述代码之前,不会下载Module.js。之后,它被完美加载和执行。

但是当我打包项目进行生产时,它停止工作。它发出以下错误(当我触发下载事件时在浏览器中(,甚至没有尝试发送请求:

未捕获错误:找不到模块"./模块"。

此外,当我动态编写路径时(如上面的代码(,构建过程会发出以下警告:

./src/app/app 中的警告.js 关键依赖关系: 74:34-47 依附的请求是表达式

为生产配置 Webpack 以支持动态下载的代码拆分的正确方法是什么?


我已经测试了@wollnyst给出的解决方案,这是结果。当我像这样实现它时,它可以工作:

require.ensure(["./Module"], (require) => {
    let path = "Module";
    let module = require("./" + path).default;
});

但这不是我想要的,我想要这样:

let path = "Module";
require.ensure(["./" + path], (require) => {
    let module = require("./" + path).default;
});

现在它在浏览器中给出一个运行时错误:

未捕获的类型错误: webpack_require(...(。确保不是一个函数

还是没有运气!

将您想要需要的路径动态放在 require.ensure 数组的第一个参数中是错误的,不应该这样做。此数组旨在用于要动态加载的模块的依赖项,以及回调中的异步代码安全运行所需的依赖项

理解 webpack 如何处理代码拆分的关键部分是你不能做完全动态的语句,因为 webpack 需要一些位置信息来解析你想要的模块,因此dependency is an expression警告。即使你可以像以前一样通过预置./来变得聪明,最好使用静态模块路径字符串实际重复完整的ensure语句,即使你有很多模块要动态加载并且它有点令人讨厌,这样你就不会遇到任何问题。

另一种方法是创建一个专用于该目的的文件夹,例如splits,并从此处解析所有模块。但这意味着您在此目录中需要的每个模块都将位于同一个分割点,除了特定的用例之外,任何人都不想要。


关于配置,您需要使用namedModulesPluginsCommonsChunkPlugin配置。我个人所做的是拥有一个包含所有公共源的main.js,一个包含所有常见node_modulesvendor.js,以及一个runtime.js(webpack 需要(。然后,将块分开,如果依赖于特定的供应商依赖项,则将其添加到该特定块而不是公共vendor.js中。

plugins: [
  new webpack.NamedModulesPlugin(),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    minChunks: module => module.context && module.context.indexOf('node_modules'),
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'runtime',
  }),
],

您还可以确保具有类似以下内容output.filename

output: {
  filename: '[name]-[chunkhash].js',
}

否则,每次源更改时,vendor.js的哈希值都会更改,即使您没有修改 deps,如果您担心缓存,这很糟糕。

最近的 webpack 可视化工具是一个非常好的工具,可以检查您的捆绑包和块的外观,并验证一切看起来是否正常或检测可以更好地分块的依赖项。如果使用StatsWriterPlugin收集统计信息,则可能需要稍微更改配置,以便它处理您的块:

new StatsWriterPlugin({
  fields: null,
  transform: (data, opts) => {
    const stats = opts.compiler.getStats().toJson({ chunkModules: true })
    return JSON.stringify(stats, null, 2)
  },
}),

还有一件事需要注意,require.ensure特定于 webpack,并且正在被它现在也处理的import()所取代。由于这个问题来自 2016 年,它可能没有我们现在使用 webpack 2 的相同元素,我将对其进行一些扩展。

现在,动态导入提案正在进入 ES,您可以在 webpack 中使用它。你需要一个 Promise polyfill 和类似 babel 语法动态导入插件的东西(现在应该在 stage-3 预设中(或动态导入 webpack,如果这对你还不起作用(基本上将import()转换为 ensures(。

你仍然需要指定完整路径,如确保如果你想为每个模块获取一个块,但这是一个更好的语法,并且在未来更加面向。

您可以在

新的 webpack 文档页面上查看许多其他有关代码拆分的资源。

你需要在require.ensure的第一个参数中传递你想要的模块:

require.ensure(['./Module'], function(require) {
    const module = require('./Module');
});

最新更新