VUE & Regular & NEJ 無(wú)痛融合解決方案

本文由cy帘靡,wxy 共同完成面褐,排名不分先后攻柠。

0 前言

在網(wǎng)易內(nèi)部恨诱,很多部門(mén)都是以NEJ+Regular作為基礎(chǔ)庫(kù)來(lái)進(jìn)行前端開(kāi)發(fā)翻默,因此腰根,各個(gè)部門(mén)也基于此積累了很多庫(kù)新翎,組件缓醋。這也產(chǎn)生了一個(gè)問(wèn)題署鸡,一個(gè)新的項(xiàng)目如果啟動(dòng)案糙,想去使用以前的積累,就必須和以前采用相同的技術(shù)方案以及選型靴庆,那么时捌,有沒(méi)有一種方法,在新項(xiàng)目(業(yè)務(wù))啟動(dòng)時(shí)炉抒,既能兼容以往部門(mén)所沉淀的技術(shù)組件奢讨,又能夠使用新技術(shù),新方案給開(kāi)發(fā)帶來(lái)全新的感受焰薄,我們?cè)凇究ù钚@】這個(gè)產(chǎn)品做了以下的嘗試拿诸。

1 NEJ篇

在網(wǎng)易內(nèi)部,大家一定對(duì)NEJ不陌生塞茅,早期乃至現(xiàn)在很多業(yè)務(wù)都基于NEJ框架進(jìn)行開(kāi)發(fā)亩码,NEJ也包攬了模塊依賴(lài)umi調(diào)度系統(tǒng)野瘦、platform適配描沟、構(gòu)建打包等多個(gè)功能,可以說(shuō)涵蓋了從開(kāi)發(fā)到構(gòu)建上線(xiàn)的所有生命周期,足見(jiàn)之強(qiáng)大吏廉〈缆纾可也正因?yàn)榇耍琋EJ也顯示的很重迟蜜,無(wú)法像webpack,postcss刹孔,babel等通過(guò)插件/loader,來(lái)進(jìn)行二次開(kāi)發(fā),有時(shí)候娜睛,一些新的想法和點(diǎn)子只能通過(guò)小聰明去解決髓霞。基于這樣的考慮畦戒,我們首先做了一件事方库,解耦NEJ,即NEJ代碼不需要通過(guò)自有的打包構(gòu)建工具障斋,而能被任意第三方框架/倉(cāng)庫(kù)使用纵潦。

1.1 模塊依賴(lài)

眾所周知,NEJ有屬于自己的模塊依賴(lài)系統(tǒng)垃环,即NEJ.define(),一個(gè)標(biāo)準(zhǔn)的NEJ模塊系統(tǒng)會(huì)有這樣的代碼

NEJ.define( [
    'pro/{mode}/base'
    './component.js',
    'text!./web/component.html',
    'css!./web/component.css'
],function(Base,Button,html,css,p,o,f,r){
    // ...具體邏輯
})

顯然邀层,NEJ的模塊依賴(lài)系統(tǒng)屬于AMD類(lèi)型,但是其語(yǔ)法與標(biāo)準(zhǔn)的AMD模塊相比遂庄,又更具靈活性:

  1. 文件依賴(lài)url支持參數(shù)寥院,可通過(guò)define.js配置:pro/{mode}/base
  2. 支持text,css,regular等拓展關(guān)鍵字來(lái)引入不同類(lèi)型的文件:text!./web/component.html
  3. 模塊中會(huì)自動(dòng)注入4個(gè)參數(shù):p,輸出結(jié)果集空間涛目;o秸谢,一個(gè)空對(duì)象;f霹肝,一個(gè)return false的函數(shù)估蹄;r,一個(gè)空數(shù)組沫换;

1.2 模塊轉(zhuǎn)化:babel插件

