美文网首页Front End
[FE] webpack群侠传(三):log + debug

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

作者: 何幻 | 来源:发表于2018-10-24 18:43 被阅读15次

    学习源码的一个好办法就是,跟进源码的逻辑中,看看流程是怎么样流转的,
    这需要我们有直接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

    相关文章

      网友评论

        本文标题:[FE] webpack群侠传(三):log + debug

        本文链接:https://www.haomeiwen.com/subject/jzjxtqtx.html