webpack 的文件監(jiān)聽
文件監(jiān)聽是在源碼發(fā)生變化時,自動重新構(gòu)建出新的輸出文件。
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 中設(shè)置
watch: true
但是,這種方式需要每次手動刷新瀏覽器
webpack文件監(jiān)聽的原理
webpack會輪詢判斷文件的最后編輯時間是否變化。
某個文件發(fā)生了變化,并不會立即告訴監(jiān)聽者,而是先緩存起來,等 aggregateTimeout
module.exports = {
// 默認(rèn)是false,即不開啟
watch: true,
// 只有開啟監(jiān)聽模式時,watchOptions才有意義
watchOptions: {
// 默認(rèn)為空,不監(jiān)聽的文件或者文件夾,支持正則匹配
ignored: /node_modules/,
// 監(jiān)聽到變化發(fā)生后會等300ms再去執(zhí)行,默認(rèn)300ms
aggregateTimeout: 300,
// 判斷文件是否發(fā)生變化是通過不停詢問系統(tǒng)指定文件有沒有變化實現(xiàn)的,默認(rèn)每秒問1000次
poll: 1000
},
};
熱更新
使用webpack-dev-server
安裝依賴
npm i -D webpack-dev-server
- WDS 不刷新瀏覽器
- WDS 不輸出文件,而是放在內(nèi)存中
- 使用 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ā)過程中使用,生產(chǎn)環(huán)境是用不到的,所以我們將mode改為development,然后再引入webpack自帶的Hot ModuleReplacementPlugin插件,由于該插件是內(nèi)置的,所以我們先引入webpack,再將插件加進來,最后還要配置一下devServer。
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist', // 服務(wù)的基礎(chǔ)目錄
hot: true // 開啟熱更新
}
};
升級填坑
但是,當(dāng)你升級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輸出的文件傳輸給服務(wù)器,適用于靈活的定制場景。
使用這種方式,通常需要再引入一個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:提供文件在瀏覽器的訪問,可以讓你的文件以服務(wù)器的方式訪問,比如“http://localhost:8080/search.html”
-
HMR Runtime:會被注入到瀏覽器端的
bundle.js里面,bundle.js就可以與服務(wù)器建立一個連接,通常這個連接是一個websocket,當(dāng)它收到一些數(shù)據(jù),一些回包之后,就會自動更新文件 - bundle.js:構(gòu)建輸出的文件
熱更新的過程
-
啟動階段,是在文件系統(tǒng)里面,文件系統(tǒng)的一個編譯,就是將初始的代碼經(jīng)過
Webpack Compile進行一個打包,打包好以后,將打包好的文件傳輸給bundle server,也就是一個服務(wù)器,bundle server就可以讓這個文件以server的方式讓瀏覽器訪問到 -
更新階段,如果本地開發(fā)時,有文件發(fā)生了變化,這時的流程是一個文件系統(tǒng)的變化,然后代碼還是會經(jīng)過
Webpack Compile進行編譯,編譯好以后會將代碼發(fā)送給HMR Server,HMR Server就可以知道哪些模塊(源代碼部分的模塊)發(fā)生了變化,然后HMR Server就會通知HMR runtime(HMR Server是在服務(wù)端,HMR runtime是在客戶端)。通常是以json的格式進行數(shù)據(jù)傳輸,傳遞給HMR runtime之后,HMR runtime就會更新我們的代碼,最后我們的代碼進行了改變,并且不需要刷新瀏覽器。