我有一个项目结构,其中包含一个文件夹,当我构建我的webpack配置并将每个文件作为输出版本中的子模块时,我想将其动态导入UMD模块。
例如,让我们说我的来源如下:
/src/snippets/red.js
/src/snippets/green.js
/src/snippets/blue.js
我希望webpack将这些源构建到一个模块中,允许我作为子模块访问每个模块,就像这样;
const red = require('snippets').red
我尝试遍历snippets目录并创建一个带有文件名和路径的对象,但是我无法确定哪个配置属性会指示webpack将它们捆绑到一个文件中并导出每个文件。这就是我到目前为止所拥有的:
const glob = require('glob')
module.exports = {
entry: glob.sync('./src/snippets/*.js').reduce((files, file) => {
files[path.basename(file,'.js')] = file
return files
}, {}),
output: {
path: __dirname + '/lib',
filename: 'snippets.js',
libraryTarget: 'umd'
}
}
这出错:Conflict: Multiple assets emit to the same filename ./lib/snippets.js
关于如何实现我所寻找的目标的任何想法?
答案 0 :(得分:3)
在生产中使用此解决方案的修改版本已有一段时间了,我没有遇到任何问题。 (我公司的设置有一个稍微复杂的过滤器,排除某些模拟模块,但在其他方面是相同的。)
我们使用构建脚本来抓取相关目录(在我们的设置中,它是src
但在你的src/snippets
中。对于以.js结尾的每个文件,我们导入它并重新在src/index.js
中导出它。如果你需要更强大的东西,比如深入多层次,你需要修改它以递归遍历目录结构。
完成此操作后,我们将其输出到index.js,同时提醒您文件是自动生成的,以阻止人们手动将条目添加到文件中。
const fs = require("fs");
const { EOL } = require("os");
const path = require("path");
let modules = 0;
const buffer = [
"// auto-generated file", "",
];
const emitModule = file => {
const moduleName = file.replace(".js", "");
modules += 1;
buffer.push(`exports.${moduleName} = require("./snippets/${moduleName}");`);
};
const files = fs.readdirSync(__dirname + "/snippets");
files
.filter(fname => fname !== "index.js" && !fname.startsWith("."))
.forEach(f => {
const stats = fs.statSync(path.join(__dirname, "snippets", f));
if (stats.isFile()) {
emitModule(f);
}
});
fs.writeFileSync(path.join(__dirname, "index.js"), buffer.join(EOL)+EOL);
console.info(`Built 'src/index.js' with ${modules} modules`);
然后,在webpack.config.js中,我们将libraryTarget设置为umd
,如下所示:
module.exports = {
entry: path.resolve(__dirname, "src/index.js"),
output: {
path: path.resolve(__dirname, "build/"),
filename: "mylib.js",
libraryTarget: "umd"
}
};
最后,为方便起见,在package.json中,我们使用以下命令在构建之前自动运行构建脚本(您也可以在启动webpack-dev-server之前使用它,或者运行mocha测试)。
这个设置感觉相当hacky,但它运作得很好。我遇到过的唯一问题是,偶尔会出现模块的顺序改变(可能是因为环境差异),文件的枚举会导致git中出现误报。
我已将整个软件包放在GitHub上:https://github.com/akatechis/webpack-lib-poc
更新:
如果您不想通过将构建脚本添加到package.json scripts
来手动调用构建脚本,则可以始终将其包装为webpack插件。您可以阅读详细信息here
简而言之,插件只是一个带有apply
方法的对象,它使用webpack编译器注册自己。来自文档:
作为一名聪明的JavaScript开发人员,您可能会记住
Function.prototype.apply
方法。由于这种方法,您可以将任何函数作为插件传递(this
将指向编译器)。您可以使用此样式在配置中内联自定义插件。
以下是两种设置之间的变化:
更改webpack配置以导入构建脚本并将其添加到plugins
阵列:
const path = require("path");
const buildPlugin = require("./src/index.build");
module.exports = {
entry: path.resolve(__dirname, "src/index.js"),
output: {
path: path.resolve(__dirname, "build/"),
filename: "mylib.js",
libraryTarget: "umd"
},
plugins: [buildPlugin]
};
然后更改index.build.js
以导出在编译器上注册回调的函数(它将其作为this
接收)。从之前获取构建脚本的内容,将其放入build()
函数,然后导出插件函数,如下所示:
module.exports = function () {
this.plugin('run', function(compiler, callback) {
console.log("Build script starting");
build();
callback();
});
};
从build-index
中的任何脚本中删除package.json
目标。 Webpack现在总是在运行之前调用您的构建脚本。
答案 1 :(得分:0)
试试这个:
我基本上以不同的方式略微更改条目,然后进一步使用NamedModulesPlugin。
module.exports = {
entry: glob.sync('./snippets/*.js').reduce(function(entry, file){
entry['./snippets'].push(file);
return entry;
}, { './snippets': []}),
output: {
path: path.resolve(__dirname, ''),
filename: '[name].js'
libraryTarget: 'umd'
},
module: {
// only relevant portions shown
plugins: [
new webpack.NamedModulesPlugin()
]
}
};
它应该有用。
答案 2 :(得分:-1)
看起来类似于conflict-multiple-assets-emit-to-the-same-filename和this solved issue,所以它可能对您有所帮助。 我看到某处也可能是由于你的模块插件中的一个(或多个)不支持打包。