源码分析(一):前言及总流程概览
前言
此系列文章作为笔记,用于记录分析 webpack
源码主流程的过程。
概览
目录
根据 webpack
构建流程及相关,本系列文章一共分为以下章节:
- 配置初始化
- 编译前的准备
- reslove 前的准备
- reslove 流程
- 构建 module(上)
- 构建 module(下)
- 生成 chunk
- 优化 chunk
- 资源的构建
- 文件的生成
- 打包后文件解析
- watch
- webpack 优化
流程图
webpack
构建流程图:
本系列代码环境
json
"devDependencies": {
"@babel/core": "^7.7.5",
"@babel/preset-env": "^7.7.6",
"@fe_korey/test-loader": "^1.0.0",
"babel-loader": "^8.0.6",
"html-webpack-plugin": "^3.2.0"
},
"dependencies": {
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
}
版本不同,源码略微有差异。
本项目 demo
开源在github,欢迎交流学习。
分析源码前的一系列准备工作
采用 vscode 来打断点调试分析。
配置 vscode
json
//launch.json
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "debug"],
"port": 5858,
"console": "externalTerminal",
"skipFiles": ["<node_internals>/**/*.js"]
}
]
配置 npm script
json
"scripts": {
"debug": "node --inspect-brk=5858 ./node_modules/.bin/webpack"
},
了解 webpack 的插件架构
webpack
从配置初始化到打包完成定义了一个生命周期,在这个生命周期中的每一个阶段定义一些不同的功能。webpack
的流程同样也是一个事件驱动的架构,利用插件系统 tapable
,通过 发布订阅事件
来实现所有内部的,外部扩展的功能。
了解 webpack 的核心模块
webpack
的构建是通过 Compiler
控制构建流程,Compilation
解析,ModuleFactory
生成模块,Parser
解析源码,Template
渲染代码,最后输出打包后的文件。
了解 tapable
tapable
本质就是一个事件发布订阅机制,支持同步异步,使用xxx.tap
之类的来事件订阅,使用xxx.call
之类的来进行事件发布。 相关文档查阅:
demo 准备
npm 安装
bash
npm i webpack-cli webpack
npm i @babel/core @babel/preset-env babel-loader -D
npm i @fe_korey/test-loader -D
demo 文件
我们以 development
模式为例,暂时忽略支线剧情,只分析探索 webpack
的打包主流程。
js
//src/a.js
import { add } from 'Src/b';
import('./c.js').then((m) => m.sub(2, 1));
const a = 1;
add(3, 2 + a);
js
//src/b.js
import { mul } from '@fe_korey/test-loader?number=20!Src/e';
export function add(a, b) {
return a + b + mul(10, 5);
}
export function addddd(a, b) {
return a + b * b;
}
js
//src/c.js
import { mul } from 'Src/d';
import('./b.js').then((m) => m.add(200, 100));
export function sub(a, b) {
return a - b + mul(100, 50);
}
js
//src/d.js
export function mul(a, b) {
const d = 10000;
return a * b + d;
}
js
//webpack.config.js
var path = require('path');
module.exports = {
entry: {
bundle: './src/a.js',
},
devtool: 'none',
output: {
path: __dirname + '/dist',
filename: '[name].[chunkhash:4].js',
chunkFilename: '[name].[chunkhash:8].js',
},
mode: 'development',
resolve: {
alias: {
Src: path.resolve(__dirname, 'src/'),
},
},
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
},
],
},
],
},
};
js
//babel.config.js
module.exports = {
presets: ['@babel/env'],
};
一颗坚定且耐操的心
为什么要阅读它?
- 因为可以让我们更好的理解海量配置,知道每一个配置在打包的具体哪个环节
- 在对构建流程进行优化时能更清楚的根据过程思考优化点
- 还可以学习下在这种大型项目里,如何实现稳定的架构和良好的扩展性
- 对自定义开发一些
plugin
和loader
有更深刻的理解 - 了解它的一些代码设计方式能给我们的日常搬砖带来一些新的启发
最重要的还是想满足自己的好奇欲,想知道在这犀利的打包背后,到底是怎么实现的。
webpack
里包含数不清的变量和钩子,海量插件,这些足以让你怀疑人生,请务必保持一颗耐操的心。 一切准备就绪后,进入 vscode
的调试模式!