如果能夠找出NEJ的私有模塊依賴(lài)系統(tǒng)與標(biāo)準(zhǔn)的模塊系統(tǒng)之間的不同之處臭蚁,將NEJ的私有模塊依賴(lài)系統(tǒng)轉(zhuǎn)化為標(biāo)準(zhǔn)的AMD/CMD/CommonJS/ES6 module系統(tǒng),是不是也就意味著NEJ模塊可以被其它類(lèi)型的模塊所用苗沧?

基于此刊棕,我們決定采取編寫(xiě)Babel插件的方式來(lái)進(jìn)行NEJ module -> CommonJS module的轉(zhuǎn)化炭晒。

Babel 是 JavaScript 編譯器待逞,更確切地說(shuō)是源碼到源碼的編譯器,通常也叫做“轉(zhuǎn)換編譯器(transpiler)”网严。 意思是說(shuō)你為 Babel 提供一些 JavaScript 代碼识樱,Babel 更改這些代碼,然后返回給你新生成的代碼。

1.2.1 使用babel轉(zhuǎn)化NEJ需要解決的問(wèn)題

除了以上三點(diǎn)怜庸,babel轉(zhuǎn)化NEJ的過(guò)程中当犯,我們還需要解決如下幾個(gè)問(wèn)題:

  1. NEJ return && 輸出結(jié)果集空間的處理
  2. 依賴(lài)系統(tǒng)中循環(huán)依賴(lài)的處理
  3. NEJ依賴(lài)中,默認(rèn)this = window
  4. NEJ很多文件在嚴(yán)格模式下會(huì)報(bào)錯(cuò)割疾,因?yàn)榇嬖诤芏喾菄?yán)格寫(xiě)法嚎卫,(如 xxx.bind(undefine),非嚴(yán)格模式情況下, this指向window宏榕;而嚴(yán)格模式下this指向undefined)

在不斷的分析NEJ源碼以及嘗試下拓诸,我們小組完成了babel插件babel-plugin-transform-nej-module來(lái)做這件事情。

1.2.2 插件效果示例

對(duì)一個(gè)常見(jiàn)的NEJ模塊文件:

// NEJ模塊
NEJ.define( [
    '../component.js',
    'text!./component.html',
    'text!./component.css'
],function(
    Component,
    html,
    css,
    pro,
    o, f, r
) {
    return uxModal;
});

babel-plugin-transform-nej-module會(huì)將其轉(zhuǎn)化為:

// CommonJS模塊
(function nejModule() {
    var Component = require('../component');
    var html = require('./component.html');
    var css = require('./component.css');

    var css = "";
    
    var pro = exports;
    
    var o = {};
    var f = function () {};
    var r = [];
    
    module.exports = uxModal;
    return;
}).call(window);

查看更多示例

1.2.3 插件運(yùn)行剖析

插件的運(yùn)行流程圖及每一步的解釋如下:

image
  1. 從文件的根開(kāi)始:為什么要從根開(kāi)始麻昼?在babel插件的不同的visitor中奠支,難免會(huì)需要共享變量。這些共享變量的初始化抚芦,應(yīng)該在每個(gè)文件第一次進(jìn)入時(shí)進(jìn)行倍谜。因此選擇從根開(kāi)始處理文件,以便在文件開(kāi)始運(yùn)行前做一些初始化處理叉抡。(Babel插件處理文件的順序是并行的還是串行的尔崔,這一點(diǎn)尚有待驗(yàn)證。如果是串行的褥民,在pre階段進(jìn)行初始化更好您旁。)

  2. 取第一層節(jié)點(diǎn):JS文件被Babylon parse成一棵AST樹(shù),取該樹(shù)的第一層節(jié)點(diǎn)開(kāi)始后續(xù)處理轴捎。

