webpack 模块热替换原理


Posted in Javascript onApril 09, 2018

全称是Hot Module ReplaceMent(HMR),理解成热模块替换或者模块热替换都可以吧,和.net中的热插拔一个意思,就是在运行中对程序的模块进行更新。这个功能主要是用于开发过程中,对生产环境没有任何帮助(这一点区别.net热插拔)。效果上就是界面的无刷新更新。

HMR基于WDS,style-loader可以通过它来实现无刷新更新样式。但是对于JavaScript模块就需要做一点额外的处理,怎么处理继续往下看。因为HMR是用于开发环境的,所以我们修改下配置,做两份准备。一个用于生产,一个用于开发。

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

const PATHS = {
 app: path.join(__dirname, 'app'),
 build: path.join(__dirname, 'build'),
};

const commonConfig={
 entry: {
  app: PATHS.app,
 },
 output: {
  path: PATHS.build,
  filename: '[name].js',
 },
 plugins: [
  new HtmlWebpackPlugin({
   title: 'Webpack demo',
  }),
 ],
}
 
function developmentConfig(){
 const config ={
  devServer:{
   //使能历史记录api
   historyApiFallback:true,
    hotOnly:true,//关闭热替换 注释掉这行就行
    stats:'errors-only',
   host:process.env.Host,
   port:process.env.PORT,
   overlay:{
    errors:true,
    warnings:true,
   }
  },
   plugins: [
   new webpack.HotModuleReplacementPlugin(),
  ],
 };
  return Object.assign(
  {},
  commonConfig,
  config,
  {
   plugins: commonConfig.plugins.concat(config.plugins),
  }
 );
}

module.exports = function(env){
 console.log("env",env);
 if(env=='development'){
  return developmentConfig();
 }
  return commonConfig;
};

这个webpack.config.js建立了两个配置,一个是commonConfig,一个是developmentConfig 两者通过env参数来区分,但这个env参数是怎么来的呢?我们看看之前的package.json中的一段:

webpack 模块热替换原理

也就是说,如果按照上面的这个配置,我们通过npm start 启动的话,进入的就是开发环境配置,如果是直接build,那么就是生产环境的方式。build方式是第一节里面讲的 直接通过npm启动webpack,这就不带WDS了。另外有了一个Object.assign语法,将配置合并。这个时候通过npm start启动,控制台打印出了两条日志。

webpack 模块热替换原理

看起来HRM已经启动了。但是此时更新一下component.js

webpack 模块热替换原理

日志显示没有东西被热更新。而且这个39,36代表的是模块Id,看起来很不直观,这里可以通过一个插件使其更符合人意

plugins: [
   new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
  ],

这个时候再启动。

webpack 模块热替换原理

这样名称就直观了。但是我们期待的更新还是没有出来。因为需要实现一个接口

import component from './component';
let demoComponent=component();
document.body.appendChild(demoComponent);

//HMR 接口
if(module.hot){
  module.hot.accept('./component',()=>{
    const nextComponent=component();
    document.body.replaceChild(nextComponent,demoComponent);
    demoComponent=nextComponent;
  })
}

并修改component.js:

export default function () {
 var element = document.createElement('h1');
 element.innerHTML = 'Hello webpack';
 return element;
}

webpack 模块热替换原理

这个时候页面更新了。每次改动页面上都会增加一个带有hot-update.js ,类似于下面这样:

webpackHotUpdate(0,{

/***/ "./app/component.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony default export */ __webpack_exports__["default"] = function () {
 var element = document.createElement('h1');
 element.innerHTML = 'Hello web ';
 element.className='box';
 return element;
};

/***/ })

})

通过webpackHotUpdate对相应模块进行更新。0表示模块的id,"./app/component.js"表示模块对应的name。结构是webpack(id,{key:function(){}})。function外带了一个括号,不知道有什么作用。webpackHotUpdate的定义是这样的:

this["webpackHotUpdate"] = 
 function webpackHotUpdateCallback(chunkId, moreModules) { // eslint-disable-line no-unused-vars  
     hotAddUpdateChunk(chunkId, moreModules);
    if(parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules);
  } ;

小结:从结构来看,一个是id,一个是对应修改的模块。但实际执行更新的是hotApply方法。热更新整个机制还是有点复杂,效果上像MVVM的那种绑定。有兴趣的可以深入研究下。不建议在生产使用HMR,会让整体文件变大,而且对生成没有什么帮助,在下一节会讲样式的加载,style-loader就是用到了HMR。但对于js模块还要写额外的代码,这让人有点不爽。

