最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 以尽可能通俗易懂的方式看懂webpack-dev-server的热更新

    正文概述 掘金(last_order)   2021-03-02   759

    背景

    传统开发页面,每次更新的时候需要我们手动刷新浏览器才会更新。自从构建工具横空出世。我们可以通过热更新的方式来进行更新。通称HMR(hot module replacement),也就是模块热替换,当你每次需要更新代码的时候,不在需要手动刷新即可实现效果预览。

    前置知识

    探究热更新是怎么实现之前,我们需要知道几样东西

    • sockjs
    • webpack.HotModuleReplacementPlugin
    • memory-fs
    • webpack-dev-middleware
    • webpack一些知识和一些底层知识,否则你估计会看不懂,并且属于懵逼状态,对于一些东西都给出了链接
    • Compiler事件流

    memory-fs

    内存文件系统,webpack默认生成的文件会丢到内存中,并不会直接写入硬盘

    webpack.HotModuleReplacementPlugin

    中文文档

    英文文档

    这个是HMR实现核心,由webpack内部所提供的一个插件,该插件会提供一些方法,用于检查变更,并告诉你每次变更所生成的文件hash

    sockjs

    用于发送socket请求,通知浏览器进行更改

    webpack-dev-middleware

    webpack-dev-middleware会接收一个webpack所返回的一个compiler对象,然后调用compiler.watch监听文件更改,

    我们知道webpack热更新的时候,并不会写入硬盘中,这是因为默认的情况下是写入内存的,因为内存的读取速度比硬盘会快很多,我们可以通过devServer.writeToDisk来修改

    if (options.writeToDisk) {
        // 写入硬盘
    } else {
        // 写入内存,并设置内存中的路径为当前路径
        const memoryFs = new MemoryFs()
    }
    

    这样我们就可以知道文件是否更改,并且把文件存在了内存中,现在在回到webpack-dev-server

    HMR是怎么实现的

    这里用webpack-dev-server进行举例,所有热更新原理基本类似。手写我们实现一个简单的webpack配置文件。

    const path = require('path')
    const webpack = require('webpack')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    module.exports = {
        entry: './src/index.js',
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: 'main.js'
        },
        devServer: {
            host: 'localhost',
            contentBase: path.resolve(__dirname, 'src')
            port: 8080,
            hot: true,
            open: true
        },
        plugins: [
            new webpack.HotModuleReplacementPlugin(),
            new HtmlWebpackPlugin({
                template: './src/pages/index.html',
                filename: 'index.html'
            })
        ]
    }
    

    简单实现

    以尽可能通俗易懂的方式看懂webpack-dev-server的热更新 这是一个简单的流程图,不涉及任何复杂逻辑,这图中我们需要关注几个问题

    1. 为什么需要启动
    2. 为什么需要添加webpack.HotModuleReplacementPlugin
    3. webpack-dev-server怎么知道文件发生了变化
    4. 如何实现更新

    现在我们有了上面的问题,来逐个去看下

    1. 为什么需要webpack.HotModuleReplacementPlugin

    这个是webpack官方所提供的插件,该插件提供了一些方法,当我们启动的时候webpack会给每个文件注入moudle一个对象,这个对象里面有个module.hot对象,具体可以参考中文文档,并且webpack每次重新构建的时候会生成一个hash,当我们把devServer.writeToDisk设置为true的时候,每次更改还会生成这2个文件。

    • hot-update.js是每次需要更新的文件
    • hot-update.json下次更新需要生成的hash
    [id].[fullhash].hot-update.js
    [runtime].[fullhash].hot-update.json
    
    1. webpack-dev-server怎么知道文件发生了变化

    这个问题比较简单,webpack-dev-server启动的时候,初始化了express,并且把expres传递给了webpack-dev-middleware,webpack-dev-middleware也是webpack团队出品,devServer几乎所有api都是通过这个库去实现的。

    webpack构建的时候会返回一个compiler对象,该对象会提供一个watch方法用来监听文件更改,而webpack-dev-middleware就是通过这种方法监听文件更改,webpack.HotModuleReplacementPlugin也是一样的操作。并且每次重新构建的时候webpack-dev-server都会监听compiler的compile、invalid、done方法,会通知socket服务用于是否展示overlay(遮罩层)。

    • compile 在compilation生成之前,compilation是webpack每次重新编译所返回的一个对象
    • invalid 编译失败
    • done 编译成功
    1. 如何实现更新

    webpack-dev-server在启动的时候还会给entry添加2个文件

    webpack-dev-server/clinet/index.js
    webpack/hot/devServer.js // 如果设置了hotonly会注入webpack/hot/only-dev-server
    

    现在我们知道了每次构建所产生的hash,和产生的文件,但这时候还没办法热更新。我们可以记录每次构建所生成的hash,用于判断和当前的hash是否匹配,从而实现热更新,并且通知浏览器进行更新。

    webpack-dev-server/client/index.js负责每次更新的状态,当状态为ok和warinings的时候会执行一个reloadApp方法,该方法会emit一个webpackHotUpdate事件,并把变更的文件hash传递出去,然后webpack/hot/devServer.js负责监听这个事件,当监听到该事件的时候,保存该文件hash,并且判断hash是否已更新并且module.hot.status为idle的时候,执行一个check方法,check会拿到一个需要更新的模块,如果有需要更新,则调用location.reload()方法,进行更新。

    if (module.hot) {
    	var lastHash;
    	var upToDate = function upToDate() {
    		return lastHash.indexOf(__webpack_hash__) >= 0;
    	};
    	var log = require("./log");
    	var check = function check() {
    		module.hot
    			.check(true)
    			.then(function(updatedModules) {
    				if (!updatedModules) {
    					log("warning", "[HMR] Cannot find update. Need to do a full reload!");
    					log(
    						"warning",
    						"[HMR] (Probably because of restarting the webpack-dev-server)"
    					);
    					window.location.reload();
    					return;
    				}
    
    				if (!upToDate()) {
    					check();
    				}
    
    				require("./log-apply-result")(updatedModules, updatedModules);
    
    				if (upToDate()) {
    					log("info", "[HMR] App is up to date.");
    				}
    			})
    			.catch(function(err) {
    				var status = module.hot.status();
    				if (["abort", "fail"].indexOf(status) >= 0) {
    					log(
    						"warning",
    						"[HMR] Cannot apply update. Need to do a full reload!"
    					);
    					log("warning", "[HMR] " + log.formatError(err));
    					window.location.reload();
    				} else {
    					log("warning", "[HMR] Update failed: " + log.formatError(err));
    				}
    			});
    	};
    	var hotEmitter = require("./emitter");
    	hotEmitter.on("webpackHotUpdate", function(currentHash) {
    		lastHash = currentHash;
    		if (!upToDate() && module.hot.status() === "idle") {
    			log("info", "[HMR] Checking for updates on the server...");
    			check();
    		}
    	});
    	log("info", "[HMR] Waiting for update signal from WDS...");
    } else {
    	throw new Error("[HMR] Hot Module Replacement is disabled.");
    }
    

    现在我们已经大概了解了热更新的过程,下面丢个完整流程图进行理解。 以尽可能通俗易懂的方式看懂webpack-dev-server的热更新 上面是webpack5的更新过程,webpack4的时候是通过创建script标签,并插入dom来实现的。

    由于掘金不支持md流程图,所以就只能截图了。所以看上去会有点糊。


    起源地下载网 » 以尽可能通俗易懂的方式看懂webpack-dev-server的热更新

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元