成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

如何在前端項(xiàng)目中實(shí)現(xiàn)熱更新

antz / 1437人閱讀

摘要:如果你的項(xiàng)目中使用了的話,你會(huì)很幸運(yùn),借助插件可以實(shí)現(xiàn)項(xiàng)目的熱更新。對(duì)模板更新的處理目前項(xiàng)目中使用的是的模板引擎。


這個(gè)是組內(nèi)一位同學(xué)在平時(shí)開(kāi)發(fā)中,發(fā)現(xiàn)調(diào)試不便,為團(tuán)隊(duì)開(kāi)發(fā)的熱更新工具。很厲害,文章中的技術(shù)實(shí)現(xiàn)內(nèi)容也是我了解了他的具體實(shí)現(xiàn)思路后,整理出來(lái)的。

工具源碼EHU(esl-hot-update)

熱更新是什么

熱更新就是當(dāng)你在開(kāi)發(fā)環(huán)境修改代碼后,不用刷新整個(gè)頁(yè)面即可看到修改后的效果。

如果你的項(xiàng)目中使用了webpack的話,你會(huì)很幸運(yùn),借助webpack-dev-server插件可以實(shí)現(xiàn)項(xiàng)目的熱更新。

解決的問(wèn)題

對(duì)于大型的系統(tǒng)級(jí)別項(xiàng)目會(huì)有下面幾個(gè)特點(diǎn)

模塊化(AMD)模式的廣泛使用后,開(kāi)發(fā)環(huán)境散文件特別多,很容易上百,一不小心還能上千

初始化的內(nèi)容特別多,各種底層庫(kù),ui庫(kù)等等

這兩個(gè)特點(diǎn)直接導(dǎo)致每次調(diào)試后,刷新會(huì)很慢。如果初始化的js達(dá)到上千的數(shù)量級(jí),每一次重新刷新都是5s,10s,甚至20s的等待。

而熱更新的目的就是為了在一定程度上減少這5s,10s,甚20s的浪費(fèi)。

遇到的問(wèn)題

我們使用的是百度自己的開(kāi)發(fā)環(huán)境工具edp,首先他不支持熱更新

我們使用的AMD實(shí)踐也是百度自己的esl,而且即使是requirejs也暫時(shí)沒(méi)有找到對(duì)應(yīng)的熱更新策略,假如requirejs有對(duì)應(yīng)的,我們也無(wú)法直接使用

所以最終的結(jié)論是我們自己去實(shí)現(xiàn)一個(gè)基于我們自己業(yè)務(wù)的。這樣我們考慮的面不用太廣,并且解決方案的更有針對(duì)性,即面向我們現(xiàn)有的業(yè)務(wù)框架。最重要的是可以嘗試修改底層框架做配合。

等待路踩通了,我們?cè)偃タ紤]普適性。

解決的思路

從ehu/package.json 這個(gè)文件中,我們就可以看出一些具體的思路

需要一個(gè)watch功能,即能夠監(jiān)聽(tīng)到文件的修改

socket.io通知瀏覽器處理文件的改變

修改esl這個(gè)文件,達(dá)到能夠?qū)崟r(shí)更新的效果

當(dāng)時(shí)最簡(jiǎn)單的考慮,就是文件改變了后,能夠通知瀏覽器,瀏覽器去重新load這個(gè)文件并且執(zhí)行一次。這個(gè)時(shí)候再重新去打開(kāi)這個(gè)模塊或者功能后,會(huì)發(fā)現(xiàn)新load的代碼在執(zhí)行后會(huì)覆蓋上一次的。

所以當(dāng)時(shí)的我的第一直覺(jué)是,esl重復(fù)require時(shí),如果后面一次會(huì)覆蓋前面的,那么可以通過(guò)簡(jiǎn)單的覆蓋思路去嘗試,結(jié)果發(fā)現(xiàn)覆蓋不了。經(jīng)過(guò)驗(yàn)證,發(fā)現(xiàn)是esl內(nèi)部維護(hù)了一個(gè)map,即require過(guò)的模塊會(huì)存起來(lái)。我們?nèi)绻M逻@個(gè)模塊,只能將map中的對(duì)應(yīng)模塊名刪除。(后面會(huì)詳細(xì)講述esl的改造)

