欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

webpack自動(dòng)刷新瀏覽器源碼解析

 更新時(shí)間:2023年02月07日 08:21:50   作者:尼羲  
Webpack自動(dòng)刷新瀏覽器是一項(xiàng)非常實(shí)用的功能,它可以讓開發(fā)者在編輯代碼時(shí),自動(dòng)更新瀏覽器,從而節(jié)省大量的時(shí)間。那么它是如何實(shí)現(xiàn)的呢?

在我們?nèi)粘5那岸碎_發(fā)過程中,在編輯器里只需要保存代碼,瀏覽器就會(huì)自動(dòng)刷新當(dāng)前頁面。這個(gè)過程被稱為熱更新。

其實(shí)實(shí)現(xiàn)這一功能需要兩步:

  • 監(jiān)聽代碼的變化
  • 自動(dòng)刷新瀏覽器

下面看一下這兩個(gè)步驟是如何實(shí)現(xiàn)的。

配置webpack熱更新模式

  • 初識(shí)化項(xiàng)目并導(dǎo)入依賴
npm i webpack webpack-cli -D
npm i webpack-dev-server -D
npm i html-webpack-plugin -D

然后,我們需要弄明白,webpack 從版本 webpack@4 之后,需要通過 webpack CLI 來啟動(dòng)服務(wù),提供了啟動(dòng)開發(fā)服務(wù)的命令。

# 啟動(dòng)開發(fā)服務(wù)器
webpack serve --mode development --config webpack.config.js
// pkg.json
{
"scripts": {
"dev": "webpack serve --mode development --config webpack.config.js",
"build": "webpack build --mode production --config webpack.config.js"
},
"devDependencies": {
"webpack": "^5.45.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2",
"html-webpack-plugin": "^5.3.2",
}
}

在啟動(dòng)開發(fā)服務(wù)的時(shí)候,在 webpack 的配置文件中配置 ??devServe?? 屬性,即可開啟熱更新模式。

// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
devServer: {
hot: true, // 開啟熱更新
port: 8080, // 指定服務(wù)器端口號(hào)
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
}

源碼解析

開啟本地服務(wù)

首先通過webpack創(chuàng)建了一個(gè)compiler實(shí)例,然后通過創(chuàng)建自定義server實(shí)例,開啟了一個(gè)本地服務(wù)。

// node_modules/webpack-dev-server/bin/webpack-dev-server.js

const webpack = require('webpack');

const config = require('../../webpack.config');

const Server = require('../lib/Server')



const compiler = webpack(config);

const server = new Server(compiler);

server.listen(8080, 'localhost', () => {})

這個(gè)自定義Server 不僅是創(chuàng)建了一個(gè)http服務(wù),它還基于http服務(wù)創(chuàng)建了一個(gè)websocket服務(wù),同時(shí)監(jiān)聽瀏覽器的接入,當(dāng)瀏覽器成功接入時(shí)向它發(fā)送hash值,從而實(shí)現(xiàn)服務(wù)端和瀏覽器間的雙向通信。

// node_modules/webpack-dev-server/lib/Server.js

class Server {

constructor() {

this.setupApp();

this.createServer();

}

//創(chuàng)建http應(yīng)用

setupApp() {

this.app = express();

}

//創(chuàng)建http服務(wù)

createServer() {

this.server = http.createServer(this.app);

}

//監(jiān)聽端口號(hào)

listen(port, host, callback) {

this.server.listen(port, host, callback)

this.createSocketServer();

}

//基于http服務(wù)創(chuàng)建websocket服務(wù),并注冊(cè)監(jiān)聽事件connection

createSocketServer() {

const io = socketIO(this.server);

io.on('connection', (socket) => {

this.clientSocketList.push(socket);

socket.emit('hash', this.currentHash);

socket.emit('ok');

socket.on('disconnect', () => {

let index = this.clientSocketList.indexOf(socket);

this.clientSocketList.splice(index, 1)

})

})

}

}



module.exports = Server;

監(jiān)聽編譯完成

