webpack-dev-server HMR内部逻辑

379 阅读1分钟

webpack-dev-server 内置支持了HMR

仅仅通过配置hot hotOnly来开启(或者使用命令行参数 并且命令行参数的优先级更高)

记得在webpack早期版本中开启HMR还是比较繁琐,混乱的,各种的配置方式,有时候也各种不生效。

目前webpack-dev-server@3.11.2版本的内置逻辑

不论是通过命令行启动或者是node api的形式启动webpack-dev-server,都最终初始化了这个类

class Server {
    constructor(compiler, options = {}, _log) {
        ...
        // 这里是添加HMR脚本的入口
        updateCompiler(this.compiler, this.options);
        ...
    }
    
}

updateCompiler

function updateCompiler() {
    // 同时还支持了自动添加HotModuleReplacementPlugin 所以我们的配置中可以忽略
    const findHMRPlugin = (config) => {
      if (!config.plugins) {
        return undefined;
      }

      return config.plugins.find(
        (plugin) => plugin.constructor === webpack.HotModuleReplacementPlugin
      );
    };
    // 真正执行 添加入口的逻辑
    addEntries(webpackConfig, options);
}

addEntries(webpackConfig, options);

function addEntries() {
    ...
    // client端连接到socket服务
    const clientEntry = `${require.resolve(
      '../../client/'
    )}?${domain}${sockHost}${sockPath}${sockPort}`;
    
    // client 负责HMR 或者 live-reload的逻辑
    let hotEntry;

    if (options.hotOnly) {
      hotEntry = require.resolve('webpack/hot/only-dev-server');
    } else if (options.hot) {
      hotEntry = require.resolve('webpack/hot/dev-server');
    }
    
    //其中 下面的这个构建target 都会自动的注入 clientEntry
    const webTarget = [
        'web',
        'webworker',
        'electron-renderer',
        'node-webkit',
        undefined, // eslint-disable-line
        null,
      ].includes(config.target);
      /** @type {Entry} */
      const additionalEntries = checkInject(
        options.injectClient,
        config,
        webTarget
      )
        ? [clientEntry]
        : [];
     // 如果开启hot 注入hotEntry   
     if (hotEntry && checkInject(options.injectHot, config, true)) {
        additionalEntries.push(hotEntry);
      }
    ...
}

注意点 target

参考官方文档:webpack.js.org/configurati…

image.png