為什么取第一層鹤盒?

  • 在以NEJ為基礎(chǔ)的前端工程中,所有的業(yè)務(wù)代碼都包含在NEJ.define/define語(yǔ)句中侦副,形成模塊侦锯。
    如果NEJ模塊被包含在其他代碼塊中,那它不一定能被執(zhí)行到秦驯,則該模塊是無(wú)效的尺碰。
    即使一定能執(zhí)行到,在NEJ打包時(shí)译隘,也不會(huì)將模塊外部的代碼打包亲桥。
  • 如果從任意一條語(yǔ)句開(kāi)始,可能會(huì)遇到其他文件中的define函數(shù)被識(shí)別為nej模塊情況固耘。

因此题篷,我們只考慮一個(gè)文件就是一個(gè)nej模塊的情況

  1. 判斷NEJ模塊nej.define() 或者 define()函數(shù)被識(shí)別為NEJ模塊

  2. 獲取依賴(lài)列表和回調(diào)函數(shù):處理了無(wú)依賴(lài)列表、依賴(lài)列表為空厅目、回調(diào)函數(shù)為變量的情況番枚。

  3. 進(jìn)一步尋找回調(diào)函數(shù)(當(dāng)回調(diào)函數(shù)為變量的時(shí)候):訪問(wèn)模塊內(nèi)代碼的所有賦值語(yǔ)句法严,找到對(duì)回調(diào)函數(shù)變量賦值的語(yǔ)句。

  4. 將回調(diào)函數(shù)命名為nejModule:這一步很重要葫笼。用來(lái)定位回調(diào)函數(shù)的return和輸出結(jié)果集空間的變動(dòng)深啤,并進(jìn)行跟蹤修改。

  5. 處理return:回調(diào)函數(shù)對(duì)應(yīng)的return xxxmodule.exports = xxx; return;

  6. 處理依賴(lài)

  • 初始化注入?yún)?shù)路星;
  • 標(biāo)準(zhǔn)化依賴(lài)路徑溯街;
  • 初始化css文件為空字符串,以兼容NEJ對(duì)css的處理洋丐,盡管這些處理在不使用define函數(shù)的時(shí)候是無(wú)效的苫幢。
  1. 處理輸出結(jié)果集空間(設(shè)為pro):將所有使用到pro的代碼替換為exports,(不直接module.exports = pro垫挨,因?yàn)樾枰幚硌h(huán)依賴(lài))

  2. 保證模塊內(nèi)this指向window:使用自執(zhí)行函數(shù)將全部語(yǔ)句包裝起來(lái)韩肝。

1.2.4 方案不足之處

  • 尚存在兩種罕見(jiàn)的異常未做處理:
  1. text!方式引入的css文件為空字符串,實(shí)際應(yīng)該是css文件的內(nèi)容;
  2. 輸出結(jié)果集空間被直接修改為其它對(duì)象;
  • NEJ對(duì)于不同平臺(tái)的適配處理:
  1. {platform}/element.js被轉(zhuǎn)化為./platform/element.js九榔,實(shí)際應(yīng)當(dāng)同時(shí)引入./platform/element.patch.js

如果你發(fā)現(xiàn)了任何其它異常情況哀峻,請(qǐng)一定要提出issue或直接聯(lián)系我們,我們將會(huì)在最快時(shí)間內(nèi)解決

1.3 與webpack的結(jié)合

NEJ模塊轉(zhuǎn)化為標(biāo)準(zhǔn)Common JS模塊后哲泊,還需要再兩項(xiàng)額外配置剩蟀,來(lái)保證與webpack的結(jié)合使用:

  1. 將NEJ的路徑參數(shù)配置為weppack別名,以下是已知的NEJ路徑參數(shù)配置:
module.exports = {
    ...
    resolve: {
        alias: {
            'base': resolve('lib/nej/src/base'),
            'lib': resolve('lib/nej/src'),
            'ui': resolve('lib/nej/src/ui'),
            'util': resolve('lib/nej/src/util')
        }
    }
    ...
}
  1. 在插件中配置非前綴的路徑參數(shù)切威、以及嚴(yán)格模式的去除:
 "plugins": [
    ...    
    "transform-remove-strict-mode",
    [
      "transform-nej-module",
      {
        "mode": "web"
      }
    ],
    ///
  ],