僅僅在建立websocket連接時(shí),服務(wù)端向?yàn)g覽器發(fā)送hash和拉取代碼的通知還不夠,我們還希望當(dāng)代碼改變時(shí),瀏覽器也可以接到這樣的通知。于是,在開啟服務(wù)前,還需要對(duì)編譯完成事件進(jìn)行監(jiān)聽。

//監(jiān)聽編譯完成,當(dāng)編譯完成后通過websocket向?yàn)g覽器發(fā)送廣播

setupHooks() {

let { compiler } = this;

compiler.hooks.done.tap('webpack-dev-server', (stats) => {

this.currentHash = stats.hash;

this.clientSocketList.forEach((socket) => {

socket.emit('hash', this.currentHash);

socket.emit('ok');

})

})

}

監(jiān)聽文件修改

要想在代碼修改的時(shí)候,觸發(fā)重新編譯,那么就需要對(duì)代碼的變動(dòng)進(jìn)行監(jiān)聽。這一步,源碼是通過??webpackDevMiddleware???庫實(shí)現(xiàn)的。庫中使用了compiler.watch對(duì)文件的修改進(jìn)行了監(jiān)聽,并且通過??memory-fs??實(shí)現(xiàn)了將編譯的產(chǎn)物存放到內(nèi)存中,這也是為什么我們?cè)赿ist目錄下看不到變化的內(nèi)容,放到內(nèi)存的好處就是為了更快的讀寫從而提高開發(fā)效率。

// node_modules/webpack-dev-middleware/index.js

const MemoryFs = require('memory-fs')

compiler.watch({}, () => {})

let fs = new MemoryFs();

this.fs = compiler.outputFileSystem = fs;

向?yàn)g覽器中插入客戶端代碼

前面提到要想實(shí)現(xiàn)瀏覽器和本地服務(wù)的通信,那么就需要瀏覽器接入到本地開啟的websocket服務(wù),然而瀏覽器本身并不具備這樣的能力,這就需要我們自己提供這樣的客戶端代碼將它運(yùn)行在瀏覽器。因此自定Server在開啟http服務(wù)之前,就調(diào)用了??updateCompiler()??方法,它修改了webpack配置中的entry,使得插入的兩個(gè)文件的代碼可以一同被打包到 main.js 中,運(yùn)行在瀏覽器。

//node_modules/webpack-dev-server/lib/utils/updateCompiler.js

const path = require('path');

function updateCompiler(compiler) {

compiler.options.entry = {

main: [

path.resolve(__dirname, '../../client/index.js'),

path.resolve(__dirname, '../../../webpack/hot/dev-server.js'),

config.entry,

]

}

}

module.exports = updateCompiler

node_modules /webpack-dev-server/client/index.js

這段代碼會(huì)放在瀏覽器作為客戶端代碼,它用來建立 websocket 連接,當(dāng)服務(wù)端發(fā)送hash廣播時(shí)就保存hash,當(dāng)服務(wù)端發(fā)送ok廣播時(shí)就調(diào)用reloadApp()。

let currentHash;

let hotEmitter = new EventEmitter();

const socket = window.io('/');



socket.on('hash', (hash) => {

currentHash = hash;

})

socket.on('ok', () => {

reloadApp();

})



function reloadApp() {

hotEmitter.emit('webpackHotUpdate', currentHash)

}

webpack/hot/dev-server.js

reloadApp()繼續(xù)調(diào)用module.hot.check(),當(dāng)然第一次加載頁面時(shí)是不會(huì)被調(diào)用的。至于這里為啥會(huì)分成兩個(gè)文件,個(gè)人理解是為了解藕,每個(gè)模塊負(fù)責(zé)不同的分工。

let lastHash;

hotEmitter.on('webpackHotUpdate', (currentHash) => {

if (!lastHash) {

lastHash = currentHash;

return;

}

module.hot.check();

})

module.hot.check()是哪來的?答案是??HotModuleReplacementPlugin??。

到此這篇關(guān)于webpack自動(dòng)刷新瀏覽器源碼解析的文章就介紹到這了,更多相關(guān)webpack自動(dòng)刷新瀏覽器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論