国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Node.js 熱更新(一)

LancerComet / 2336人閱讀

摘要:直到最近在使用微信機(jī)器人時(shí),遇到了強(qiáng)烈的需求。增刪文件后熱更新上面的代碼已經(jīng)不小心實(shí)現(xiàn)了增加文件后熱更新,因?yàn)楸硎緳z測(cè)的更新,如果增加一個(gè),那么就變成,于是新模塊不等于老模塊不存在,從而使用注冊(cè)事件監(jiān)聽器。

背景

剛思考這個(gè)話題的時(shí)候,首先想到的是 VueReact 的組件熱更新(基于 Webpack HMR),后來又想到了 LuaErlang 等語言的熱更新,不過在實(shí)際開發(fā) Node.js 后臺(tái)時(shí),使用 remy/nodemon 之類的熱重啟(偵測(cè)代碼改動(dòng)重啟程序)工具也夠用,于是 Node.js 的熱更新(替換模塊,無須重啟)的驗(yàn)證就一直擱置。

直到最近在使用「微信機(jī)器人」)(Node.js) 時(shí),遇到了強(qiáng)烈的需求。這類機(jī)器人程序就是:啟動(dòng)了一個(gè)網(wǎng)頁,登錄 Web 微信,通過抓取識(shí)別頁面中的元素獲得一些狀態(tài)信息,如:消息、好友請(qǐng)求等等,由于它的啟動(dòng)時(shí)間也比較長,如果每次修改業(yè)務(wù)代碼后都要重啟,那么等待程序啟動(dòng)就要消耗不少時(shí)間,導(dǎo)致開發(fā)體驗(yàn)很差,于是實(shí)踐 Node.js 的熱更新就迫在眉睫了。

目標(biāo)

以下是機(jī)器人的核心用法:

robot = new Robot()
robot.addEventListener("msg", ...)
robot.removeEventListener("msg", ...)

那么我們的目標(biāo):增/刪/改 業(yè)務(wù)邏輯(事件處理器)的時(shí)候程序無須重啟,自動(dòng)熱更新業(yè)務(wù)邏輯代碼,從而提高開發(fā)效率。

思路一:基于 Webpack 驗(yàn)證可行

從 Webpack Wiki hot module replacement · webpack/docs Wiki 了解到,Webpack 能知道「哪個(gè)模塊需要熱更新」,并提供一些鉤子,另外 webpack 自有一套模塊管理,能夠管理替換模塊,讓你訪問的是熱更新之后的模塊。另外,要實(shí)現(xiàn)熱加載的不僅要滿足「再次加載」,還要考慮如何清空相關(guān)的「持久資源」。

所以說,如果基于 webpack HMR 來實(shí)現(xiàn)的話,需要完成幾件事情:

把事件處理器的代碼模塊化,便于 webpack 管理。

自動(dòng)加載所有處理器模塊

某個(gè)事件處理模塊更新后需要拿到老的模塊,用來移除老的監(jiān)聽處理器。

要知道文件的增加和刪除,并且拿到模塊內(nèi)容。

1. 業(yè)務(wù)代碼模塊化

簡單地把每個(gè)事件處理器定義為一個(gè)文件 *.biz.js

// msg.biz.js
module.exports = {
    evt: "msg",
    fn() {
        console.log("msg hanlder....")
    }
};

其中 evt 是事件名, fn 是處理器,于是加載一個(gè)業(yè)務(wù)模塊后就能拿到事件名稱和處理器。
(可能不滿足實(shí)際要求,先簡單驗(yàn)證熱更新是否可行哈!)

2. 自動(dòng)加載

我們約定,業(yè)務(wù)模塊 *.biz.js 都放在 /biz 目錄下,該目錄下的 index.js 會(huì)加載所有業(yè)務(wù)模塊,而 main.js 就只需加載 /biz/index.js

src
 |--- /biz
       |--- a.biz.js
       |--- b.biz.js
       |--- index.js
          
 |--- main.js
    

借助 webpack 的 require-context 加載所有 *.biz.js 模塊,避免手寫 require:

// index.js
// 加載當(dāng)前目錄下所有 `*.biz.js`
const requireContext = require.context("./", true, /.biz.js/);

// 此時(shí) requireContext.keys() 為 ["./a.biz.js", "./b.biz.js"]
requireContext.keys().forEach(key => {

    const module = requireContext(key);
    // 相當(dāng)于 module = require("./biz/a.biz.js")
    
    // 于是拿到事件名和處理器,然后進(jìn)行事件監(jiān)聽
    // robot.addEventListener(module.evt, module.fn)
    
});
3. 修改后熱更新

參考 Wiki 的例子 Example 3,知道 require.context 如何使用熱更新機(jī)制