demo:webpack-ch3_3water.rar

参考:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
juqery 学习之五 文档处理 插入
Feb 11 Javascript
IE网页js语法错误2行字符1、FF中正常的解决方法
Sep 09 Javascript
Js实现滚动变色的文字效果
Jun 16 Javascript
jquery实现的美女拼图游戏实例
May 04 Javascript
js基于面向对象实现网页TAB选项卡菜单效果代码
Sep 09 Javascript
JS中innerHTML和pasteHTML的区别实例分析
Jun 22 Javascript
Bootstrap学习系列之使用 Bootstrap Typeahead 组件实现百度下拉效果
Jul 07 Javascript
Bootstrap框架结合jQuery仿百度换肤功能实例解析
Sep 17 Javascript
Javascript中的神器——Promise
Feb 08 Javascript
vue实现移动端图片裁剪上传功能
Aug 18 Javascript
Vue-cli创建项目从单页面到多页面的方法
Sep 20 Javascript
解决vue prop传值default属性如何使用,为何不生效的问题
Sep 21 Javascript
Angular5升级RxJS到5.5.3报错:EmptyError: no elements in sequence的解决方法
Apr 09 #Javascript
浅谈webpack 自动刷新与解析
Apr 09 #Javascript
webpack 插件html-webpack-plugin的具体使用
Apr 09 #Javascript
详解webpack 入门与解析
Apr 09 #Javascript
vue技术分享之你可能不知道的7个秘密
Apr 09 #Javascript
一步步教会你微信小程序的登录鉴权
Apr 09 #Javascript
vue组件详解之使用slot分发内容
Apr 09 #Javascript
You might like
php如何获取文件的扩展名
2015/10/28 PHP
PHP验证码生成原理和实现
2016/01/24 PHP
TNC vs IO BO3 第二场2.13
2021/03/10 DOTA
JS 非图片动态loading效果实现代码
2010/04/09 Javascript
js编写trim()函数及正则表达式的运用
2013/10/24 Javascript
利用jquery写的左右轮播图特效
2014/02/12 Javascript
捕获和分析JavaScript Error的方法
2014/03/25 Javascript
jquery实现倒计时功能
2015/12/28 Javascript
JavaScript事件处理的方式(三种)
2016/04/26 Javascript
JavaScript实现类似拉勾网的鼠标移入移出效果
2016/10/27 Javascript
一个非常好用的文字滚动的案例,鼠标悬浮可暂停[两种方案任选]
2016/12/01 Javascript
微信小程序图片自适应支持多图实例详解
2017/06/21 Javascript
使用express搭建一个简单的查询服务器的方法
2018/02/09 Javascript
Vue使用mixins实现压缩图片代码
2018/03/14 Javascript
VSCode搭建React Native环境
2020/05/07 Javascript
jQuery实现评论模块
2020/08/19 jQuery
[01:00:49]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第二场 1月31日
2021/03/11 DOTA
python采用getopt解析命令行输入参数实例
2014/09/30 Python
python获取一组汉字拼音首字母的方法
2015/07/01 Python
讲解Python的Scrapy爬虫框架使用代理进行采集的方法
2016/02/18 Python
关于Python中异常(Exception)的汇总
2017/01/18 Python
python中matplotlib的颜色及线条控制的示例
2018/03/16 Python
python对矩阵进行转置的2种处理方法
2019/07/17 Python
利用pandas合并多个excel的方法示例
2019/10/10 Python
DJANGO-URL反向解析REVERSE实例讲解
2019/10/25 Python
python plotly画柱状图代码实例
2019/12/13 Python
Python 中由 yield 实现异步操作
2020/05/04 Python
Blue Nile中国官网:全球知名的钻石和珠宝网络零售商
2020/03/22 全球购物
英国时尚首饰品牌:Missoma
2020/06/29 全球购物
社会实践感言
2014/01/25 职场文书
2014年园林绿化工作总结
2014/12/11 职场文书
初中作文评语集锦
2014/12/25 职场文书
本科毕业论文致谢词
2015/05/14 职场文书
婚宴来宾致辞
2015/07/28 职场文书
Python Parser的用法
2021/05/12 Python
英镑符号 £
2022/02/17 杂记