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

webpack自動刷新瀏覽器源碼解析

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

在我們日常的前端開發(fā)過程中,在編輯器里只需要保存代碼,瀏覽器就會自動刷新當前頁面。這個過程被稱為熱更新。

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

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

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

配置webpack熱更新模式

  • 初識化項目并導入依賴
npm i webpack webpack-cli -D
npm i webpack-dev-server -D
npm i html-webpack-plugin -D

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

# 啟動開發(fā)服務器
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",
}
}

在啟動開發(fā)服務的時候,在 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, // 指定服務器端口號
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
}

源碼解析

開啟本地服務

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

// 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', () => {})

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

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

class Server {

constructor() {

this.setupApp();

this.createServer();

}

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

setupApp() {

this.app = express();

}

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

createServer() {

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

}

//監(jiān)聽端口號

listen(port, host, callback) {

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

this.createSocketServer();

}

//基于http服務創(chuàng)建websocket服務,并注冊監(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連接時,服務端向瀏覽器發(fā)送hash和拉取代碼的通知還不夠,我們還希望當代碼改變時,瀏覽器也可以接到這樣的通知。于是,在開啟服務前,還需要對編譯完成事件進行監(jiān)聽。

//監(jiān)聽編譯完成,當編譯完成后通過websocket向瀏覽器發(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)聽文件修改

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

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

const MemoryFs = require('memory-fs')

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

let fs = new MemoryFs();

this.fs = compiler.outputFileSystem = fs;

向瀏覽器中插入客戶端代碼

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

//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

這段代碼會放在瀏覽器作為客戶端代碼,它用來建立 websocket 連接,當服務端發(fā)送hash廣播時就保存hash,當服務端發(fā)送ok廣播時就調用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ù)調用module.hot.check(),當然第一次加載頁面時是不會被調用的。至于這里為啥會分成兩個文件,個人理解是為了解藕,每個模塊負責不同的分工。

let lastHash;

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

if (!lastHash) {

lastHash = currentHash;

return;

}

module.hot.check();

})

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

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

相關文章

最新評論