// index.js
// 啟動(dòng) webpack HRM 時(shí)則 module.hot 為 true
if (module.hot) {
    // 表示該 context 下的模塊都要檢測(cè)更新
    module.hot.accept(requireContext.id, () => {

        const requireContext = require.context("./", true, /.biz.js/);
        requireContext.keys().forEach(key => {
        
            const newModule = requireContext(key);

            // 前面首次自動(dòng)加載所有模塊后,記錄到 oldModules 對(duì)象()
            // 如果模塊內(nèi)容不一樣,則表示要作熱更新處理了
            if (oldModules[key] !== newModule) {
                   // ... 對(duì)老模塊 oldModules[key] 移除事件監(jiān)聽
                   // ... 對(duì)新模塊 newModule 注冊(cè)事件監(jiān)聽
                    
                    // 同時(shí)更新緩存記錄
                oldModules[key] = newModule;
            }
        });
    });
}

到了這一步,修改任何 *.biz.js 的代碼都能自動(dòng)熱更新了。

4. 增刪文件后熱更新

上面的代碼已經(jīng)不小心實(shí)現(xiàn)了 「增加文件后熱更新」,因?yàn)?module.hot.accept(requireContext.id 表示檢測(cè) ./biz/*.biz.js 的更新,如果增加一個(gè) c.biz.js,那么 requireContext.keys() 就變成 [ ..., "./c.biz.js"],于是新模塊不等于老模塊(不存在),從而使用 c.biz.js 注冊(cè)事件監(jiān)聽器。

對(duì)于刪除文件后的熱更新,則在上面代碼基礎(chǔ)上增加:

    if (module.hot) {
        module.hot.accept(requireContext.id, () => {
            
            // 在重新加載目錄下的所有模塊前,對(duì)老記錄作個(gè)副本
            const oldKeysRetain = {};
            Object.keys(oldModules)
                .forEach(k => (oldKeysRetain[k] = true));

            const requireContext = require.context("./", true, /.biz.js/);
            requireContext.keys().forEach(key => {
            
                  // 如果某模塊存在當(dāng)前目錄,則從臨時(shí)記錄中抹去
                delete oldKeysRetain[key];
                const newModule = requireContext(key);
                if (oldModules[key] !== newModule) {
                   ...
                }
            });

            // 未抹去的部分,意味著不存在當(dāng)前目錄下了,也就是被刪除了
            Object.keys(oldKeysRetain).forEach(key => {
                // ... 對(duì)老模塊移除事件監(jiān)聽
                delete oldModules[key];
            });
        });
    }

經(jīng)過以上四步,算是初步驗(yàn)證了,借助 Webpack 來玩是可以的,當(dāng)然我們作了不少嚴(yán)格約定,不過不影響這一階段的思路。

完整代碼請(qǐng)移步:zhenyong/webpack-hot-nodejs-demo: Webpack HMR demo use in Node.js, showing how to auto add/remove listeners.

思路二:基于 Webpack 進(jìn)階

上面一種思路存在一些問題

業(yè)務(wù)代碼的格式限制太死,不夠靈活

在生產(chǎn)階段也耦合了 webpack

于是我想,約定業(yè)務(wù)代碼格式是為了方便通過模塊管理事件的注冊(cè)和移除,假如說在不侵入代碼,不作任何約定的情況下,也能知道某個(gè)模塊注冊(cè)了哪些事件,是不是就不需約定了,好像是的:

//## a.biz.js 不約定業(yè)務(wù)代碼格式
robot.addLisenter("msg", ...)


//## 入口.js
robot = new Robot();

_add = robot.addLisenter
robot.addLisenter = () => {
    // 攔截注冊(cè)事件方法
    // 從而記錄下 a.biz 模塊都注冊(cè)了哪些事件處理器
}
require("a.biz")
robot.addLisenter = _add

但是問題來了,我們的目標(biāo)包括「自動(dòng)加載所有業(yè)務(wù)模塊,增刪文件都能熱更新」,那么在開發(fā)階段我們還是借助 webpack 的 require.context 方法,并且約定每個(gè)業(yè)務(wù)模塊的入口文件命名為 *.biz.js,至于里面代碼怎么寫就隨意了,而在生產(chǎn)階段可以遍歷文件找到所有 *.biz.js 進(jìn)行加載,無須依賴 webpack。

剩下的大部分思路跟 #思路一 類似,代碼可參考 zhenyong/webpack-hot-nodejs-demo: Webpack HMR demo use in Node.js, showing how to auto add/remove listeners.

更多思路

最開始寫這篇文章是想深扒一下 Node.js 的模塊管理和緩存結(jié)構(gòu),然后驗(yàn)證一下通過清除模塊緩存來做熱更新是否可行,后來感覺 webpack 給我們作了很多工作,于是就先用 webpack 玩了一輪,看來擇日還得再寫一篇(二)了

問題

熱更新的主要目的是為了提高開發(fā)效率,并不是為了在生產(chǎn)上玩熱更新,畢竟還有很多潛在問題,例如,模塊中涉及全局狀態(tài)或者單例資源,通過熱更新可能會(huì)引起混亂......

參考

Webpack 做 Node.js 代碼熱替換, 第一步 - 題葉 - SegmentFault

Backend Apps with Webpack (Part I)

Backend Apps with Webpack: Driving with Gulp (Part II)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/82416.html

相關(guān)文章

  • Node.js 前后端分離開發(fā)新思路

    摘要:從事開發(fā)的程序員,對(duì)于前后端分離模式多半不陌生,這也是目前主流的開發(fā)模式,具體關(guān)于前后端分離的模式可以參看文章你不得不了解的前后端分離原理,在這里寫者不進(jìn)行說明。原理圖如下,前后端在一個(gè)進(jìn)程同一個(gè)端口中,通過熱替換更新的,而不是全量重啟。 從事 Web 開發(fā)的程序員,對(duì)于前后端分離模式多半不陌生,這也是目前主流的 Web 開發(fā)模式,具體關(guān)于前后端分離的模式可以參看文章《你不得不了解的前...

    Lionad-Morotar 評(píng)論0 收藏0
  • 如何打造個(gè)令人愉悅的前端開發(fā)環(huán)境(四)

    摘要:在前后端分離的前端項(xiàng)目開發(fā)中經(jīng)常用到。是的一個(gè)中間件。即是一個(gè)重要的功能。配置先來在配置文件中引入添加一個(gè)和通信的客戶端添加應(yīng)用入口文件在插件中引入在我們的開發(fā)環(huán)境中是這樣配置的。 原文鏈接此文是我同事寫的,搭建Express結(jié)合Webpack。以下是正文,后面我會(huì)附上我的解讀 Express 結(jié)合 Webpack 實(shí)現(xiàn)HMR 本篇文件主要講結(jié)合 Webpack 和 Express 實(shí)...

    StonePanda 評(píng)論0 收藏0
  • 如何打造個(gè)令人愉悅的前端開發(fā)環(huán)境(四)

    摘要:在前后端分離的前端項(xiàng)目開發(fā)中經(jīng)常用到。是的一個(gè)中間件。即是一個(gè)重要的功能。配置先來在配置文件中引入添加一個(gè)和通信的客戶端添加應(yīng)用入口文件在插件中引入在我們的開發(fā)環(huán)境中是這樣配置的。 原文鏈接此文是我同事寫的,搭建Express結(jié)合Webpack。以下是正文,后面我會(huì)附上我的解讀 Express 結(jié)合 Webpack 實(shí)現(xiàn)HMR 本篇文件主要講結(jié)合 Webpack 和 Express 實(shí)...

    animabear 評(píng)論0 收藏0
  • webpack優(yōu)化

    摘要:使用要給項(xiàng)目構(gòu)建接入動(dòng)態(tài)鏈接庫的思想,需要完成以下事情把網(wǎng)頁依賴的基礎(chǔ)模塊抽離出來,打包到一個(gè)個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫中去。接入已經(jīng)內(nèi)置了對(duì)動(dòng)態(tài)鏈接庫的支持,需要通過個(gè)內(nèi)置的插件接入,它們分別是插件用于打包出一個(gè)個(gè)單獨(dú)的動(dòng)態(tài)鏈接庫文件。 webpack優(yōu)化 查看所有文檔頁面:全棧開發(fā),獲取更多信息。原文鏈接:webpack優(yōu)化,原文廣告模態(tài)框遮擋,閱讀體驗(yàn)不好,所以整理成本文,方便查找。 ...

    ChanceWong 評(píng)論0 收藏0
  • 9102年:手寫個(gè)React腳手架 【優(yōu)化極致版】

    摘要:馬上要出了,完全手寫一個(gè)優(yōu)化后的腳手架是不可或缺的技能。每個(gè)依賴項(xiàng)隨即被處理,最后輸出到稱之為的文件中,我們將在下一章節(jié)詳細(xì)討論這個(gè)過程。的事件流機(jī)制保證了插件的有序性,使得整個(gè)系統(tǒng)擴(kuò)展性很好。 webpack馬上要出5了,完全手寫一個(gè)優(yōu)化后的腳手架是不可或缺的技能。 本文書寫時(shí)間 2019年5月9日 , webpack版本 4.30.0最新版本 本人所有代碼均手寫,親自試驗(yàn)過可...

    Kylin_Mountain 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<