2 Regular篇

說(shuō)完如何處理NEJ育特,現(xiàn)在我們來(lái)分析一下,如何處理部門(mén)所沉淀的regular組件庫(kù)先朦?

我們所在的部門(mén)從16年起缰冤,開(kāi)始搭建了一套用regular編寫(xiě)的組件庫(kù),大大小小封裝了上百個(gè)模塊及組件喳魏,為各條產(chǎn)品線(xiàn)提供支持棉浸。

眾所周知,vue template和regular template是不同DSL語(yǔ)法的模板技術(shù)刺彩,兩個(gè)框架擁有各自的語(yǔ)法迷郑,
在框架層面,如何能最小程度的兼容regular組件成了我們需要優(yōu)先考慮的問(wèn)題创倔。

2.1 原理探究

在regularjs中嗡害,組件被拆分為了 模板template + 數(shù)據(jù)data + 業(yè)務(wù)邏輯(實(shí)例函數(shù))的組合。也就是說(shuō)畦攘,只要滿(mǎn)足上述三個(gè)條件霸妹,就可以實(shí)例出一個(gè)regular組件。

regular組件有兩種使用方式念搬,一種是直接實(shí)例化抑堡,一種是標(biāo)簽式。

1.對(duì)于直接使用new方法實(shí)例出來(lái)的組件朗徊,將所需要數(shù)據(jù)傳入即可首妖,注意要及時(shí)銷(xiāo)毀。

2.對(duì)于標(biāo)簽式組件爷恳,就必須要有一個(gè)地方來(lái)承載regular模版有缆,于是想到可以通過(guò)注冊(cè)一個(gè)通用的vue組件,拿到regularjs模版温亲,傳入數(shù)據(jù)與邏輯棚壁,在該組件中進(jìn)行實(shí)例化,從而達(dá)到承載regular組件的效果栈虚。

2.2 開(kāi)始設(shè)計(jì)

我們的目的就是設(shè)計(jì)并實(shí)現(xiàn)這樣一個(gè)RegularComponent(簡(jiǎn)稱(chēng)RC)組件袖外。

首先遇到的問(wèn)題是如何獲取標(biāo)簽內(nèi)的模版?

我們可以利用vue插槽

業(yè)務(wù)組件

// 業(yè)務(wù)組件模版
<rc ref="rc" :revent="REvent" :rdata="RData" :rfilter="RFilter">
    <ux-button value={name} on-click={this.clickBtn($event)}></ux-button>
</rc>

RC組件

// RC組件模版
<div ref="rc">
    <slot/>
</div>

這樣就可以在RC組件中,拿到

  1. this.$slots 模版
  2. this.rdata 數(shù)據(jù)
  3. this.revent 業(yè)務(wù)邏輯
  4. this.rfilter 過(guò)濾器

這里需要注意魂务,this.$slots 直接獲取到的是vue規(guī)范的AST曼验,下面稱(chēng)為VNode,我們可以封裝一個(gè)方法將VNode轉(zhuǎn)為模版字符串粘姜,再去執(zhí)行實(shí)例化regular的行為鬓照。

let attrStringify = obj => {
    let ret = '';
    for (let i in obj) {
        if (obj[i]) {
            ret += ' ' + i + '="' + obj[i] + '"';
        } else {
            ret += ' ' + i;
        }
    }
    return ret;
};

// 拼裝模版
let formatTpl = arr => {
    let tpl = '';
    arr.forEach(item => {
        if (item.text) {
            tpl += item.text;
        } else if (item.tag) {
            tpl += '<' + item.tag;

            // 組裝attr
            if (item.data) {
                tpl += attrStringify(item.data.attrs) + '>';
            } else {
                tpl += '>';
            }

            // 組裝子節(jié)點(diǎn)
            if (item.children) {
                tpl += formatTpl(item.children);
            }

            // 閉合組件標(biāo)簽
            tpl += '</' + item.tag + '>';
        } else if (item.children) {
            tpl += formatTpl(item.children);
        }
    });
    return tpl;
};

