webpack-dev-server

570 阅读3分钟

一、介绍

webpack-dev-server就是一个小型的静态文件服务器。使用它,可以为webpack打包生成的资源文件提供Web服务

webpac-dev-server支持Hot Module Replacement,即模块热替换,在前端代码变动的时候无需整个刷新页面,只把变化的部分替换掉。
浏览器通过 websocket 和 webpack-dev-server 进行通信

二、流程

1、HotModuleReplacementPlugin插件

引入

const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');
module.exports = {  
    // ...
    plugins: [        
       new HotModuleReplacementPlugin()
    ],
  }

在重新打包后会生成两个补丁文件

  • hash.hot-update.json 上次编译更改文件清单manifest
  • hash.hot-update.js 这里调用了全局方法webpackHotUpdate函数(父文件module.hot.accept注册的更新函数)

2、服务端server(hmrServer)

监听webpack done事件

compiler.hooks.done.tap

创建websocket服务器

收集clientSocketList,在webpack done事件通知client

3、客户端client(bundleServer)

创建express服务器

返回dist下文件

父文件添加更新逻辑

module.hot.accept([child.js],updateFn)

hotCreateModule

compiler.hooks.moduleRequire.tap()改写require函数,往module注入hot相关逻辑

function hotCreateModule() {
        var hot = {
            accept: function (dep, callback) {
                for (var i = 0; i < dep.length; i++)
                    hot._acceptedDependencies[dep[i]] = callback;
            },//收集子模块的更新
            check: hotCheck,//编译更新socket接收更新
            apply:hotApply,//更新逻辑
        };
        return hot;
    }

socket接收更新通知,xhr请求express服务获取补丁

hotEmitter.on("webpackHotUpdate", (hash) => {
    hotCheck();
})

补丁js调用webpackHotUpdate

最终调用hotApply来更新,主要逻辑如下:

newModule.parents && newModule.parents.forEach(parentID => {
            let parentModule = __webpack_require__.c[parentID];
            parentModule.hot._acceptedDependencies[moduleID] && parentModule.hot._acceptedDependencies[moduleID]()
        });

参考 从零实现webpack热更新HMR

三、原理

image.png

通过webpack-dev-server创建两个服务器:提供静态资源的服务express(bundle server)和Socket服务(hmr server)

  • bundle server. 负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
  • socket server. 【hmr server与hmr runtime】是一个 websocket 的长连接,双方可以通信
    当模块发生变化时,webpack监听到后重新编译,生成唯一hash值,会生成manifest.json(含chunkid与hash)和chunk.js文件
    通过长连接,hmr server向浏览器推送manifest,浏览器通过ajax获取变化后的js文件
    浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块触发render流程。

参考地址:webpack热更新原理

四、插件

1. Webpack-dev-middleware

让webpack以watch模式编译;

并将文件系统改为内存文件系统,不会把打包后的资源写入磁盘而是在内存中处理;

中间件负责将编译的文件返回;

2. webpack-dev-server

Webpack-Dev-Server 就是内置了 Webpack-dev-middleware 和 Express 服务器,以及利用websocket替代eventSource实现webpack-hot-middleware的逻辑

3. Webpack-hot-middleware:

提供浏览器和 Webpack 服务器之间的通信机制、且在浏览器端订阅并接收 Webpack 服务器端的更新变化,然后使用webpack的HMR API执行这些更改

4. HotModuleReplacementPlugin

向应用的主 Chunk 注入一系列 HMR Runtime,通过改写require在module上增加了hot属性。包括:

  • 用于建立 WebSocket 连接,处理 hash 等消息的运行时代码
  • 用于加载热更新资源。调用 AJAX 向服务端请求是否有更新的文件,如果有将发更新的文件列表返回浏览器端; 请求最新的模块代码,然后将代码返回给 HMR runtime,HMR runtime 会根据返回的新模块代码做进一步处理,可能是刷新页面,也可能是对模块进行热更新
  • 用于处理模块更新策略的 module.hot.accept 接口

欢迎关注我的前端自检清单,我和你一起成长