❝本文由作者 xfz 授权发布 ❞
webpack本质:理解为是一种基于事件流的编程范例,一系列的插件运行
运行命令后 npm让命令行工具进入node_modules/.bin目录查找是否存在webpack.sh或者webpack.cmd文件 如果存在,则执行,不存在,抛出错误(node_modules/wepback/bin/wepback.js)
启动后的结果:wepback最终找到wepback-cli(webpack-command)包,并且执行cli
// 正常执行返回
process.exitCode = 0;
// 运行某个命令
const runCommand = (command, args) => {
const cp = require("child_process");
return new Promise((resolve, reject) => {
const executedCommand = cp.spawn(command, args, {});
executedCommand.on("error", error => reject(error););
// code 为 0 则说明成功,resolve,否则reject
executedCommand.on("exit", code => {})
});
}
// 判断某个包是否安装
onst isInstalled = packageName => {
try {
require.resolve(packageName);
return true;
} catch (err) {
return false;
}
};
// wepback 可用的 cli:webpck-cli和webpack-command
const installedClis = CLIs.filter(cli => cli.installed)
// 判断两个cli是否安装,根据安装数量处理
if (installedClis.length === 0) {}
else if (installedClis.length === 1) {}
else {}
// wepback-cli处理不需要经过编译的命令
const NON_COMPILATION_ARGS = [
"init", // 创建一份webpack配置文件
"migrate", // 进行webpack版本迁移
"add", // 往webpack配置文件中增加属性
"remove", // 从webpack配置文件中删除属性
"serve", // 运行webpack-serve
"generate-loader", // 生成webpack loader 代码
"generate-plugin", // 生成webpack plugins 代码
"info" // 返回与本地环境相关的一些信息
];
const NON_COMPILATION_CMD = process.argv.find(arg => {
if (arg === "serve") {
global.process.argv = global.process.argv.filter(a => a !== "serve");
process.argv = global.process.argv;
}
return NON_COMPILATION_ARGS.find(a => a === arg);
});
if (NON_COMPILATION_CMD) {
return require("./prompt-command")(NON_COMPILATION_CMD, ...process.argv);
}
// 通过yargs,提供命令和分组参数,动态生成help帮助信息
const yargs = require("yargs").usage(`webpack-cli ${
require("../package.json").version
}
// 将输入的命令传递给config-yargs
require("./config-yargs")(yargs);
// 对命令行参数进行解析
yargs.parse(process.argv.slice(2), (err, argv, output) => {}
// 生成 options webpack参数配置对象
let options = require("./convert-argv")(argv);
// 将参数设置对象交给webpack执行
let compiler = webpack(options);
// 创建钩子
const hook = new SyncHook(['arg1', 'arg2', 'arg3'])
// 绑定事件到webpack事件流
hook.tap('hook1', (arg1, arg2, arg3) => {console.log(arg1, arg2, arg3)})
// 执行
hook.call(1, 2, 3);// 1, 2, 3
if (Array.isArray(options)) {
compiler = new MultiCompiler(options.map(options => webpack(options)));
} else if (typeof options === "object") {
options = new WebpackOptionsDefaulter().process(options);
compiler = new Compiler(options.context);
compiler.options = options;
new NodeEnvironmentPlugin().apply(compiler);
if (options.plugins && Array.isArray(options.plugins)) {
for (const plugin of options.plugins) {
plugin.apply(compiler);
}
}
compiler.hooks.environment.call(); // hook了
compiler.hooks.afterEnvironment.call();
compiler.options = new WebpackOptionsApply().process(options, compiler);
} else {
throw new Error("Invalid argument: options");
}
if (callback) {
// ....
compiler.run(callback);
}
return compiler;
};
// 分别将各个依赖模块的代码⽤ modules 的⽅式组织起来打包成⼀个⽂件
================================entry======================================
// entry.js
import { bar } from './bar.js'; // 依赖 ./bar.js 模块
// bar.js
const foo = require('./foo.js'); // 依赖 ./foo.js 模块
递归下去,直至没有更多的依赖模块,最终形成一颗模块依赖树
================================moudles======================================
// entry.js
modules['./entry.js'] = function() {
const { bar } = __webpack__require__('./bar.js')
}
// bar.js
modules['./bar.js'] = function() {
const foo = __webpack__require__('./foo.js')
};
// foo.js
modules['./foo.js'] = function() {
// ...
}
================================output===========================
// 已经执⾏的代码模块结果会保存在这⾥
(function(modules){
const installedModules = {}
function __webpack__require__(id) {
// 如果 installedModules 中有就直接获取
// 没有的话从 modules 中获取 function 然后执⾏,
//将结果缓存在 installedModules 中然后返回结果
}
})({
"./entry.js": (function(__webpack_require__){
var bar = __webpack_require__(/*code内容*/)
}),
"./bar.js": (function(){}),
"./foo.js": (function(){}),
})
compiler hooks
compilation
ModuleFactory
Module
build
Compilation hooks
优化和seal相关
chunk生成算法
经过一周的时间,重新对这几年使用webpack4的感悟进行整理,是时候和 webpack4 说再见了,希望以后不要再见了...