學(xué)習(xí)源碼的一個(gè)好辦法就是宋彼,跟進(jìn)源碼的邏輯中掂咒,看看流程是怎么樣流轉(zhuǎn)的捅彻,
這需要我們有直接debug代碼的能力逮栅,
有時(shí)候還需要我們?cè)谀承╆P(guān)鍵位置寫入log戚揭。
下面我們從npm run build
命令行工具開始扯饶,想辦法debug進(jìn)webpack中悯姊,
然后在關(guān)鍵位置寫入log。
1. npm scripts
上一篇中揖曾,我們?cè)诿钚兄姓{(diào)用npm run build
落萎,
源碼就被自動(dòng)的編譯打包,然后結(jié)果輸出到了 ./dist/index.js 文件中了炭剪。
$ npm run build
> debug-webpack@1.0.0 build ~/Test/debug-webpack
> webpack
Hash: 2e91628041d9a877f709
Version: webpack 4.20.2
Time: 639ms
Built at: 2018-10-09 09:25:24
Asset Size Chunks Chunk Names
index.js 937 bytes 0 [emitted] index
Entrypoint index = index.js
[0] ./src/index.js 8 bytes {0} [built]
可是练链,這到底發(fā)生了什么呢?
1.1 npm run build
上一篇中我們?cè)趎pm scripts配置了npm run build
命令奴拦,
{
...,
"scripts:": {
...,
"build": "webpack"
}
...,
}
通過(guò)查看npm-run-script文檔兑宇,我們知道,
npm run
會(huì)自動(dòng)添加node_module/.bin
到當(dāng)前命令所用的PATH
變量中粱坤,
因此隶糕,npm run build
實(shí)際會(huì)調(diào)用 node_modules/.bin/webpack
。
$ node_modules/.bin/webpack
Hash: 2070b107dceedfc63c72
Version: webpack 4.20.2
Time: 334ms
Built at: 2018-10-09 10:13:05
Asset Size Chunks Chunk Names
index.js 930 bytes 0 [emitted] index
Entrypoint index = index.js
[0] ./src/index.js 10 bytes {0} [built]
與執(zhí)行npm run build 效果一樣站玄。
1.2 顯示原身
我在Finder中打開這個(gè)文件看了下枚驻,發(fā)現(xiàn)它是一個(gè)軟鏈接(symbolic link),
于是株旷,我們還要看看它的原身在哪里再登。
$ l ~/.nvm/versions/node/v8.12.0/bin/webpack
lrwxr-xr-x 1 用戶名 staff 41B 10 24 09:50 node_modules/.bin/webpack -> ../_webpack@4.20.2@webpack/bin/webpack.js
我們看到它的原身在這里,
../_webpack@4.20.2@webpack/bin/webpack.js
完整路徑如下晾剖,
~/Test/debug-webpack/node_modules/_webpack@4.20.2@webpack/bin/webpack.js
這就是我們?cè)趎ode_modules中安裝的webpack模塊的文件地址锉矢。
我們來(lái)看看代碼,
https://github.com/webpack/webpack/blob/v4.20.2/bin/webpack.js
#!/usr/bin/env node
process.exitCode = 0;
/**
* @param {string} command process to run
* @param {string[]} args commandline arguments
* @returns {Promise<void>} promise
*/
const runCommand =
...
以上鏈接是webpack github倉(cāng)庫(kù)的地址齿尽,我已經(jīng)找到了tag為4.20.2的版本位置沽损,
它展示了4.20.2版本的webpack,./bin/webpack.js的源代碼循头。
后文中我們可以使用這樣的方式展示源代碼了绵估。
1.3 Shebang
我們注意到了,./bin/webpack.js 文件頭有一行這樣的代碼卡骂,
#!/usr/bin/env node
它被稱為 Shebang国裳。
在類Unix系統(tǒng)中,包含Shebang的文本全跨,如果作為可執(zhí)行文件調(diào)用缝左,
#!
后面指定的解釋器將會(huì)被調(diào)用,用來(lái)執(zhí)行后面的代碼。
Shebang 語(yǔ)法如下渺杉,
#!interpreter [optional-arg]
注:
/usr/bin/env
不是一個(gè)路徑蛇数,而是一個(gè)命令,
后面跟node
參數(shù)少办,就會(huì)找到node并調(diào)用它,
我們來(lái)試試诵原,
$ /usr/bin/env node --version
v8.12.0
2. 寫入日志
上文中英妓,我們了解到,
npm run build
最終導(dǎo)致node解釋執(zhí)行了 ./bin/webpack.js 文件绍赛。
由于Node.js是解釋型語(yǔ)言蔓纠,所以,我們可以直接修改源碼吗蚌,來(lái)查看更改效果腿倚。
一般而言,最常見的寫日志的方法是直接使用console.log
蚯妇,
但是我們發(fā)現(xiàn)敷燎,控制臺(tái)還輸出了其他的文本,
我們很難找到自己輸出的信息箩言。
為了展示方便硬贯,我決定使用 debug 模塊來(lái)輸出信息,
它是一個(gè)日志庫(kù)陨收,可以用顏色來(lái)區(qū)分不同的日志饭豹,
看看github倉(cāng)庫(kù)中的官方截圖,
2.1 安裝debug為devDependencies
./bin/webpack.js 位于 ~/Test/debug-webpack/node_modules/_webpack@4.20.2@webpack 文件夾中务漩,
我們進(jìn)入這個(gè)文件夾拄衰,然后安裝debug,
$ cd ~/Test/debug-webpack/node_modules/_webpack@4.20.2@webpack
$ npm i -D debug
2.2 使用debug
在 ./bin/webpack.js 文件頭部調(diào)用debug饵骨,這里我們創(chuàng)建了一個(gè)log
變量翘悉。
#!/usr/bin/env node
const log = require('debug')('debug-webpack webpack webpack.js');
...
記得要放到 #!/usr/bin/env node
后面,
其中第二個(gè)參數(shù)debug-webpack webpack webpack.js
稱為namespace 居触,可用于區(qū)分日志的顏色镐确,
這里我們?yōu)檎麄€(gè)文件使用了相同的namespace。
2.3 bin/webpack.js 代碼邏輯
通過(guò)閱讀 ./bin/webpack.js 源碼饼煞,我們發(fā)現(xiàn)源葫,
它首先會(huì)對(duì)已安裝的CLI進(jìn)行檢查,然后會(huì)載入安裝的CLI工具砖瞧。
webpack要求我們必須安裝webpack-cli 或 webpack-command 之一息堂,否則就會(huì)報(bào)錯(cuò)。
if (installedClis.length === 0) {
// 報(bào)錯(cuò)
}
源碼位置如下:https://github.com/webpack/webpack/blob/v4.20.2/bin/webpack.js#L84
如果我們已經(jīng)安裝了某一個(gè)CLI的話,就會(huì)加載這個(gè)CLI荣堰,源碼第149-159行床未,
else if (installedClis.length === 1) {
const path = require("path");
const pkgPath = require.resolve(`${installedClis[0].package}/package.json`);
// eslint-disable-next-line node/no-missing-require
const pkg = require(pkgPath);
// eslint-disable-next-line node/no-missing-require
require(path.resolve(
path.dirname(pkgPath),
pkg.bin[installedClis[0].binName]
));
}
注意以上代碼第7
行,webpack動(dòng)態(tài) require
了一個(gè)地址振坚,
這時(shí)候我們的log
工具就有用武之地了薇搁。
const cliPath = path.resolve(path.dirname(pkgPath), pkg.bin[installedClis[0].binName]);
log('cliPath: %s', cliPath);
require(cliPath);
2.3 查看日志
直接按原樣調(diào)用npm run build
是看不到剛才寫入的日志信息的,
我們還需要傳入前置參數(shù)渡八,
$ DEBUG=debug-webpack* npm run build
The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described > in Shell Parameters. These assignment statements affect only the environment seen by that command.
—— Bash Reference Manual - 3.7.4 Environment
其中名為DEBUG
的前置參數(shù)啃洋,是 debug 模塊所需要的,
debug-webpack*
表示我們要輸出所有以debug-webpack
開頭namespace中的日志屎鳍。
我們示例中宏娄,namespace是debug-webpack webpack webpack.js
。
運(yùn)行結(jié)果如下逮壁,
debug-webpack webpack webpack.js cliPath: ~/Test/debug-webpack/node_modules/_webpack-cli@3.1.2@webpack-cli/bin/cli.js +0ms
3. webpack-cli/bin/cli.js
上文中我們得到了webpack require
的CLI地址孵坚,
~/Test/debug-webpack/node_modules/_webpack-cli@3.1.2@webpack-cli/bin/cli.js
源碼位于,https://github.com/webpack/webpack-cli/blob/v3.1.2/bin/cli.js
webpack-cli版本為 v3.1.2窥淆。
分析源碼我們發(fā)現(xiàn)卖宠,代碼中第436行require
了webpack
模塊,
https://github.com/webpack/webpack-cli/blob/v3.1.2/bin/cli.js#L436
const webpack = require("webpack");
隨后在第441行忧饭,調(diào)用webpack
逗堵,返回了一個(gè)compiler
,
https://github.com/webpack/webpack-cli/blob/v3.1.2/bin/cli.js#L441
compiler = webpack(options);
最后眷昆,在第533行蜒秤,調(diào)用了compiler.run
,
https://github.com/webpack/webpack-cli/blob/v3.1.2/bin/cli.js#L533
} else compiler.run(compilerCallback);
4. 開始debug
知道了webpack-cli的代碼邏輯之后亚斋,我們就可以創(chuàng)建一個(gè)debug.js腳本來(lái)模擬webpack-cli調(diào)用了作媚,
在我們上一篇debug-webpack示例項(xiàng)目中,添加一個(gè)./debug.js 文件帅刊,
const webpack = require('webpack');
const options = require('./webpack.config');
const compiler = webpack(options);
compiler.run((...args) => {
console.log(...args);
});
保持這個(gè)文件打開狀態(tài)纸泡,在以上代碼第6
行位置打個(gè)斷點(diǎn),
然后在vscode中按 F5
(或者點(diǎn)擊左側(cè)調(diào)試面板赖瞒,再點(diǎn)擊調(diào)試)女揭。
代碼就停在我們的斷點(diǎn)位置上了。
然后我們可以點(diǎn)擊左數(shù)第3個(gè)按鈕栏饮,進(jìn)行單步調(diào)試吧兔,就可以進(jìn)入compiler.run
方法中了。
參考
github: debug
github: webpack v4.20.2 ./bin/webpack.js
github: webpack-cli v3.1.2 ./bin/cli.js
Debugging in Visual Studio Code