拿到這些數(shù)據(jù),就可以生成reuglar組件了孤紧。

到了這一步豺裆,還沒(méi)有完全實(shí)現(xiàn)我們想要的效果,因?yàn)関ue插槽會(huì)將內(nèi)容分發(fā)至子組件号显,查看源碼可以看到模版代碼直接展示在頁(yè)面上臭猜;而且模版中的標(biāo)簽式組件是在regular中注冊(cè)的,直接使用會(huì)報(bào)錯(cuò)押蚤,這是不希望看到的获讳。

[Vue warn]: Unknown custom element: <ux-button> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

不過(guò)修復(fù)這個(gè)問(wèn)題并不困難,只需隱藏這個(gè)插槽即可活喊。

<div ref="rc">
    <slot v-if="false" />
</div>

現(xiàn)在組件實(shí)例化好了丐膝,假設(shè)需要異步獲取數(shù)據(jù),同步至regular組件钾菊,要如何更新呢帅矗?

在regular中,我們一般在接口請(qǐng)求回調(diào)中煞烫,將返回的數(shù)據(jù)賦值到this.data上浑此,然后調(diào)用regular的update方法來(lái)觸發(fā)一輪臟檢查來(lái)同步數(shù)據(jù)。

在使用RC時(shí)滞详,當(dāng)vue組件中RData發(fā)生變化時(shí)凛俱,會(huì)自動(dòng)同步至RC組件紊馏,但regular組件實(shí)例化完成之后,不會(huì)繼續(xù)更新數(shù)據(jù)蒲犬。我們只要在RC組件內(nèi)部監(jiān)聽(tīng)這個(gè)對(duì)象朱监,再去更新regular組件內(nèi)的數(shù)據(jù)即可,這個(gè)流程可以用下圖表示:

image.png

2.3 注意事項(xiàng)

1.目前已知regular模版中雙大括號(hào)會(huì)被編譯原叮,導(dǎo)致返回錯(cuò)誤的AST赫编,可以在最外層加上v-pre,若有使用r-class奋隶、r-style就必須加上擂送,其他場(chǎng)景最好也加上

示例

<rc ref="rc" :revent="REvent" :rdata="RData" :rfilter="RFilter">
    <div v-pre>
        <ux-button value={name} on-click={this.clickBtn($event)}></ux-button2>
    </div>
</rc>

2.需要注意函數(shù)中this的指向,vue事件指向vue唯欣,regular事件指向regular

3.在regular模版中嘹吨,若在逗號(hào)后面包含空格,如 on-click={this.xxx(item, $event)}境氢,會(huì)導(dǎo)致AST格式出錯(cuò)躺苦,解決方案是把空格去掉,或者大括號(hào)外加上引號(hào)

2.4 小結(jié)

為了在vue中支持regular产还,我們可以注冊(cè)一個(gè)RC組件來(lái)承載匹厘,它是一個(gè)vue組件,通過(guò)vue slot(插槽)獲取模版脐区,綁定data愈诚、event、filter牛隅,動(dòng)態(tài)生成regular組件插入到視圖層炕柔,從而支持了在vue組件中直接編寫(xiě)regular代碼的功能。

2.5 該方案的不足

因?yàn)槲覀兊捻?xiàng)目是采取weex控制組件的各個(gè)state媒佣,即單向數(shù)據(jù)流來(lái)控制組件中的數(shù)據(jù)匕累,但是在目前已實(shí)現(xiàn)的組件池基本已被regular雙向綁定給限制了,雖然也可以在watch中觸發(fā)commit,dispatch,可這也無(wú)疑會(huì)將邏輯打亂默伍,因此欢嘿,針對(duì)這部分代碼,我們大多沒(méi)有采用weex管理狀態(tài)也糊,而交由組件自身去維護(hù)炼蹦,有時(shí)候享受不了單向數(shù)據(jù)流帶來(lái)的便利性。

