webpack-require-from v 1.8.1

允许为获取动态导入配置路径或 URL 的 webpack 插件。

在运行时控制动态导入的路径/URL

  • 支持 webpack 5,4,3,2
  • 支持 web-worker 加载
  • 生产环境OK。
  • 无依赖。
  • 轻量。
  • 测试完备。

为什么要在运行时更改动态道路的路径?

Webpack 允许使用[require.ensure][require.ensure]dynamic importimport()来自动分割和加载代码。当你的主包在浏览器中运行时,模块以“按需”方式获取。

Webpack 根据配置中的config.output.publicPath从静态 URL 加载模块(包块)。

有些时候您需要在运行时控制模块(包块)的加载,举个例子:

  • 包块(chunks)托管在 CDN 上。
  • 不同的环境使用的 URL 来加载静态资源(生产环境,测试环境等)。
  • 您的index文件来自不同的域名/端口。
  • 您需要从不同的域名动态加载预编译文件。
  • 您需要从 CDN 加载第三方的 web worker。

如何使用?

// webpack.config.js
const WebpackRequireFrom = require("webpack-require-from");
const webpackRequireFromConfig = (module.exports = {
  output: {
    publicPath: "/webpack/"
  },
  plugins: [
    new WebpackRequireFrom({
      // 参见下方配置
    })
  ]
});
1
2
3
4
5
6
7
8
9
10
11
12

配置

