使用 webpack 从动态源输出 UMD 模块
Output a UMD module from dynamic sources with webpack
我有一个项目结构,其中包含一个文件夹,当我构建我的 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
关于如何完成我正在寻找的东西有什么想法吗?
看起来与 and this solved issue 相似,因此它可能对您有所帮助。
我在某处看到它也可能是由于您的一个(或多个)模块插件不支持打包。
试试这个:
我基本上是稍微改变条目,然后进一步使用 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()
]
}
};
应该可以。
一段时间以来,我一直在生产中使用此解决方案的修改版本,而且我没有遇到任何问题。 (我公司的设置有一个稍微复杂的过滤器,用于排除某些模拟模块,但其他方面是一样的)。
我们使用构建脚本来抓取有问题的目录(在我们的设置中,它是 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之前使用,或者运行宁摩卡测试)。
这个设置感觉有点老套,但效果很好。我遇到过的唯一问题是偶尔会改变模块的顺序(大概是由于环境差异),并且文件的枚举会导致 git 中的误报。
我已将整个包裹放在 GitHub 此处:https://github.com/akatechis/webpack-lib-poc
更新:
如果您不想通过将构建脚本添加到您的 package.json scripts
来手动调用构建脚本,您可以随时将其包装为 webpack 插件。您可以阅读详情here
简而言之,插件只是一个带有 apply
方法的对象,该方法将自身注册到 webpack 编译器。来自文档:
As a clever JavaScript developer you may remember the Function.prototype.apply
method. Because of this method you can pass any function as plugin (this
will point to the compiler). You can use this style to inline custom plugins in your configuration.
以下是两种设置之间的变化:
更改 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();
});
};
从 package.json
中的任何脚本中删除 build-index
目标。 Webpack 现在总是会在 运行ning.
之前调用你的构建脚本
我有一个项目结构,其中包含一个文件夹,当我构建我的 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
关于如何完成我正在寻找的东西有什么想法吗?
看起来与
试试这个:
我基本上是稍微改变条目,然后进一步使用 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()
]
}
};
应该可以。
一段时间以来,我一直在生产中使用此解决方案的修改版本,而且我没有遇到任何问题。 (我公司的设置有一个稍微复杂的过滤器,用于排除某些模拟模块,但其他方面是一样的)。
我们使用构建脚本来抓取有问题的目录(在我们的设置中,它是 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之前使用,或者运行宁摩卡测试)。
这个设置感觉有点老套,但效果很好。我遇到过的唯一问题是偶尔会改变模块的顺序(大概是由于环境差异),并且文件的枚举会导致 git 中的误报。
我已将整个包裹放在 GitHub 此处:https://github.com/akatechis/webpack-lib-poc
更新:
如果您不想通过将构建脚本添加到您的 package.json scripts
来手动调用构建脚本,您可以随时将其包装为 webpack 插件。您可以阅读详情here
简而言之,插件只是一个带有 apply
方法的对象,该方法将自身注册到 webpack 编译器。来自文档:
As a clever JavaScript developer you may remember the
Function.prototype.apply
method. Because of this method you can pass any function as plugin (this
will point to the compiler). You can use this style to inline custom plugins in your configuration.
以下是两种设置之间的变化:
更改 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();
});
};
从 package.json
中的任何脚本中删除 build-index
目标。 Webpack 现在总是会在 运行ning.