在我的项目中,我想导入特定的模块,它们的实际路径只有在编译过程中才知道。
假设我有components/A.js、components/B.js和components/C.js,在我的App.js中,我想包含它们的一个子集,这些子集只有在webpack的编译时才能知道(例如:(JSON)
我所尝试的- 1
//App.js
compileData = await getCompileDataSomehow()
import("./components/" + compileData.component + ".js")
.then( /* Do stuff with component */);
这个工作很好,但是webpack会为每个components/*.js
文件创建一个块。此外,还将有额外的网络往返。我觉得这有点矫枉过正,因为我会知道什么组件,我想当webpack将运行。因此,我尝试 * 提供 * 组件数组,但没有成功,因为require([...])
也被认为是动态的。
我的结局
//App.js
import("./components/ALL.js") //this file doesn't actually exists
//webpack.config.js
const fs = require('fs')
const componentsToInclude = ["A", "B"] //this will be read from a json
fs.writeFileSync('./src/components/ALL.js',
`
export default [
${componentsToInclude.map(comp => `require("./${comp}.js")` )}
].map(c => c.default);
`)
module.exports = { // config //}
这是可行的!但正如你所看到的,这不是一个优雅的解决方案,而且很容易发生错误。那么,有没有人知道一个正确的方法来处理这种情况?
1条答案
按热度按时间nqwrtyyt1#
在这个答案中,我将假设,与问题类似,有一个主
App.js
文件,以及一个名为components
的目录,其中包含文件A.js
,B.js
,C.js
,D.js
等。只有A.js
、B.js
需要捆绑,所有其他文件都应该从捆绑中排除,但这只有在编译时才知道。require.context
Webpack提供了一种使用定制的、Webpack特定的require.context方法来指定一组依赖项的方法。
require.context
有四个参数:包含文件的目录的路径、确定是否包含子目录的布尔值、筛选文件的正则表达式以及加载模式的指令。将所有文件捆绑到我们运行的组件目录中
req
来运行从这些文件导出的任何函数。例如,如果每个.js
文件都导出了一个default
函数,要运行每个default
函数,您需要执行以下操作:*require.context
的更多信息,请参见this question and answers)*因为我们只想加载
A.js
和B.js
,所以必须向require.context
发送一个正则表达式来过滤文件。假设我们知道在写App.js
时只需要A.js
和B.js
。我们可以用一个硬编码的正则表达式来过滤文件,如下所示:/(A|B)\.js$/
是一个简单的正则表达式,如果输入是A.js
或B.js
,则返回true。它可以很容易地扩展到允许更多的文件:/(A|B|C|D)\.js$/
,或者只搜索特定的子目录。Webpack将在编译时计算正则表达式,并在包中只包含匹配的文件。然而,问题仍然存在:当我们在编译时只知道文件名时,我们如何确定过滤器是什么?
webpack.DefinePlugin
使用webpack.DefinePlugin,我们可以在
webpack.config.js
中定义全局变量,这些变量是在编译时定义的,Webpack使其静态地可用于每个文件。例如,我们可以将前面的正则表达式放入一个全局变量__IMPORT_REGEX__
:注意,通过
DefinePlugin
创建的变量的值必须是字符串化的;也就是说,我们不能提供原始RegExp值。这意味着任何反斜杠都必须转义。如果我们在数组中有文件的名称,也许以前从JSON文件中读取,我们可以在
webpack.config.js
中动态构建所需的正则表达式。在这个例子中,它是一个简单的join
使用|
字符作为分隔符的数组:把一切都放在一起
最后一点:Typescript用户需要为
__IMPORT_REGEX__
声明一个全局