细说webpack-dev-server --inline --progress --config build/webpack.dev.conf.js的一二三

发布于:2023-01-22 ⋅ 阅读:(727) ⋅ 点赞:(0)

直奔主题,在node中的loader.js 调用 cli.js,在cli.js中包括以下引用

const { checkForBrokenNode, checkForUnsupportedNode } = require('./utils/unsupported.js')
const exitHandler = require('./utils/exit-handler.js')
const Npm = require('./npm.js')
const log = require('./utils/log-shim.js')
const replaceInfo = require('./utils/replace-info.js')
const updateNotifier = require('./utils/update-notifier.js')

小TIPS:对于这种require的引用,因为不同的文件依赖很多,有时候一步步查看会逐渐偏离主线。可以在 internal/modules/cjs/helpers.js 下的

require=function(path){
    mod.require(path);
}

的部分添加断点调试,使用单步跳出就可以直接定位到当前调用它的位置。

在cli.js中执行到 await npm.exec(cmd,npm.argv) 这一步比较关键,可以得到 cmd 的值是 run,而 npm.argv 的值是 dev。当执行完之后,会发现再次跳入了loader.js 下的 Module.runMain 但是这一次对应的参数变成了 dev 之后的 webpack-dev-server 对应的参数。也就是说从npm、npm-cli的处理流程结束,进入了webpack-dev-server的分析过程。

这个过程从vscode调试窗口中的调用堆栈上也能看到蛛丝马迹,如下:
在这里插入图片描述
接下来我们抛开require中通过node调用c++实现函数调用的过程,来直接步入webpack.dev.server.js的逻辑中。首先来看一下webpack.dev.server.js通过使用require引用的依赖图,如下:

在这里插入图片描述

以这个骨架图为依据,可以对webpack.dev.server.js的依赖关系能够一目了然。梳理除外部业务和内部业务,通过这种方式确定范围,有助于各个击破。

这里与要特别提到的一个是上图中的yargs。要明白的是yargs在这里承担的任务是什么?它的主要目的是解析在命令行中输入的参数,能够让我们更专注的处理业务,而不是去拆分获取命令行中输入的内容。如下图,在yargs.js中的parseArgs方法中对参数的解析和赋值过程:

在这里插入图片描述

这里弹窗的四个参数对应的就是,package.json 下的 webpack-dev-server --inline --progress --config build/webpack.dev.conf.js。中webpack-dev-server后的四个参数。

小TIPS:如果对于深耕webpack中的Loader加载器、rules、plugins的前奏中的require的实现过程不清晰的情况下,就会导致很容易陷入某个单个模块的具体逻辑中无法抽身。最终没有办法从全局掌握webpack的主线。

明确上述的yargs的使用目的之后,回到 webpack-dev-server.js中的如下位置:

在这里插入图片描述

从上图可以明确,在webpack-dev-server.js中通过require调用模块 webpack/bin/convert-arg ,在这里会读取配置文件的路径,如下:
在这里插入图片描述

到这一步require完成之后,--config ./build/webpack.conf.dev.js 这个命令行中配置项的内容才被读取进入内存,称为当前的 wpOpt 常量,如下:

在这里插入图片描述

到这一步才是我们熟悉的工程下配置文件中的 context、devServer、devtool、entry、module、node、output、plugins、resolve。而在这之前笔者用了6个篇幅的文章来打基础。

总的来说,之前的内容说的都是从npm运行开始,到加载工程中配置的webpack.dev.conf.js的过程。

如果参数读取之后端口不为空的情况下,将会启动开发服务器,如下的webpack-dev-server.js中的内容:

function processOptions(webpackOptions) {
  ...
  if (options.port != null) {
    startDevServer(webpackOptions, options);
    return;
  }
  ...
}
function startDevServer(webpackOptions, options) {
  addDevServerEntrypoints(webpackOptions, options);
}

在前面的依赖图中可以看到,addDevServerEntrypoints ../lib/util/addDevServerEntrypoints,如下:

...
module.exports = function addDevServerEntrypoints(webpackOptions, devServerOptions, listeningApp) {
  if (devServerOptions.inline !== false) {
    ...
    const prependDevClient = (entry) => {
      if (typeof entry === 'function') {
		...
      }
      if (typeof entry === 'object' && !Array.isArray(entry)) {
		...
      }
	  ...
    };

    [].concat(webpackOptions).forEach((wpOpt) => {
      wpOpt.entry = prependDevClient(wpOpt.entry);
    });
  }
};

从这一段代码中就能够看出来,在配置文件中,对于 entry 入口的配置,可以确定,它支持的方式有:function、object,这两种。(注:可能这就是读源码带来的好处吧,它不仅仅像入门书那样直接告诉你entry的用法和配置,而不知道原有。那么这该死的代码就能让我们清晰可见)


网站公告

今日签到

点亮在社区的每一天
去签到