對(duì)于工具的要求

對(duì)應(yīng)這個(gè)工具,我當(dāng)時(shí)也提出了幾個(gè)要求

esl必然是需要修改的,但是如何對(duì)開(kāi)發(fā)人員透明?首先是不能讓大家都做這種修改。

頁(yè)面中也必須加入socket.io支持,那么我們?nèi)绾卧诓挥绊懫渌藛T開(kāi)發(fā)的情況下加入?

我們做的屬于beta版本,如何選擇性的使用?ehu工具和以前的開(kāi)發(fā)模式隨意切換?

安裝方便,能否只是作為一個(gè)工具,即插即用,不需要繁瑣的配置?

如何使用

npm install -g ehu(mac下需要sudo,windows下需要管理員權(quán)限)

在原來(lái)執(zhí)行edp webserver start命令的路徑 執(zhí)行 ehu(不再需要執(zhí)行 edp webserver start)

原來(lái)端口號(hào)8848修改為8844(原8848依舊可以使用,但不支持熱更新)

首先使用的方式很簡(jiǎn)單,為此特意將工具打包到npm上,以后就算有升級(jí),僅僅需要大家update即可。

另外從使用角度,也盡量集成化(一句命令行即可),避免為了這個(gè)工具的使用而做太多額外的事情。

依賴的框架
"dependencies": {
    "async": "^1.5.0",
    "commander": "^2.9.0",
    "express": "^4.13.3",
    "express-http-proxy": "^0.6.0",
    "lodash": "^3.10.1",
    "socket.io": "^1.3.7",
    "watch": "^0.16.0"
  }

幾個(gè)必要的
watch——監(jiān)聽(tīng)文件變化
socket.io——和瀏覽器的實(shí)時(shí)通訊
express——搭建一個(gè)服務(wù)
express-http-proxy——代理
commander——便于自己寫node命令

工具類:
asynclodash

框架的思想

先看看昨天對(duì)于這個(gè)工具提出的幾個(gè)要求

esl必然是需要修改的,但是如何對(duì)開(kāi)發(fā)人員透明?首先是不能讓大家都做這種修改。

頁(yè)面中也必須加入socket.io支持,那么我們?nèi)绾卧诓挥绊懫渌藛T開(kāi)發(fā)的情況下加入?

我們做的屬于beta版本,如何選擇性的使用?ehu工具和以前的開(kāi)發(fā)模式隨意切換?

安裝方便,能否只是作為一個(gè)工具,即插即用,不需要繁瑣的配置?

對(duì)于1和2,我們其實(shí)是需要修改/添加一些代碼的,但是代碼都不希望提交到項(xiàng)目的開(kāi)發(fā)環(huán)境,因?yàn)檫@些代碼生成環(huán)境完全不需要。

所以我們的解決方案是:攔截,改寫(偷梁換柱)

舉個(gè)例子,當(dāng)我們需要對(duì)esl做一些改造時(shí),我們處理方式是當(dāng)路由指向esl.js時(shí),我們換成另外一個(gè)esl-ehu.js(esl-ehu.js是對(duì)esl.js改造后的)返回去,這樣就對(duì)開(kāi)發(fā)環(huán)境的代碼透明了。

socket.io的支持也是同理,我們可以在返回html時(shí),改寫html的代碼,加入對(duì)于socket.io的引入。

上面的思路其實(shí)來(lái)源于之前項(xiàng)目構(gòu)建打包。

對(duì)于3,我們希望在使用工具時(shí),任然能很快切換到以前模式,這樣做兼容的目的是希望工具更有競(jìng)爭(zhēng)力,能吸引大家使用。

我們的解決方案是:內(nèi)部實(shí)現(xiàn)一個(gè)子線程,端口號(hào)依然是以前的,而且訪問(wèn)這個(gè)端口,就繞過(guò)了這個(gè)工具。

對(duì)于子線程child_process,我們還遇到一個(gè)問(wèn)題,就是子線程跑系統(tǒng)的時(shí)候,經(jīng)常掛掉,今天剛剛找到一個(gè)解決方案,后面會(huì)單開(kāi)一個(gè)文章講這個(gè)坑。

對(duì)于4,其實(shí)就是使用npm方式

技術(shù)細(xì)節(jié)

