浅谈webpack 自动刷新与解析


Posted in Javascript onApril 09, 2018

前端需要频繁的修改js和样式,且需要根据浏览器的页面效果不断的做调整;而且往往我们的开发目录和本地发布目录不是同一个,修改之后需要发布一下;另外一点就是并不是所有的效果都可以直接双击页面就能看到,我们常常需要在本地用nginx建一个站点来观察(自己电脑上ok了才放到测试环境去)。所以如果要用手工刷新浏览器和手动(或点击)发布,还要启动站点,确实是个不小的体力活。而这三点webpack可以帮我们做到。

webpack-dev-serverwebpack

是通过webpack-dev-server(WDS)来实现自动刷新。WDS是一个运行在内存中的开发服务器(一个express)。启动之后,它会检测文件是否发生改变并再自动编译一次。

1.安装

npm install webpack-dev-server --save-dev

先通过npm将其安装到开发目录。安装完成之后会在node_modules/bin下找到。

2.npm启动

然后修改package.json:(基于上一节)

"scripts": {
  "start": "webpack-dev-server --env development",
  "build": "webpack --env production"
 }

现在就可以通过npm run start 或者 npm start来启动了。

浅谈webpack 自动刷新与解析

启动之后,可以看到Project is running at http://localhost:8080 上面。打开页面

浅谈webpack 自动刷新与解析

说明WDS已经帮我们自动建了一个站点.我们修改component.js ,cmd中会出现编译,页面会自动刷新。

浅谈webpack 自动刷新与解析

3.直接启动

官网介绍可以直接通过下面的命令启动WDS。

webpack-dev-server --env development

但会出现webpack-dev-server --env development 不是内部命令的提示,这种问题都是环境变量的问题,将你开发的bin目录设置到环境变量中即可,比如我的目录是‘E:\Html5\node_modules\.bin',就加上分号写在后面。

C:\Users\Administrator.9BBOFZPACSCXLG2\AppData\Roaming\npm;C:\Program Files (x86)\Microsoft VS Code\bin;E:\Html5\node_modules\.bin

浅谈webpack 自动刷新与解析

4.8080端口占用

如果默认的8080端口占用,WDS会换一个。比如用nginx先发布一个。

server{
   listen    8080;
   location / {
      root  E:/Html5/build;
      index index.html index.htm;
    }
  }

再启动WDS:

浅谈webpack 自动刷新与解析

端口切到了8081。也可以手动配置端口:

devServer:{
  //...
  port: 9000
}

nodemon 自动启动

WDS是监视开发文件的,webpack.config.js改变不会引起自动启动。所以我们需要nodemon去做这件事情。

npm install nodemon --save-dev

先安装在开发目录,然后修改package.json:

"scripts": {
  "start": "nodemon --watch webpack.config.js --exec \"webpack-dev-server --env development\"",
  "build": "webpack --env production"
 },

等于让nodemon去监视webpack.config.js,变化了就去启动它。

浅谈webpack 自动刷新与解析

这样就你可以让你的双手专心的开发了。

代理

不过有一点疑问,就是WDS这个站点的替代性,因为我们自己部署的nginx有一些api的代理。如果挂在WDS的这个默认站点上自然是无法访问的。换句话说可否给WDS配置一个刷新路径。如果文件改变去刷新指定的地址,或者让我去配个代理。既然它本身是一个http服务器,肯定也有代理的功能。搜了下果然有:https://github.com/webpack/webpack-dev-server/tree/master/examples/proxy-advanced

module.exports = {
  context: __dirname,
  entry: "./app.js",
  devServer: {
    proxy: {
      "/api": {
        target: "http://jsonplaceholder.typicode.com/",
        changeOrigin: true,
        pathRewrite: {
          "^/api": ""
        },
        bypass: function(req) {
          if(req.url === "/api/nope") {
            return "/bypass.html";
          }
        }
      }
    }
  }
}

即将api这个字段替换成http://jsonplaceholder.typicode.com/,并将其从原地址中删掉,这样就可以自己实现代理了。皆大欢喜!WDS是通过http-proxy-middleware来实现代理。更多参考:http://webpack.github.io/docs/webpack-dev-server.html;https://github.com/chimurai/http-proxy-middleware#options

