14_webpack_devServe
当我们每次修改完成源代码之后都需要重新执行npm run build,这样子的开发效率是非常低下的
解决:通过watch监听源代码的变化
方式一:在build脚本的webpack中添加--watch选项
"build": "webpack --watch"
当我们执行npm run build的时候,线程是阻塞在那里的,当你修改源代码的时候,它会自动构建
方式二:在webpack.config.js中添加watch选项:watch:true,那么就等同于方式一了
目前开发模式:
1.watch方案来监听文件的变化
2:通过live-server插件提供本地服务(当我们文件发生变化时,自动刷新页面)
效率不是特别高:
1.对所有的源代码都重新进行编译
2.编译成功后,都会生成新的文件(文件操作 file-system)
3.live-server属于vscode插件(可能其他的编译器不具备)->不属于webpack给我们的解决方案
4.live-server每次都会重新刷新整个页面
Webpack-dev-serve
安装:
npm i webpack-dev-serve -D
配置:
在package.json中的脚本中配置:
执行命令:
npm run serve
当我们修改源代码的时候,会对所有源代码进行重新编译,然后重新刷新整个页面
通过npm run serve指令,他是不会生成任何文件的
我们通过npm run serve命令,他是会编译代码的,他是把编译后的代码放到内存里面的,直接从内存中去加载性能会更高的
如何通过内存保存所有东西呢?
其实他早期用到了一个memory-fs(内存文件系统)的一个库(不更新了,webpack放弃了)
现在使用的是一个叫memfs库,把编译的文件通过这个库放到了内存里面,读取文件的时候直接在内存中读取性能会更高
当我们使用了webpack-dev-serve,它会先把资源进行构建,然后加入到内存中去,开启一个express服务,把我们请求的资源返回
Webpack-dev-middleware
开发过程中很少定义这个东西
默认情况下,webpack-dev-server已经帮助我们做好了一切;
比如通过express启动一个服务,比如HMR(热模块替换);
如果我们想要有更好的自由度(比如想更换koa),可以使用webpack-dev-middleware;
1.安装:
npm i webpack-dev-middleware express(使用express中间件)
npm i webpack-dev-middleware koa(使用koa中间件)
这里我使用的是express
2.创建server.js
const express = require("express"); const app = express(); app.listen(3000, () => { console.log("服务开启在3000端口"); });
上面的代码可以通过node server.js开启一个服务,但是开启的这个服务肯定是和我们的webpack是没有关系的
所以我们还需要做以下配置
const express = require("express"); const webpack = require("webpack"); const webpackDevMiddleware = require("webpack-dev-middleware"); const app = express(); //加载配置文件 const config = require("./webpack.config.js"); //传入配置信息,webpack根据配置信息进行编译 const compiler = webpack(config); //传给webpack写好的中间件,进行处理,返回express的中间件 const middleware = webpackDevMiddleware(compiler); app.use(middleware); app.listen(3000, () => { console.log("服务开启在3000端口"); });
加载配置信息,把配置信息传给webpack,他会生成compiler的对象,把compiler的对象直接传给我们写好的中间件,它会处理返回给我们一个express的中间件,直接传给express
之后就会对源代码进行编译, 编译好之后,把编译好的东西放到express中间件中
当我们的浏览器去服务里面请求相关资源的时候会根据中间件(middleware)需要返回的数据给你返回
模块热替换(HMR)
Hot Module Replacement
模块热替换是指在 应用程序运行过程中,替换,添加,删除模块,而无需重新刷新整个页面;
通过以下几种方式,来提高开发的速度
不重新加载整个页面,这样可以保留某些应用程序的状态不丢失
只更新需要变化的内容,节省开发的时间
修改了css\js源代码,会立即在浏览器更新,相当于直接在浏览器的devtools中直接修改样式
怎么使用HMR
首先不能使用webpack的watch选项和webpack-dev-middleware
使用webpack-dev-serve启动服务,因为wds里面已经帮助我们封装好了HMR所需要的技术
然后就是修改一个配置:webpack.config.js中添加一个devServer选项(专门为wds的配置),然后在里面添加一个指hot:true
// 专门为webpack-dev-serve devServer: { hot: true, },
停掉当前的服务重新 npm run serve(每次修改完webpack.config.js都需要重新跑)
有这个提示就代表开启了HMR
但是你会发现,当我们修改了某个一模块的时候,依然是刷新整个页面的
这是因为我们需要去指定哪些模块发生更新时,进行HMR
import "./math"; console.log("Hello 1237778887"); console.log("abc"); if (module.hot) { /* 1.依赖(当前哪个模块发生变化的时候,你想去使用HMR,可以些多个或者数组), 2.当模块更新之后,做的一些操作,当模块发生更新的时候,它会去回调这个参数 */ module.hot.accept("./math.js", () => { console.log("math Update..."); }); }
这样子太麻烦了,如果有很多模块我都需要去每个都指定
Vue中的HMR
比如Vue项目,我们修改了组件,希望进行更新,这个时候应该如何去操作
社区已经帮我们解决了这个问题
Vue中我们使用vue-loader,此loader支持Vue组件的HMR,开箱即用
HMR的原理
webpack-dev-serve会创建两个服务:提供静态资源的服务(express)和Socket服务(net.Socket)
express server负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
HMR SocketServer,是一个socket的长连接
长链接有一个最好的好处是建立连接后双方可以通信,服务器可以直接发送文件到客户端
当服务器监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk)
通过长连接可以直接将这两个文件主动发送给客户端(浏览器)
浏览器拿到这两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新