webpack系列5:源码流程,webpack编译流程
1. webpack编译流程
- 初始化参数:从配置文件和
Shell
语句中读取与合并参数,得出最终的参数; - 开始编译:用上一步得到的参数初始化
Compiler
对象,加载所有配置的插件,执行对象的run
方法开始执行编译; 确定入口:根据配置中的entry
找出所有的入口文件 - 编译模块:从入口文件出发,调用所有配置的
Loader
对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理; - 完成模块编译:在经过第4步使用
Loader
翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系 - 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的
Chunk
,再把每个Chunk
转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会 - 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
在以上过程中,
Webpack
会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果
2.调试webpack
2.1 如何生成调试文件
- 打开工程目录,点击调试按钮,再点击小齿轮的配置按钮系统就会生成launch.json配置文件
- 修改好了以后直接点击F5就可以启动调试
.vscode\launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "debug webpack",
"cwd":"${workspaceFolder}",
"program":"${workspaceFolder}/node_modules/webpack-cli/bin/cli.js"
}
]
}
2.2 webpack.cmd
-
webpack-source\node_modules\.bin\webpack.cmd
-
%~dp0
是批处理文件所在的盘符:+路径(%~dp0 C:\vipdata\vipproject\webpack-source\node_modules.bin) -
SETLOCAL
主要针对临时环境变量,不会影响到系统的变量环境设置,应与endlocal联用 -
PATHEXT
当在一个相同的目录结构下,有相同的多个主文件名,不同的文件后缀名时,系统会根据PATHEXT中的后缀名,选择其中顺序最靠前的那一个
@IF EXIST "%~dp0\node.exe" (//如果当前盘符的根目录下存在node.exe,用当前的node执行
"%~dp0\node.exe" "%~dp0\..\_webpack@4.39.3@webpack\bin\webpack.js" %*
) ELSE (//如果当前的盘符没有node.exe
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\_webpack@4.39.3@webpack\bin\webpack.js" %*
)
2.3 webpack.js
- node_modules\webpack\bin\webpack.js
const path = require("path");
const pkgPath = require.resolve(`${installedClis[0].package}/package.json`);
const pkg = require(pkgPath);
require(path.resolve(
path.dirname(pkgPath),
pkg.bin[installedClis[0].binName]
));
const path = require("path");
const pkgPath = require.resolve(`webpack-cli/package.json`);
const pkg = require(pkgPath);
require(path.resolve(path.dirname(pkgPath),pkg.bin['webpack-cli']));
npx webpack = node ./node_modules/webpack-cli/bin/cli.js
2.4 cli.js
const webpack = require("webpack");
const webpackOptions = require("./webpack.config");
const compiler = webpack(webpackOptions);
compiler.run((err, stats) => {
console.log(err);
console.log(stats.toJson({
entries:true,
chunks:true,
modules:true,
_modules:true,
assets:true
}));
});
3.Stats 对象
- 在 Webpack 的回调函数中会得到stats对象
- 这个对象实际来自于
Compilation.getStats()
,返回的是主要含有modules
、chunks
和assets
三个属性值的对象。 - Stats对象本质上来自于lib/Stats.js的类实例
字段 | 含义 |
---|---|
modules | 记录了所有解析后的模块 |
chunks | 记录了所有chunk |
assets | 记录了所有要生成的文件 |
npx webpack --profile --json > stats.json
{
"errors": [],// 错误字符串 (error string) 的数组
"warnings": [],//警告字符串 (warning string) 的数组
"version": "4.39.3",// 用来编译的 webpack 的版本
"hash": "3e945ec6b2c56d0b010e",//编译使用的 hash
"time": 66, // 编译耗时 (ms)
"builtAt": 1567225465347,//编译的时间
"publicPath": "",//资源访问路径
"outputPath": "C:\\vipdata\\vipproject\\webpack-source\\dist",//webpack输出目录
"assetsByChunkName": {//用作映射的 chunk 的名称
"lazy": "lazy.bundle.js",//chunk的名字叫lazy,lazy.bundle.js
"main": "bundle.js"//chunk的名字叫main,打包出来了bundle.js
},
"assets": [//asset 对象 (asset objects) 的数组
{
"name": "bundle.js",//文件名
"size": 9043,//大小
"chunks": [//包含的代码块
"main"
],
"chunkNames": [//包含的代码块名称
"main"
],
"emitted": true//是否要生成
},
{
"name": "lazy.bundle.js", // 输出的文件名
"size": 336,// 文件的大小
"chunks": [ // 这个 asset 包含的 chunk 的 id
"lazy"
],
"chunkNames": [// 这个 asset 包含的 chunk
"lazy"
],
"emitted": true // 表示这个 asset 是否会让它输出到 output 目录
}
],
"filteredAssets": 0,
"entrypoints": {
"main": {
"chunks": [
"main"
],
"assets": [
"bundle.js"
],
"children": {},
"childAssets": {}
}
},
"namedChunkGroups": {
"main": {
"chunks": [
"main"
],
"assets": [
"bundle.js"
],
"children": {},
"childAssets": {}
},
"lazy": {
"chunks": [
"lazy"
],
"assets": [
"lazy.bundle.js"
],
"children": {},
"childAssets": {}
}
},