but,这种刷新是怎么实现的呢?因为页面上没有嵌入什么别的js,去翻原码 web-dev-server/server.js中有这么一段:

Server.prototype._watch = function(path) {
  const watcher = chokidar.watch(path).on("change", function() {
    this.sockWrite(this.sockets, "content-changed");
  }.bind(this))

  this.contentBaseWatchers.push(watcher);
}

用chokidar来监视文件变化,server的内部维护的有一个socket集合:

Server.prototype.sockWrite = function(sockets, type, data) {
  sockets.forEach(function(sock) {
    sock.write(JSON.stringify({
      type: type,
      data: data
    }));
  });
}

sock是一个sockjs对象。https://github.com/sockjs/sockjs-client,从http://localhost:8080/webpack-dev-server/页面来看,sockjs是用来通信记录日志的。

var onSocketMsg = {
  hot: function() {
    hot = true;
    log("info", "[WDS] Hot Module Replacement enabled.");
  },
  invalid: function() {
    log("info", "[WDS] App updated. Recompiling...");
    sendMsg("Invalid");
  },
  hash: function(hash) {
    currentHash = hash;
  },
...
}

我们在看app.js,其中有一个OnSocketMsg 对象。

var onSocketMsg = {
  hot: function() {
    hot = true;
    log("info", "[WDS] Hot Module Replacement enabled.");
  },
  invalid: function() {
    log("info", "[WDS] App updated. Recompiling...");
    sendMsg("Invalid");
  },
  hash: function(hash) {
    currentHash = hash;
  },
  "still-ok": function() {
    log("info", "[WDS] Nothing changed.")
    if(useWarningOverlay || useErrorOverlay) overlay.clear();
    sendMsg("StillOk");
  },
  "log-level": function(level) {
    logLevel = level;
  },
  "overlay": function(overlay) {
    if(typeof document !== "undefined") {
      if(typeof(overlay) === "boolean") {
        useWarningOverlay = overlay;
        useErrorOverlay = overlay;
      } else if(overlay) {
        useWarningOverlay = overlay.warnings;
        useErrorOverlay = overlay.errors;
      }
    }
  },
  ok: function() {
    sendMsg("Ok");
    if(useWarningOverlay || useErrorOverlay) overlay.clear();
    if(initial) return initial = false;
    reloadApp();
  },
  "content-changed": function() {
    log("info", "[WDS] Content base changed. Reloading...")
    self.location.reload();
  },
  warnings: function(warnings) {
    log("info", "[WDS] Warnings while compiling.");
    var strippedWarnings = warnings.map(function(warning) {
      return stripAnsi(warning);
    });
    sendMsg("Warnings", strippedWarnings);
    for(var i = 0; i < strippedWarnings.length; i++)
      console.warn(strippedWarnings[i]);
    if(useWarningOverlay) overlay.showMessage(warnings);

    if(initial) return initial = false;
    reloadApp();
  },
  errors: function(errors) {
    log("info", "[WDS] Errors while compiling. Reload prevented.");
    var strippedErrors = errors.map(function(error) {
      return stripAnsi(error);
    });
    sendMsg("Errors", strippedErrors);
    for(var i = 0; i < strippedErrors.length; i++)
      console.error(strippedErrors[i]);
    if(useErrorOverlay) overlay.showMessage(errors);
  },
  close: function() {
    log("error", "[WDS] Disconnected!");
    sendMsg("Close");
  }
};

ok的时候触发一个reloadApp

function reloadApp() {
  if(hot) {
    log("info", "[WDS] App hot update...");
    var hotEmitter = __webpack_require__("./node_modules/webpack/hot/emitter.js");
    hotEmitter.emit("webpackHotUpdate", currentHash);
    if(typeof self !== "undefined") {
      // broadcast update to window
      self.postMessage("webpackHotUpdate" + currentHash, "*");
    }
  } else {
    log("info", "[WDS] App updated. Reloading...");
    self.location.reload();
  }
}

也就是说WDS先检测文件是否变化,然后通过sockjs通知到客户端,这样就实现了刷新。之前WebSocket的第三方只用过socket.io,看起来sockjs也蛮好用的。不必外带一个js,在主js里面就可以写了。

