前端须要频繁的修改js和样式,且须要根据浏览器的页面效果不断的作调整;并且每每咱们的开发目录和本地发布目录不是同一个,修改以后须要发布一下;另一点就是并非全部的效果均可以直接双击页面就能看到,咱们经常须要在本地用nginx建一个站点来观察(本身电脑上ok了才放到测试环境去)。因此若是要用手工刷新浏览器和手动(或点击)发布,还要启动站点,确实是个不小的体力活。而这三点webpack能够帮咱们作到。html
npm install webpack-dev-server --save-dev
先经过npm将其安装到开发目录。安装完成以后会在node_modules/bin下找到。前端
而后修改package.json:(基于上一节)node
"scripts": { "start": "webpack-dev-server --env development", "build": "webpack --env production" }
如今就能够经过npm run start 或者 npm start来启动了。webpack
启动以后,能够看到Project is running at http://localhost:8080 上面。打开页面nginx
说明WDS已经帮咱们自动建了一个站点.咱们修改component.js ,cmd中会出现编译,页面会自动刷新。git
官网介绍能够直接经过下面的命令启动WDS。github
webpack-dev-server --env development
但会出现webpack-dev-server --env development 不是内部命令的提示,这种问题都是环境变量的问题,将你开发的bin目录设置到环境变量中便可,好比个人目录是‘E:\Html5\node_modules\.bin’,就加上分号写在后面。web
C:\Users\Administrator.9BBOFZPACSCXLG2\AppData\Roaming\npm;C:\Program Files (x86)\Microsoft VS Code\bin;E:\Html5\node_modules\.bin
若是默认的8080端口占用,WDS会换一个。好比用nginx先发布一个。express
server{ listen 8080; location / { root E:/Html5/build; index index.html index.htm; } }
再启动WDS:npm
端口切到了8081。也能够手动配置端口:
devServer:{ //... port: 9000 }
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,变化了就去启动它。
这样就你可让你的双手专心的开发了。
不过有一点疑问,就是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#bypass-the-proxy;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:http://files.cnblogs.com/files/stoneniqiu/webpack-ch2.zip