webpack 的文件監(jiān)聽
文件監(jiān)聽是在源碼發(fā)生變化時,自動重新構建出新的輸出文件。
webpack開啟監(jiān)聽模式擎场,有兩種方式:
- 啟動 webpack 命令時,帶上 --watch 參數(shù)讳推。
{ "name": "project", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack", "watch": "webpack --watch" }, "keywords": [], "author": "", "license": "ISC", }
- 在配置 webpack.config.js 中設置
watch: true
但是顶籽,這種方式需要每次手動刷新瀏覽器
webpack文件監(jiān)聽的原理
webpack會輪詢判斷文件的最后編輯時間是否變化。
某個文件發(fā)生了變化银觅,并不會立即告訴監(jiān)聽者礼饱,而是先緩存起來,等 aggregateTimeout
module.exports = {
// 默認是false,即不開啟
watch: true,
// 只有開啟監(jiān)聽模式時镊绪,watchOptions才有意義
watchOptions: {
// 默認為空匀伏,不監(jiān)聽的文件或者文件夾,支持正則匹配
ignored: /node_modules/,
// 監(jiān)聽到變化發(fā)生后會等300ms再去執(zhí)行蝴韭,默認300ms
aggregateTimeout: 300,
// 判斷文件是否發(fā)生變化是通過不停詢問系統(tǒng)指定文件有沒有變化實現(xiàn)的够颠,默認每秒問1000次
poll: 1000
},
};
熱更新
使用webpack-dev-server
安裝依賴
npm i -D webpack-dev-server
- WDS 不刷新瀏覽器
- WDS 不輸出文件,而是放在內存中
- 使用 Hot ModuleReplacementPlugin插件
{
"name": "project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --open"
},
"keywords": [],
"author": "",
"license": "ISC",
}
因為WDS主要是在開發(fā)過程中使用榄鉴,生產環(huán)境是用不到的履磨,所以我們將mode
改為development
,然后再引入webpack自帶的Hot ModuleReplacementPlugin
插件庆尘,由于該插件是內置的剃诅,所以我們先引入webpack,再將插件加進來驶忌,最后還要配置一下devServer
矛辕。
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist', // 服務的基礎目錄
hot: true // 開啟熱更新
}
};
升級填坑
但是,當你升級webpack4 ---->webpack5時付魔,如果你的版本是webpack-cli 4*時聊品,就會報錯
Error: Cannot find module 'webpack-cli/bin/config-yargs'
{
"webpack": "^5.36.0",
"webpack-cli": "^4.6.0",
"webpack-dev-server": "^3.11.2"
}
這是,因為在webpack-cli 4*中几苍,作者刪除了config-yargs翻屈,所以會報錯
這里有兩種解決方案:
- 臨時解決方案:將webpack-cli版本降級到webpack-cli 3*
- 終極解決方案:修改配置文件,使用
webpack serve
替代webpack-dev-server
也就是將配置項的"dev": "webpack-dev-server --open"
改為"dev": "webpack serve --open"
使用webpack-dev-middleware
WDM將webpack輸出的文件傳輸給服務器妻坝,適用于靈活的定制場景妖胀。
使用這種方式,通常需要再引入一個server惠勒,一般是express或者koa
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}));
app.listen(3000, function(){
console.log('Example app listening on port 3000!\n');
})
熱更新原理分析
- Webpack Compile(webpack的編譯器):將JS的源代碼編譯成Bundle
-
HMR Server:將熱更新的文件輸出給
HMR Runtime
- Bundle server:提供文件在瀏覽器的訪問赚抡,可以讓你的文件以服務器的方式訪問,比如“http://localhost:8080/search.html”
-
HMR Runtime:會被注入到瀏覽器端的
bundle.js
里面纠屋,bundle.js
就可以與服務器建立一個連接涂臣,通常這個連接是一個websocket
,當它收到一些數(shù)據(jù)售担,一些回包之后赁遗,就會自動更新文件 - bundle.js:構建輸出的文件
熱更新的過程
-
啟動階段,是在文件系統(tǒng)里面族铆,文件系統(tǒng)的一個編譯岩四,就是將初始的代碼經過
Webpack Compile
進行一個打包,打包好以后哥攘,將打包好的文件傳輸給bundle server
剖煌,也就是一個服務器材鹦,bundle server
就可以讓這個文件以server
的方式讓瀏覽器訪問到 -
更新階段,如果本地開發(fā)時耕姊,有文件發(fā)生了變化桶唐,這時的流程是一個文件系統(tǒng)的變化,然后代碼還是會經過
Webpack Compile
進行編譯茉兰,編譯好以后會將代碼發(fā)送給HMR Server
尤泽,HMR Server
就可以知道哪些模塊(源代碼部分的模塊)發(fā)生了變化,然后HMR Server
就會通知HMR runtime
(HMR Server
是在服務端规脸,HMR runtime
是在客戶端)坯约。通常是以json的格式進行數(shù)據(jù)傳輸,傳遞給HMR runtime
之后莫鸭,HMR runtime
就會更新我們的代碼鬼店,最后我們的代碼進行了改變,并且不需要刷新瀏覽器黔龟。