第一步:搭建一個(gè)新服務(wù)作為底層,去托管住我們現(xiàn)在edp服務(wù),新服務(wù)上有一個(gè)路由配置,對(duì)于我們需要處理的,攔截。對(duì)于不用處理的直接代理給edp

代碼參考

var mid = express();
mid.all("*", httpProxy(config.defaultServer, {
    // 先走特殊規(guī)則,否則就代理到默認(rèn)web server
    filter: function(req, res) {
        return !ruleRoute(req, res);
    },
    forwardPath: function(req, res) {
        return URL.parse(req.url).path;
    }
}));
// 由express-http-proxy托管路由
app.use("/", mid);

ruleRoute就是一些攔截處理

在此之前,啟動(dòng)下子進(jìn)程

var child = require("child_process");
var cli = child.exec(defaultServerCLI);
cli.stdout.on("data", function (log) {
    !isServerStarted && (cb(null, log));
    isServerStarted && console.log(log);
});

此處有坑,后面單開(kāi)文章描述

第二步: 因?yàn)樯厦鏀r截后的返回的文件已經(jīng)支持socket.io,esl等底層已經(jīng)修改了,所以下面是需要去監(jiān)聽(tīng)文件通知瀏覽器做對(duì)應(yīng)處理。

// 啟動(dòng)socket.io服務(wù)
io = require("socket.io")(server);
io.on("connection", function (socket) {
    socket.emit("hello");
});
// 監(jiān)視文件改動(dòng)
initWatch();

第三步: 做一些集成工作

program
    .version("0.0.6")
    .usage("[options]")
    .option("-p, --port ", "Set the port", setPort)
    .option("-n, --noServerCLI", "...", noServerCLI)
    .parse(process.argv);

集成到node命令中

第四步: 默認(rèn)配置

module.exports = {
    // 默認(rèn)的服務(wù)器
    defaultServer: "http://127.0.0.1:8848",
    // 默認(rèn)的服務(wù)器啟動(dòng)命令
    defaultServerCLI: "edp webserver start",
    // 從服務(wù)器根目錄到需要監(jiān)控的文件夾中間path
    baseDir: "nirvana-workspace",
    // hot update 需要watch的文件夾(不包括baseDir)
    watchDirs: "src",
    // 入口文件(不包括baseDir)
    indexHTML: "main.html",
    // ehu啟動(dòng)端口號(hào)(不可與默認(rèn)的服務(wù)器端口號(hào)沖突)
    port: 8844
};

源碼中有很多邏輯是處理配置的

瀏覽器依賴

socket.io——瀏覽器端僅僅依賴socket這個(gè)去和服務(wù)端通信

通信邏輯

// 建立連接
socket.on("hello", function () {
    log(getLogMsgPrefix(), "HotUpdate已啟動(dòng)!");
});
// 檢測(cè)到文件改動(dòng)
socket.on("hotUpdate", function (file) {
    // log(getLogMsgPrefix(), "檢測(cè)到文件改動(dòng)", file);
    // ....處理文件修改后對(duì)應(yīng)熱更新邏輯
});
對(duì)css/less更新的處理

這個(gè)原理比較簡(jiǎn)單,頁(yè)面監(jiān)聽(tīng)到樣式的修改,重新加載一次樣式即可,簡(jiǎn)單的覆蓋。

但是存在一個(gè)潛在問(wèn)題,因?yàn)闃邮绞呛?jiǎn)單的覆蓋,所以,如果修改是刪除了樣式,是無(wú)法生效的。

舉例:
修改前:

display: none;
overflow: hidden;
position: relative;
background: #FFFFFF;
border: 1px solid #E8E8E8;
margin-top: 20px;

修改后:

display: none;
overflow: hidden;
position: relative;
background: #FFFFFF;

刪除的bordermargin-top其實(shí)是沒(méi)有生效的

這個(gè)也是后期需要解決的一個(gè)問(wèn)題。

對(duì)模板更新的處理

目前項(xiàng)目中使用的是tpl的模板引擎。

現(xiàn)在就遇到一個(gè)問(wèn)題,在熱更新時(shí),模板引擎其實(shí)是重復(fù)加載模板的,那么就涉及到重復(fù)加載是否后面的會(huì)覆蓋前面問(wèn)題。