小结:效率提高的一方面是将一些机械的重复性流程或动作自动化起来。WDS和nodemon就是两个为你干活的小弟。

demo:webpack-ch2_3water.rar

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

Javascript 相关文章推荐
ExtJs默认的字体大小改变的几种方法(自己整理)
Apr 18 Javascript
用jquery中插件dialog实现弹框效果实例代码
Nov 15 Javascript
jquery获取元素索引值index()示例
Feb 13 Javascript
常用的几段javascript代码分享
Mar 25 Javascript
Javascript正则控制文本框只能输入整数或浮点数
Sep 02 Javascript
JavaScript检测弹出窗口是否已经关闭的方法
Mar 24 Javascript
浅析JavaScript的几种Math函数,random(),ceil(),round(),floor()
Dec 22 Javascript
详解Vue.js组件可复用性的混合(mixin)方式和自定义指令
Sep 06 Javascript
JQuery 又谈ajax局部刷新
Nov 27 jQuery
webpack之引入图片的实现及问题
Oct 08 Javascript
vue-cli 打包后提交到线上出现 &quot;Uncaught SyntaxError:Unexpected token&quot; 报错
Nov 06 Javascript
Vue动态生成表格的行和列
Jul 18 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
vue组件中使用props传递数据的实例详解
Apr 08 #Javascript
Vue入门之animate过渡动画效果
Apr 08 #Javascript
You might like
PHP 处理TXT文件(打开/关闭/检查/读取)
2013/05/13 PHP
详解PHP序列化反序列化的方法
2015/10/27 PHP
YII视图整合kindeditor扩展的方法
2016/07/13 PHP
javascript定时变换图片实例代码
2013/03/17 Javascript
jQuery lazyLoad图片延迟加载插件的优化改造方法分享
2013/08/13 Javascript
js获取html页面节点方法(递归方式)
2013/12/13 Javascript
简单实现兼容各大浏览器的js复制内容到剪切板
2015/09/09 Javascript
JS代码实现根据时间变换页面背景效果
2016/06/16 Javascript
Javascript oop设计模式 面向对象编程简单实例介绍
2016/12/13 Javascript
jQuery实现百度登录框的动态切换效果
2017/04/21 jQuery
详解angularjs popup-table 弹出框表格指令
2017/09/20 Javascript
用最少的JS代码写出贪吃蛇游戏
2018/01/12 Javascript
JavaScript简易计算器制作
2020/01/17 Javascript
Python函数嵌套实例
2014/09/23 Python
Python的IDEL增加清屏功能实例
2017/06/19 Python
理解python中生成器用法
2017/12/20 Python
Python logging管理不同级别log打印和存储实例
2018/01/19 Python
Django框架模板注入操作示例【变量传递到模板】
2018/12/19 Python
PyTorch中常用的激活函数的方法示例
2019/08/20 Python
Python测试线程应用程序过程解析
2019/12/31 Python
Python 实现递归法解决迷宫问题的示例代码
2020/01/12 Python
python抢购软件/插件/脚本附完整源码
2021/03/04 Python
HTML5 Canvas概述
2009/08/26 HTML / CSS
ProBikeKit美国官网:自行车套件,跑步和铁人三项套件
2016/10/13 全球购物
美国顶级防滑鞋:Shoes For Crews
2017/03/27 全球购物
高山背包:High Sierra
2017/11/23 全球购物
TUMI马来西亚官方网站:国际领先的高品质商旅箱包品牌
2018/04/26 全球购物
高尔夫球鞋、服装、手套和装备:FootJoy
2018/12/15 全球购物
Camille Jewelry官网:现代女性时尚首饰
2019/07/07 全球购物
保卫科工作岗位职责
2014/03/01 职场文书
市场营销专业大学生职业生涯规划文
2014/03/06 职场文书
项目委托协议书(最新)
2014/09/13 职场文书
网络工程专业大学生求职信
2014/10/01 职场文书
解决numpy和torch数据类型转化的问题
2021/05/23 Python
python异步的ASGI与Fast Api实现
2021/07/16 Python
MySQL普通表如何转换成分区表
2022/05/30 MySQL