如果没有传入任何配置项,那么该插件将默认使用[config.output.publicPath](https://webpack.js.org/guides/public-path/#on-the-fly)

path

为动态加载模块设置路径。您传入的值将在动态导入代码块时替换config.output.publicPath

举个例子,如果默认的 URL 是https://localhost,包名是0.js同时配置对象为{path: "customPath/" },那么代码块将从https://localhost/customPath/0.js获取。

注意: path / methodName / variableName这三个配置项是互斥的,不可同时使用。

variableName

variableName是全局定义的变量,它会在运行时进行计算,variableName是变量的名称,带有字符串的值表示路径/URL,它们用于动态导入代码块。

举个例子,如果默认的 URL 是https://localhost,包名是0.js同时配置对象为{variableName: "chunkURL" },同时window.chunkURL将定义为:

window.chunkURL = "https://app.cdn.com/buildXXX/"
1

代码块将从https://app.cdn.com/buildXXX/0.js获取。

methodName

全局定义的方法名,它将在运行时调用,该方法应该返回动态导入的代码块的路径/URL。

举个例子,如果默认的 URL 是https://localhost,包名是0.js,配置项为{methodName: "getChunkURL" },同时window.getChunkURL将定义为:

window.getChunkURL = function() {
  if (true) {
    // 使用任何条件来选择URL
    return "https://app.cdn.com/buildXXX/";
  }
};
1
2
3
4
5
6

代码块将从https://app.cdn.com/buildXXX/0.js获取。

如果与replaceSrcMethodName一起使用,chunk URL 将首先被 window[methodName]修改,然后修改的值作为一个参数传递给window[replaceSrcMethodName]函数。

注意: path / methodName / variableName这三个配置项是互斥的,不可同时使用。

注意: 该方法应该在全局命名空间中定义,并且应该在调用require.ensureimport()之前定义。请参见下面的例子:

replaceSrcMethodName

全局定义的方法名,它将在运行时调用,该方法接收动态引入的代码块的完整URL作为其参数并返回新 URL 的字符串。

举个例子,如果默认的 URL 是https://localhost,包名是0.jscommon.js,配置项为{replaceSrcMethodName: "replaceSrc" },同时window.replaceSrc将定义为:

window.replaceSrc = function(originalSrc) {
  if (originalSrc.match(/common/)) {
    // 对指定的 chunk 进行重命名
    return originalSrc.replace(/common/, "static");
  }
  return originalSrc;
};
1
2
3
4
5
6
7

代码块将从https://localhost/0.jshttps://localhost/static.js获取。

如果同时使用了methodNamevariableName,chunk URL 将首先被 window[methodName]修改亦或是修改为window[variableName],然后修改的值作为一个参数传递给window[replaceSrcMethodName]函数。

注意: 该方法应该在全局命名空间中定义,并且应该在调用require.ensureimport()之前定义。

supressErrors

默认值false。当无法检测到您在replaceSrcMethodNamemethodNamevariableName中定义的方法名时,插件将调用console.error。打开该配置项将压制错误信息。

全局方法和变量

当您的 JS 代码在浏览器中执行时,您作为variableNamemethodNamereplaceSrcMethodName值的方法/变量名应该在第一次调用require.ensure()import()执行之前设置。

方法的返回值将用于构建获取资源的 URL。

例如,在执行主包之前我们可以定义一个veryFirst的全局方法:

const window.veryFirst = function () {
    console.log("I am very first!");
}
1
2
3

您可以使用单独的文并使用 webpack 的配置项:

// 文件名: veryFirst.js
const window.veryFirst = function () {
 console.log("I am very first!");
}

// webpack.config.js
module.exports = {
  entry: {
    ['./veryFirst.js', './index.js']
  }
}
1
2
3
4
5
6
7
8
9
10
11

另一个方法是在服务端构建时将veryFirst定义为index.html的一部分:

// 文件名:server/app.js
app.get("/", (req, res) =>
  res.render("views/index", {
    cdnPath: "https://qa.cdn.com/|https://prod.cdn.com/"
  })
);
1
2
3
4
5
6
<!-- 文件名: views/index.ejs -->
<html>
<script>
    const baseCDN = "<%= cdnPath %>";
    window.veryFirst = function () {
        console.log(`${baseCDN}/js/`);
    }
</script>
</html>
1
2
3
4
5
6
7
8
9

Web Workers

使用replaceSrcMethodName提供一个修改 web-worker 加载路径的方法。该方法必须是全局可用的,并且必须在 web-worker 内的import()调用之前定义。

/* webpack.config.js */
  // ...
  module: {
    rules: [
      {
        test: /worker\.js$/,
        use: {
          loader: `worker-loader`
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin(),
    new RequireFrom({
      replaceSrcMethodName: "getSrc"
    })
  ]
  // ...


/* worker.js */
require("./globals.js");

import("./worker-module.js").then(workerModule => {
  workerModule.default();
  console.log("loaded workerModule");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

详细信息

该插件允许更改加载 web-worker 的路径。

为达成这个需求,使用了[worker-loader][worker-loader]加载器。该加载器使用[importScripts][importScripts]从您的 web-worker 中动态加载模块,并支持跨域web worker。更具体地说:

  1. 创建一个新的 webpack 入口,它只包含new Worker(workerURL),而workerURL是您的主要 webworker 模块。
  2. 用 webpack 运行时工具增强您的 webworker 主模块。
  3. 使用importScripts在 webworker 上下文中动态加载新模块(从而避免跨域限制)。

该插件重写了importScript并调用您在replaceSrcMethodName中定义的方法。您提供的方法将在调用importScripts之前被调用,所需的模块路径作为单个参数。

您可以在这里找到本插件联动 web worker 的应用实例。

排忧解难

${methodName}不是函数,或者在运行时不可用。

  • 确保webpack.config.js中的方法名与在全局window对象中定义的方法名匹配。
  • 确保在第一次调用require.ensure()import()之前定义该方法。

配置methodNamepath中的一个,不要两者都配置。

  • pathmethodName是互斥的,不能一起使用,随便使用一个就行。

${methodName} 不返回字符串。

  • 当使用replaceSrcMethodName配置项时,调用window[replaceSrcMethodName]的结果将被验证——它应该被定义并且是一个字符串。
  • 确保您从window[replaceSrcMethodName]返回一个字符串值。