查看加載模板的源碼后,發(fā)現(xiàn)根據(jù)配置有三個(gè)選擇,覆蓋,忽略報(bào)錯(cuò), 我們業(yè)務(wù)中使用的配置是遇到重復(fù)后會(huì)報(bào)錯(cuò)處理,所以我們需要在不修改業(yè)務(wù)默認(rèn)屬性的情況下,添加一些邏輯。

// [esl-hot-update] 重新加載需要覆蓋
window.EHU_HOT_UPDATE_OPTIONS
&& window.EHU_HOT_UPDATE_OPTIONS.etpl.isOverride
&& (namingConflict = "override");
switch (namingConflict) {
    /* jshint ignore:start */
    case "override":
        engine.targets[name] = target;
        context.targets.push(name);
    case "ignore":
        break;
    /* jshint ignore:end */
    default:
        throw new Error("Target exists: " + name);
}

window.EHU_HOT_UPDATE_OPTIONS.etpl.isOverride這個(gè)是修改后自己實(shí)現(xiàn)的控制配置修改的邏輯。

然后這個(gè)文件加入到服務(wù)端的路由中,請(qǐng)求時(shí)替換。

對(duì)js更新的處理

這里邏輯比較復(fù)雜,因?yàn)樾枰薷牡讓拥腁MD模塊加載的邏輯。

js沒(méi)有模板那么簡(jiǎn)單,不是直接覆蓋,因?yàn)樵贏MD模式中,每一個(gè)文件,都是被上一個(gè)文件調(diào)用執(zhí)行的結(jié)果。

所以我們處理的邏輯是不僅需要重新加載修改的文件,并且遞歸所有直接或者間接調(diào)用他的文件,全部重新加載。

所以從上面的特點(diǎn)可以看出,這個(gè)工具目前階段主要適用于業(yè)務(wù)模塊的開(kāi)發(fā),因?yàn)闃I(yè)務(wù)的依賴不會(huì)特別深,對(duì)于dep中的核心文件修改,就不是很合適,一旦文件比較底層,熱跟新是重新加載的模塊也會(huì)非常多。

另外也有很多其他的坑,還在不斷優(yōu)化中。

總結(jié)

這次實(shí)踐其實(shí)就是業(yè)務(wù)中遇到的問(wèn)題(系統(tǒng)太龐大,調(diào)試太麻煩),如何解決問(wèn)題,如何把解決的思路變成一個(gè)解決方案,分享給團(tuán)隊(duì)。

因?yàn)樽约航鉀Q了,和形成一個(gè)解決方案還是有非常大的差別的,例如我們?cè)谛纬煞桨傅倪^(guò)程中,就嘗試了很多新東西,踩了很多坑。

目前還有個(gè)坑就是chrome瀏覽器,調(diào)試的Source資源時(shí),如果一個(gè)資源重復(fù)加載,內(nèi)存中會(huì)更新,但是對(duì)應(yīng)的資源沒(méi)有更新,導(dǎo)致斷點(diǎn)時(shí),映射不對(duì)(斷點(diǎn)失效),目前暫時(shí)的解決方案是,每次請(qǐng)求時(shí)添加時(shí)間戳,讓Source映射的資源強(qiáng)制更新。這個(gè)可以正常斷點(diǎn),但是斷點(diǎn)沒(méi)有記憶功能(坑啊,因?yàn)槲募兞耍?/p> 微信公眾號(hào)

博客地址

http://tangguangyao.github.io/

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/78318.html