3 構(gòu)建部署篇

我們可以看到狸剃,我們通過(guò)Babel將完成了對(duì)NEJ模塊依賴(lài)的解耦掐隐,通過(guò)Vue組件代理,完成了regular組件上的兼容钞馁,最后就是去解決如何上線(xiàn)部署了

3.1構(gòu)建

3.1.1問(wèn)題

1.【卡搭校園】這個(gè)項(xiàng)目虑省,后端還是按照以往的邏輯匿刮,將一些后端數(shù)據(jù)直接寫(xiě)到ftl模板之中。也就是說(shuō)探颈,最后上線(xiàn)熟丸,我們?nèi)匀灰蕾?lài)freemarker去解析數(shù)據(jù)。但是膝擂,我們?cè)谑褂脀ebpack構(gòu)建開(kāi)發(fā)環(huán)境之時(shí)虑啤,其本質(zhì)是不支持渲染java模板的隙弛。因此架馋,在構(gòu)建環(huán)境,我們要區(qū)分開(kāi)發(fā)狀態(tài)以及上線(xiàn)打包狀態(tài)全闷,提供不同的代碼用來(lái)兼容不同平臺(tái)(node or html/ java)

  1. 靜態(tài)資源路徑叉寂,NEJ-toolkit已經(jīng)幫忙實(shí)現(xiàn)了類(lèi)似靜態(tài)資源地址前綴添加,切換到webpack后总珠,不交給webpack打包的js屏鳍,css,img等資源文件默認(rèn)是不會(huì)自動(dòng)加前綴的,這塊也要想辦法進(jìn)行兼容局服。

3.1.2 問(wèn)題解決

先來(lái)看看第一個(gè)問(wèn)題钓瞭,在webpack-server中,默認(rèn)是通過(guò)HtmlWebpackPlugin插件生成自動(dòng)生成html淫奔,同時(shí)山涡,該插件可以兼容ejs語(yǔ)法對(duì)各種環(huán)境進(jìn)行定制。那么唆迁,我們也可以通過(guò)他自動(dòng)生成ftl模板鸭丛。webpack配置如下

        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));
        let conf = {
            // 模板來(lái)源
            template: '!!ejs-compiled-loader!' + filePath,
            // 文件名稱(chēng)
            filename: filename + '.html',
            // 頁(yè)面模板需要加對(duì)應(yīng)的js腳本,如果不加這行則每個(gè)頁(yè)面都會(huì)引入所有的js腳本
            chunks: ['manifest', 'vendor', filename],
            inject: true
        };
        // 生產(chǎn)環(huán)境轉(zhuǎn)為ftl
        if (process.env.NODE_ENV === 'production') {
            conf = merge(conf, {
                filename: filename + '.ftl',
                env: 'production',
                minify: {
                    removeComments: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true
                },
                chunksSortMode: 'dependency'
            });
        }

對(duì)應(yīng)的html模板如下所示


<% if(htmlWebpackPlugin.options.env === 'production'){ %>
<!--生產(chǎn)環(huán)境-->
<script>
    <#if webUser?exists>
    window.webUser = {
    <#if webUser.id?exists>id: "${webUser.id?html}",</#if>
    end_key: "end_value"
    };
    </#if>
</script>
<%} else{%>
<!--開(kāi)發(fā)環(huán)境-->
<script>
    window.webUser = {
        "id": 123456
    };
</script>
<%} %>

