[FE] webpack群侠传(三):log + debug

学习源码的一个好办法就是,跟进源码的逻辑中,看看流程是怎么样流转的,
这需要我们有直接debug代码的能力,
有时候还需要我们在某些关键位置写入log

下面我们从npm run build 命令行工具开始,想办法debug进webpack中,
然后在关键位置写入log。

1. npm scripts

上一篇中,我们在命令行中调用npm run build
源码就被自动的编译打包,然后结果输出到了 ./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]

可是,这到底发生了什么呢?

1.1 npm run build

上一篇中我们在npm scripts配置了npm run build命令,

{
    ...,
    "scripts:": {
        ...,
        "build": "webpack"
    }
    ...,
}

通过查看npm-run-script文档,我们知道,
npm run会自动添加node_module/.bin 到当前命令所用的PATH变量中,
因此,npm run build 实际会调用 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]

与执行npm run build 效果一样。

1.2 显示原身

我在Finder中打开这个文件看了下,发现它是一个软链接(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

这就是我们在node_modules中安装的webpack模块的文件地址。

我们来看看代码,
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仓库的地址,我已经找到了tag为4.20.2的版本位置,
它展示了4.20.2版本的webpack,./bin/webpack.js的源代码。
后文中我们可以使用这样的方式展示源代码了。

1.3 Shebang

我们注意到了,./bin/webpack.js 文件头有一行这样的代码,

#!/usr/bin/env node

它被称为 Shebang

在类Unix系统中,包含Shebang的文本,如果作为可执行文件调用,
#!后面指定的解释器将会被调用,用来执行后面的代码。

Shebang 语法如下,

#!interpreter [optional-arg]

注:
/usr/bin/env 不是一个路径,而是一个命令,
后面跟node 参数,就会找到node并调用它,
我们来试试,

$ /usr/bin/env node --version
v8.12.0

2. 写入日志

上文中,我们了解到,
npm run build最终导致node解释执行了 ./bin/webpack.js 文件。
由于Node.js是解释型语言,所以,我们可以直接修改源码,来查看更改效果。

一般而言,最常见的写日志的方法是直接使用console.log
但是我们发现,控制台还输出了其他的文本,
我们很难找到自己输出的信息。

为了展示方便,我决定使用 debug 模块来输出信息,
它是一个日志库,可以用颜色来区分不同的日志,
看看github仓库中的官方截图,

2.1 安装debug为devDependencies

./bin/webpack.js 位于 ~/Test/debug-webpack/node_modules/_webpack@4.20.2@webpack 文件夹中,
我们进入这个文件夹,然后安装debug,

$ cd ~/Test/debug-webpack/node_modules/_webpack@4.20.2@webpack
$ npm i -D debug

2.2 使用debug

在 ./bin/webpack.js 文件头部调用debug,这里我们创建了一个log变量。

#!/usr/bin/env node
const log = require('debug')('debug-webpack webpack webpack.js');

...

记得要放到 #!/usr/bin/env node 后面,
其中第二个参数debug-webpack webpack webpack.js 称为namespace ,可用于区分日志的颜色
这里我们为整个文件使用了相同的namespace。

2.3 bin/webpack.js 代码逻辑

通过阅读 ./bin/webpack.js 源码,我们发现,
它首先会对已安装的CLI进行检查,然后会载入安装的CLI工具。
webpack要求我们必须安装webpack-cliwebpack-command 之一,否则就会报错。

if (installedClis.length === 0) {
    // 报错
}

源码位置如下:https://github.com/webpack/webpack/blob/v4.20.2/bin/webpack.js#L84

如果我们已经安装了某一个CLI的话,就会加载这个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动态 require了一个地址,
这时候我们的log 工具就有用武之地了。

const cliPath = path.resolve(path.dirname(pkgPath), pkg.bin[installedClis[0].binName]);
log('cliPath: %s', cliPath);
require(cliPath);

2.3 查看日志

直接按原样调用npm run build是看不到刚才写入的日志信息的,
我们还需要传入前置参数

$ 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的前置参数,是 debug 模块所需要的,
debug-webpack* 表示我们要输出所有以debug-webpack 开头namespace中的日志。
我们示例中,namespacedebug-webpack webpack webpack.js

运行结果如下,

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

分析源码我们发现,代码中第436行requirewebpack模块,
https://github.com/webpack/webpack-cli/blob/v3.1.2/bin/cli.js#L436

const webpack = require("webpack");

随后在第441行,调用webpack,返回了一个compiler
https://github.com/webpack/webpack-cli/blob/v3.1.2/bin/cli.js#L441

compiler = webpack(options);

最后,在第533行,调用了compiler.run
https://github.com/webpack/webpack-cli/blob/v3.1.2/bin/cli.js#L533

} else compiler.run(compilerCallback);

4. 开始debug

知道了webpack-cli的代码逻辑之后,我们就可以创建一个debug.js脚本来模拟webpack-cli调用了,
在我们上一篇debug-webpack示例项目中,添加一个./debug.js 文件,

const webpack = require('webpack');
const options = require('./webpack.config');

const compiler = webpack(options);

compiler.run((...args) => {
    console.log(...args);
});

保持这个文件打开状态,在以上代码第6行位置打个断点,
然后在vscode中按 F5(或者点击左侧调试面板,再点击调试)。


代码就停在我们的断点位置上了。

然后我们可以点击左数第3个按钮,进行单步调试,就可以进入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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容