相關(guān)文章

  • 使用node子進(jìn)程spawn,exec踩過(guò)的坑

    摘要:最后發(fā)現(xiàn)使用子進(jìn)程打開(kāi)還真的就是使用到一定程度就掛掉。上面的簡(jiǎn)單流程就是啟動(dòng)一個(gè)子進(jìn)程。邏輯就是,記錄子進(jìn)程的大小,一旦超過(guò)就掉子進(jìn)程。我們?cè)谑褂脮r(shí),不知道設(shè)置,默認(rèn)的是當(dāng)我們子進(jìn)程日志達(dá)到時(shí),自動(dòng)掉了。 showImg(https://segmentfault.com/img/bVrCnh); 如何在項(xiàng)目中實(shí)現(xiàn)熱更新中提到的一個(gè)坑child_process的exec使用問(wèn)題,下面文章...

    cppprimer 評(píng)論0 收藏0
  • 2018年8月所遇知識(shí)點(diǎn)整理

    摘要:注本文章是在工作過(guò)程中所接觸的知識(shí)點(diǎn)的整理,涉及的東西比價(jià)雜亂,如有錯(cuò)誤之處,歡迎糾錯(cuò)與指導(dǎo)一,頁(yè)面的錨鏈接定義錨點(diǎn)錨點(diǎn)鏈接。類似于我們閱讀書籍時(shí)的目錄頁(yè)碼或章回提示。 *注:本文章是在工作過(guò)程中所接觸的知識(shí)點(diǎn)的整理,涉及的東西比價(jià)雜亂,如有錯(cuò)誤之處,歡迎糾錯(cuò)與指導(dǎo) 一, 頁(yè)面的錨鏈接 1,定義:錨點(diǎn),錨點(diǎn)鏈接。常常用于那些內(nèi)容龐大繁瑣的網(wǎng)頁(yè),通過(guò)點(diǎn)擊命名錨點(diǎn),不僅讓我們能指向文檔,還...

    silenceboy 評(píng)論0 收藏0
  • 2018年8月所遇知識(shí)點(diǎn)整理

    摘要:注本文章是在工作過(guò)程中所接觸的知識(shí)點(diǎn)的整理,涉及的東西比價(jià)雜亂,如有錯(cuò)誤之處,歡迎糾錯(cuò)與指導(dǎo)一,頁(yè)面的錨鏈接定義錨點(diǎn)錨點(diǎn)鏈接。類似于我們閱讀書籍時(shí)的目錄頁(yè)碼或章回提示。 *注:本文章是在工作過(guò)程中所接觸的知識(shí)點(diǎn)的整理,涉及的東西比價(jià)雜亂,如有錯(cuò)誤之處,歡迎糾錯(cuò)與指導(dǎo) 一, 頁(yè)面的錨鏈接 1,定義:錨點(diǎn),錨點(diǎn)鏈接。常常用于那些內(nèi)容龐大繁瑣的網(wǎng)頁(yè),通過(guò)點(diǎn)擊命名錨點(diǎn),不僅讓我們能指向文檔,還...

    guqiu 評(píng)論0 收藏0
  • React+Koa+MongoDB+Docker開(kāi)發(fā)環(huán)境

    摘要:已經(jīng)發(fā)布到,只要在環(huán)境下安裝即可。下面通過(guò)來(lái)構(gòu)建開(kāi)發(fā)環(huán)境,提高開(kāi)發(fā)體驗(yàn)。容器容器的實(shí)質(zhì)是進(jìn)程,但與直接在宿主執(zhí)行的進(jìn)程不同,容器進(jìn)程運(yùn)行于屬于自己的獨(dú)立的命名空間。部署開(kāi)發(fā)環(huán)境部署開(kāi)發(fā)環(huán)境其實(shí)很簡(jiǎn)單,只需要配置和即可。 前言 本次博文依然是對(duì) multi-spa-webpack-cli 的擴(kuò)充和完善。 集成 mongoose。 集成 Docker 開(kāi)發(fā)環(huán)境。 multi-spa-w...

    sarva 評(píng)論0 收藏0
  • WEEX系列 WEEX入門

    摘要:通過(guò)使用有限的類標(biāo)簽閹割的及基于語(yǔ)法來(lái)快速構(gòu)建原生應(yīng)用。高性能本身對(duì)加載時(shí)間和資源占用進(jìn)行了優(yōu)化。站在巨人的肩膀上,我們也很容易開(kāi)發(fā)出高性能的。我們可以把部署到服務(wù)器上實(shí)現(xiàn)熱更新。引擎運(yùn)行這些實(shí)現(xiàn)與線程通信,達(dá)到和原生應(yīng)用相同的體驗(yàn)效果。 和一步一起從前端視角聊一聊WEEX WEEX是一套構(gòu)建高性能、可擴(kuò)展的原生應(yīng)用跨平臺(tái)解決方案。就一個(gè)字吊。 通過(guò)使用有限的類HTML標(biāo)簽、閹割的CS...

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

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

0條評(píng)論

閱讀需要支付1元查看
<