因?yàn)樵趙ebpack插件中唐责,我們指定了template通過(guò)ejs-loader來(lái)渲染鳞溉,因此我們通過(guò)參數(shù)傳遞到html中,通過(guò)不同的環(huán)境模式鼠哥,來(lái)切換開(kāi)發(fā)環(huán)境以及部署到服務(wù)器與后端渲染的ftl模板熟菲,后期如果有新的后端數(shù)據(jù)需要渲染到ftl上,只需要維護(hù)自己的template模板即可朴恳。這樣處理也帶來(lái)了另外一個(gè)好處科盛,我們?cè)趆tml模板會(huì)使用類(lèi)似如下的語(yǔ)法

<body>
    <div id="app"></div>
    <% include src/pages/common/footer.html %>
</body>

插件最后生成ftl時(shí)會(huì)將所有片段組裝到一起,避免了ftl語(yǔ)法 <#include> 部署后路徑菜皂,資源以及模板被緩存等問(wèn)題

第二個(gè)問(wèn)題即靜態(tài)資源服務(wù)器替換問(wèn)題贞绵,正常情況下,webpack打包的js||css等都可以通過(guò)配置output添加對(duì)應(yīng)的靜態(tài)資源路徑恍飘,但是如果出現(xiàn)在HtmlWebpackPlugin模板中的靜態(tài)資源默認(rèn)是不會(huì)添加榨崩,我們不可能在開(kāi)發(fā)或者部署的時(shí)候手動(dòng)添加對(duì)應(yīng)的前綴來(lái)滿(mǎn)足業(yè)務(wù)上的需求谴垫,因?yàn)闆](méi)有找到合適的工具,因此母蛛,在自動(dòng)切換層翩剪,我們手動(dòng)編寫(xiě)了webpack插件來(lái)進(jìn)行解決。

解決思路如下
通過(guò)監(jiān)聽(tīng) html-webpack-plugin-before-html-processing 對(duì)輸出的html進(jìn)行處理彩郊,如果發(fā)現(xiàn)他沒(méi)有帶靜態(tài)資源路徑名前弯,則給其增加前綴,示例代碼如下

function AddStaticServer (options) {
    let option = options || {
            serverPath: '//kc.stu.126.net'
        };
    this.serverPath = option.serverPath;
}

AddStaticServer.prototype.apply = function (compiler) {
    compiler.plugin('compilation', (compilation) => {
        compilation.plugin(
            'html-webpack-plugin-before-html-processing',
            (data, cb) => {
                data.html = generatehtml(data,html)
                cb(null, data);
            }
        );
    });
};

webpack對(duì)應(yīng)配置

 plugins:[
    .....,
    .....,
    new AddStaticServerPlugin({
          serverPath: config.build.assetsPublicPath
      })])
 ]

3.1.3 該方案的不足

在前文解決方案中提到秫逝,我們?yōu)榱藚^(qū)分線(xiàn)上ftl文件以及前端html文件恕出,需要針對(duì)性的編寫(xiě)模板,并且通過(guò)配置违帆,當(dāng)遇到通用ftl數(shù)據(jù)過(guò)多的情況下浙巫,需要做很多的額外配置以及編寫(xiě),項(xiàng)目到后期的話(huà)也可能會(huì)越來(lái)越大刷后,因此的畴,在我們的項(xiàng)目中,除了約定必須的model數(shù)據(jù)外尝胆,其他都通過(guò)異步接口進(jìn)行獲取丧裁,這樣也是為了減少后期可能SSR的成本

3.2開(kāi)發(fā)數(shù)據(jù)mock

原有項(xiàng)目中,我們可以通過(guò)網(wǎng)易內(nèi)部的NEI平臺(tái)來(lái)進(jìn)行接口mock甚至是ftl的渲染含衔,而在新的工程中煎娇,因?yàn)殚_(kāi)發(fā)環(huán)境的切換,不在使用ftl作為承載頁(yè)面進(jìn)行抱慌,因此逊桦,需要尋找其他方式進(jìn)行Mock,
好在webpack-dev-server能夠提供這樣的能力我們可以配置proxy來(lái)對(duì)接口進(jìn)行代理抑进,示例代碼如下所示

