在Webpack中,如何使用自定义源模板来构造特定的模块
In Webpack, how to use custom source template to construct specific module
我知道Webpack内部的一些功能。一些关于依赖关系、模板和模块构建的内容。然而,在其源代码中几乎没有评论,目前也没有完整的文档站点。所以,我不能把它们都串起来处理我的问题。
根据我目前的需求,我需要使用自定义源模板(类似于webpack中的MultiModule
)来呈现特定模块。
注意:需要明确的是,生成的模块的依赖数组不是静态的。例如,一次它可以是
['./a', './b', './c']
,另一次它可能是['./b', './c','./d']
。这取决于构建前的一些动态配置。
对于更详细的示例,我需要一个名为main.js
的模块。在构建时,它需要动态生成目标依赖项,例如(因为不确定哪些模块是依赖项):
// main.js
var a = require('./a')
var b = require('./b')
var c = require('./c')
var d = require('./d')
...
事实上,如果我只需要动态地require
它们,我就可以动态地构建一个入口点。
// webpack.config.js
{
entry: {
main: [
'./a',
'./b',
'./c',
...
]
},
}
它(webpack)将生成一个模块,可能是这样的:
__webpack_require__(1);
__webpack_require__(2);
__webpack_require__(3);
return __webpack_require__(4);
但我需要做更多的事情:
var a = __webpack_require__(1);
var b = __webpack_require__(2);
var c = __webpack_require__(3);
var d = __webpack_require__(4);
...
// do something with a,b,c,d... under my custom need
...
return somthing or nothing;
正如你们了解webpack的人一样,它非常非常复杂,很难理解和跟踪其插件(事件)层次结构。
需要一些专业知识!:)
对不起,我之前的问题不清楚。
然而,这里有一种奇怪的气氛。我设立了一个赏金来获得关注和指导。不知怎么的,某人的自由回答驱使我发表了不礼貌的评论。然后,一些和事佬带着与问题或答案无关的评论出现了。太糟糕了。
专注于这件事只会让事情变得更糟,没有任何帮助。不放手只意味着有人心胸狭窄。
要么缺乏关注,要么缺乏专家,我必须自己与之斗争。幸运的是,深入研究webpack取得了一些进展。
先决条件
在流行的webpack的前一天,有一些流行的方式,比如grunt和gullow来构建自定义构建流(使用它们的插件)。它们可以实现大部分自定义需求,尤其是生成自定义模块(webpack没有明显而直接的方法来处理)。
当您开始执行诸如自动收集自定义依赖项之类的操作时,生成自定义模块是下一个重要步骤。它可以在产品线/系列设计中常见。
解决方案
#1
这是最简单直接的方法,但缺乏灵活性。
MultiModule的source
方法是生成具有多依赖关系的入口模块。只要压倒它就会击中目标。
// hack.js
const MultiModule = require('webpack/lib/MultiModule')
MultiModule.prototype.source = function(dependencyTemplates, outputOptions) {
var str = ['"hello world";'n'];
this.dependencies.forEach(function (dep, idx) {
if (dep.module) {
if (idx === this.dependencies.length - 1)
str.push("module.exports = ");
str.push("__webpack_require__(");
if (outputOptions.pathinfo)
str.push("/*! " + dep.request + " */");
str.push("" + JSON.stringify(dep.module.id));
str.push(")");
} else {
str.push("(function webpackMissingModule() { throw new Error(");
str.push(JSON.stringify("Cannot find module '"" + dep.request + "'""));
str.push("); }())");
}
str.push(";'n");
}, this);
return new RawSource(str.join(""));
}
在第五行,我添加了一个字符串语句"hello world;"'n
,其他内容都没有改变。
module.exports = {
entry: {
main: ["./a", "./b"],
}
// something else
}
输出CCD_ 8可能看起来像:
//...
/* 0 */
/*!******************!*'
!*** multi main ***!
'******************/
/***/ function(module, exports, __webpack_require__) {
"hello world";
__webpack_require__(/*! ./a */1);
module.exports = __webpack_require__(/*! ./b */2);
/***/ }
//...
现在,我们可以使用源方法执行我们想要的操作,同时考虑兼容性。
#2
这种方式更加灵活,但也很复杂。
它至少需要5个文件(源太长,我把它们做成了片段):
CustomMultiModule.js
:
// CustomMultiModule.js
const MultiModule = require('webpack/lib/MultiModule')
const RawSource = require('webpack/lib/RawSource')
class CustomMultiModule extends MultiModule {
constructor(...args) {
super(...args)
}
source(dependencyTemplates, outputOptions) {
var str = ['"hello world";'];
this.dependencies.forEach(function(dep, idx) {
if (dep.module) {
if (idx === this.dependencies.length - 1)
str.push("module.exports = ");
str.push("__webpack_require__(");
if (outputOptions.pathinfo)
str.push("/*! " + dep.request + " */");
str.push("" + JSON.stringify(dep.module.id));
str.push(")");
} else {
str.push("(function webpackMissingModule() { throw new Error(");
str.push(JSON.stringify("Cannot find module '"" + dep.request + "'""));
str.push("); }())");
}
str.push(";'n");
}, this);
return new RawSource(str.join(""));
}
}
module.exports = CustomMultiModule
CustomMultiModuleFactory.js
:
// CustomMultiModuleFactory.js
const MultiModuleFactory = require('webpack/lib/MultiModuleFactory')
const CustomMultiModule = require('./CustomMultiModule')
class CustomMultiModuleFactory extends MultiModuleFactory {
constructor() {
super()
}
create(context, dependency, callback) {
callback(null, new CustomMultiModule(context, dependency.dependencies, dependency.name));
};
}
module.exports = CustomMultiModuleFactory
CustomMultiEntryPlugin.js
:
// CustomMultiEntryPlugin.js
const MultiEntryPlugin = require('webpack/lib/MultiEntryPlugin')
const MultiEntryDependency = require('webpack/lib/dependencies/MultiEntryDependency')
const CustomMultiModuleFactory = require('./CustomMultiModuleFactory')
class CustomMultiEntryPlugin extends MultiEntryPlugin {
constructor(context, entries, name) {
super(context, entries, name)
}
apply(compiler) {
compiler.plugin('after-plugins', function(compiler) {
compiler.plugin("compilation", function(compilation, params) {
var multiModuleFactory = new CustomMultiModuleFactory();
compilation.dependencyFactories.set(MultiEntryDependency, multiModuleFactory);
})
})
}
}
module.exports = CustomMultiEntryPlugin
CustomEntryOptionPlugin.js
:
// CustomEntryOptionPlugin.js
const CustomMultiEntryPlugin = require('./CustomMultiEntryPlugin')
class CustomEntryOptionPlugin {
constructor() {}
apply(compiler) {
compiler.plugin("entry-option", function(context, entry) {
if (typeof entry === "object") {
Object.keys(entry).forEach(function(name) {
if (Array.isArray(entry[name])) {
compiler.apply(new CustomMultiEntryPlugin(context, entry[name], name));
}
});
}
});
}
}
module.exports = CustomEntryOptionPlugin
webpack.config.js
:
// webpack.config.js
const CustomEntryOptionPlugin = require('./CustomEntryOptionPlugin')
module.exports = {
entry: {
main: ["./a", "/b"] // this dependencies array may be generated
...
},
output: {
path: path.join(__dirname, "js"),
pathinfo: true,
filename: "[name].[chunkhash].js",
chunkFilename: "[chunkhash].js"
}
plugins: [
new CustomEntryOptionPlugin(),
...
]
...
};
通过上面的代码,我们可以实现与#1相同的功能。如果我们愿意的话,我们可以对目标条目或其他需求进行更多的控制。
通常在webpack中,你只需要一个文件,可能需要文件所依赖的不同库。如果你需要main,那么webpack将基于CommonJS语法来解决依赖关系,你可以在这里阅读。删除webpack.config.js文件中的额外要求能解决这个问题吗?例如,只有以下内容作为配置:
// webpack.config.js
{
entry: [ "./main" ],
...
}
听起来你并不真正理解webpack是如何工作的——它的想法是模仿Node的CommonJS语法如何允许你的javascript模块化并放置在单独的文件中,同时又具有高性能,不需要浏览器发出大量AJAX请求。如果您想了解更多关于Webpack配置文件的信息,请查看此页。
顺便说一句,在模块末尾返回绝对没有任何作用。如果您想导出,可以使用module.exports
,但在main.js
文件的末尾有一行类似return true
之类的内容不会有任何意义。
- 如何在Webpack中从导出中排除供应商模块peerDependencies
- 通过Webpack导入模块中的图像
- Webpack通过npm将代码拆分为单独的模块,以及如何编译es6
- 无法使用Webpack加载ES6模块
- 可以'I don’我不明白;使用webpack和es6模块进行EventEmitter
- 为具有核心模块和子模块的应用程序构建Webpack
- Javascript:Webpack+Typescript+Namespace(内部模块)
- 如何使用 webpack 要求或仅从模块导入必要的导出
- webpack配置警告和错误:;模块解析失败”;
- webpack所说的XX隐藏模块是什么意思
- 从脚本标记的全局范围调用webpack模块中的函数
- webpack在全局范围内执行模块
- 无法解析模块'角度'当使用Ionic和Webpack导入ngstorage时
- 使用webpack和babel加载程序导入导出ES6模块
- 导出由 webpack 构建的模块
- 使用 webpack 和 ts-loader 重新导出 ES6 模块
- 使用 webpack css 模块的容器查询
- 需要没有 Browserify、Webpack 或 Babel 的 reactjs 模块
- webpack 1:resolve.alias 不将一个 npm 模块别名到另一个 npm 模块
- 在前端使用 ES6 npm 模块(webpack)