devServer: {
    proxy: {
        '/api': 'http://localhost:8002/',
        '/j':'http://localhost:8002/',
    }
}

nei默認(rèn)會(huì)在8002下啟動(dòng)mock服務(wù)器强经,因此,在開(kāi)發(fā)環(huán)境中寺渗,我們可以像以往一樣匿情,使用nei平臺(tái)對(duì)接口和數(shù)據(jù)模型進(jìn)行管理,最后我們只要將webpack-dev-server的接口代理到nei下即可信殊。同樣炬称,我們也可以在開(kāi)發(fā)環(huán)境中隨時(shí)更換成線(xiàn)上服務(wù)器(需要解決csrf以及cookie的問(wèn)題),用本地訪問(wèn)真實(shí)的數(shù)據(jù)也成為了可能涡拘。

總結(jié)

目前玲躯,該套方案已經(jīng)成功運(yùn)行上線(xiàn)了一段時(shí)間,也得到了組內(nèi)同學(xué)的認(rèn)可,不過(guò)跷车,依舊還是有許多地方可以?xún)?yōu)化棘利,比如

  1. ftl是否可以去掉,因?yàn)槟壳霸摲桨敢槍?duì)本地開(kāi)發(fā)環(huán)境與線(xiàn)上部署環(huán)境生成不同的代碼朽缴,會(huì)有一定的開(kāi)發(fā)開(kāi)銷(xiāo)善玫,如果去掉類(lèi)似登錄狀態(tài)該如何判斷。
  2. webpack所構(gòu)建的sourcemap斷點(diǎn)會(huì)出現(xiàn)一到兩行偏差密强,沒(méi)有純?cè)创a調(diào)試那么方便
  3. 目前babel插件處理了 css,text,regular等NEJ插件茅郎,如果未來(lái)NEJ又有新的關(guān)鍵字插件,需要一起更新或渤,防止轉(zhuǎn)化失敗系冗。
  4. VUE代理的Regular組件,需要不斷的監(jiān)聽(tīng)事件劳坑,才可以兼容以前的代碼并完成單向數(shù)據(jù)流操作毕谴。

如果大家對(duì)這方案有興趣成畦,并且有更好的建議距芬,歡迎隨時(shí)聯(lián)系我哦~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市循帐,隨后出現(xiàn)的幾起案子框仔,更是在濱河造成了極大的恐慌,老刑警劉巖拄养,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件离斩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡瘪匿,警方通過(guò)查閱死者的電腦和手機(jī)跛梗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)棋弥,“玉大人核偿,你說(shuō)我怎么就攤上這事⊥缛荆” “怎么了漾岳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)粉寞。 經(jīng)常有香客問(wèn)我尼荆,道長(zhǎng),這世上最難降的妖魔是什么唧垦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任捅儒,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘巧还。我一直安慰自己蓄愁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布狞悲。 她就那樣靜靜地躺著撮抓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪摇锋。 梳的紋絲不亂的頭發(fā)上丹拯,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音荸恕,去河邊找鬼乖酬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛融求,可吹牛的內(nèi)容都是我干的咬像。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼生宛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼县昂!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起陷舅,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤倒彰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后莱睁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體待讳,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年仰剿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了创淡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡南吮,死狀恐怖琳彩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情旨袒,我是刑警寧澤汁针,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站砚尽,受9級(jí)特大地震影響施无,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜必孤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一猾骡、第九天 我趴在偏房一處隱蔽的房頂上張望瑞躺。 院中可真熱鬧,春花似錦兴想、人聲如沸幢哨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捞镰。三九已至,卻和暖如春毙替,著一層夾襖步出監(jiān)牢的瞬間岸售,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工厂画, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凸丸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓袱院,卻偏偏與公主長(zhǎng)得像屎慢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忽洛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容