基于weex的考拉移動(dòng)端動(dòng)態(tài)化方案

目錄:

1.為什么要使用熱發(fā)布沛贪;

2.行業(yè)現(xiàn)狀;

3.熱發(fā)布整體設(shè)計(jì)方案废登;

4.上線功能和數(shù)據(jù)情況淹魄;

5.使用過(guò)程中遇到的問(wèn)題;

6.之后需要做的事情堡距;

一甲锡、為什么使用熱發(fā)布

1.實(shí)時(shí)性限制

考拉作為一個(gè)跨境電商類(lèi)的App兆蕉,從最開(kāi)始就注定會(huì)受到政策類(lèi)的條款限制,從而導(dǎo)致經(jīng)常會(huì)出現(xiàn)一些實(shí)時(shí)變更的需求缤沦。而目前這些實(shí)時(shí)性的需求又必須通過(guò)App的直接發(fā)版本來(lái)解決虎韵,不僅發(fā)布周期長(zhǎng),應(yīng)用市場(chǎng)的審核很浪費(fèi)時(shí)間缸废,而且用戶(hù)升級(jí)率也不高包蓝。

2.新功能依賴(lài)升級(jí)

當(dāng)產(chǎn)品策劃提到一些新功能場(chǎng)景時(shí),都必須通過(guò)一個(gè)完整的迭代流程來(lái)進(jìn)行開(kāi)發(fā)企量,最終通過(guò)發(fā)布新版本來(lái)讓用戶(hù)使用到新的功能测萎,開(kāi)發(fā)和測(cè)試周期長(zhǎng)。同時(shí)届巩,用戶(hù)如果想使用新功能硅瞧,必須依賴(lài)升級(jí)。無(wú)法讓舊版本的用戶(hù)使用到新功能恕汇。

3.Bug無(wú)法熱修復(fù)

移動(dòng)開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)出現(xiàn)因?yàn)榭紤]不周導(dǎo)致的一些線上邏輯問(wèn)題或者崩潰問(wèn)題腕唧,一般情況下都會(huì)通過(guò)重新打包發(fā)布應(yīng)用市場(chǎng)來(lái)解決,目前也有更方便的通過(guò)補(bǔ)丁來(lái)解決問(wèn)題拇勃。通過(guò)動(dòng)態(tài)化方案也可以更好的通過(guò)熱發(fā)的方式來(lái)修復(fù)bug四苇。簡(jiǎn)單高效。

4.多端協(xié)作成本高

目前整個(gè)移動(dòng)市場(chǎng)是分為android和ios方咆,當(dāng)需求提出的時(shí)候月腋,會(huì)同時(shí)通知到android和ios兩位開(kāi)發(fā),進(jìn)行需求評(píng)審和功能迭代瓣赂,在需求溝通和實(shí)現(xiàn)過(guò)程中總會(huì)出現(xiàn)各種溝通問(wèn)題導(dǎo)致需求實(shí)現(xiàn)效果不統(tǒng)一榆骚,同時(shí)兩位開(kāi)發(fā)也會(huì)很浪費(fèi)人力。通過(guò)動(dòng)態(tài)化方案煌集,兩端可以共用同一套代碼妓肢,來(lái)解決各自的邏輯,能夠節(jié)省很多人力苫纤。

二碉钠、行業(yè)現(xiàn)狀

目前比較流行的兩種熱發(fā)布解決方案是,facebook的React Native和阿里的weex卷拘。

兩種方案的比較:

相同點(diǎn):

1.兩者的思想是一樣的喊废,都是通過(guò)將js轉(zhuǎn)換成Virtual-dom再映射到Native的對(duì)應(yīng)view組件;

2.遵循 W3C 標(biāo)準(zhǔn)實(shí)現(xiàn)了統(tǒng)一的 JSEngine 和 DOM API栗弟,能夠以web的方式(HTML+CSS+JS)來(lái)開(kāi)發(fā)native頁(yè)面和應(yīng)用污筷;

3.都能夠完成三端渲染,以及功能模塊的動(dòng)態(tài)下發(fā)乍赫;

不同點(diǎn):

1.上層DSL語(yǔ)言不同瓣蛀,前端流行的兩大框架就是React和Vue陆蟆,React Native使用的自家的React,而weex使用的是vue惋增;

2.RN支持ios和Android兩個(gè)平臺(tái)叠殷,web端需要自己支持和兼容;Weex號(hào)稱(chēng)支持到三端诈皿,但是還是有很多的兼容任務(wù)溪猿;

3.RN在打包的時(shí)候會(huì)將基礎(chǔ)解析部分和業(yè)務(wù)邏輯一起打包,所以js文件會(huì)比較大纫塌,而weex只是將業(yè)務(wù)部分打包诊县,具體的解析過(guò)程是在sdk中;所以bundle會(huì)比較写胱蟆依痊;

使用感受:兩種方案我們都進(jìn)行過(guò)調(diào)研,發(fā)現(xiàn)RN在編寫(xiě)過(guò)程中要求還是比較高怎披,沒(méi)有vue上手快胸嘁,而且RN更像是一門(mén)新語(yǔ)言,他為不同的端提供了不同的組件凉逛,而weex更希望這些工作由native做性宏,在weex頁(yè)面中三端使用都是相同的;而且當(dāng)時(shí)RN提供的list組件性能并不是很好状飞,weex提供的是RecyclerView性能相對(duì)好很多毫胜;
因此我們移動(dòng)端動(dòng)態(tài)化采用了weex的方案進(jìn)行。其實(shí)這兩種方案都是采用virtual-dom渲染的方式來(lái)實(shí)現(xiàn)的诬辈,下面簡(jiǎn)單介紹一下weex方案的原理.

weex的原理:

Alt pic

上面這張圖就是weex的原理圖酵使,首先最開(kāi)始是通過(guò)上層的DSL語(yǔ)言來(lái)實(shí)現(xiàn)業(yè)務(wù)功能,實(shí)現(xiàn)完成后會(huì)通過(guò)一些構(gòu)建方式來(lái)進(jìn)行打包焙糟,通過(guò)打包可以將整個(gè)業(yè)務(wù)邏輯打包成一個(gè)jsBundle口渔,jsBundle里面就包含了所實(shí)現(xiàn)的功能,以及可以被下層jsFramework識(shí)別的代碼穿撮。

有了jsBundle之后就可以將它放在后臺(tái)系統(tǒng)中缺脉,這個(gè)就是我們需要熱發(fā)布的功能。

下面一層就是sdk做的事情悦穿,sdk在拿到j(luò)sBundle之后會(huì)通過(guò)jscore進(jìn)行解析攻礼,轉(zhuǎn)換成一個(gè)虛擬dom樹(shù),不同的端在各自的sdk中解析虛擬的dom樹(shù)再渲染成各自端的組件進(jìn)行頁(yè)面的展示咧党。了解了weex的功能原理之后秘蛔,下面介紹下我們整體的熱發(fā)布應(yīng)用方案陨亡。

三、動(dòng)態(tài)化方案整體設(shè)計(jì)

整體的動(dòng)態(tài)化方案功能涉及到前端,后端和移動(dòng)端逞敷,三端的功能需求實(shí)現(xiàn)岛蚤,具體的結(jié)構(gòu)圖如下。

1.整體流程的思維導(dǎo)圖

Alt pic

主要包括三大部分:

weex層芜壁,weex工程負(fù)責(zé)業(yè)務(wù)頁(yè)面的編寫(xiě),打包和發(fā)布;

后臺(tái)層叠赐,熱發(fā)布的后臺(tái)負(fù)責(zé)配置相對(duì)應(yīng)的功能頁(yè)面,提供App檢測(cè)更新的能接口和推送下發(fā)更新包的能力屡江;

app層芭概,App端負(fù)責(zé)檢測(cè)更新,緩存Bundle惩嘉,以及渲染展示的策略罢洲;

下面可以看下整體的熱發(fā)布流程:

Alt pic

最開(kāi)始是編寫(xiě)weex的代碼實(shí)現(xiàn)功能需求,之后通過(guò)webpack打包構(gòu)建jsBundle文黎,將打包構(gòu)建好的jsBundle發(fā)布到自己的服務(wù)器上惹苗,目前使用的是ndp平臺(tái)和nginx服務(wù)器,在ndp平臺(tái)配置好cdn規(guī)則耸峭,這樣每一個(gè)js文件就會(huì)有一個(gè)單獨(dú)的靜態(tài)資源地址桩蓉。之后會(huì)把這個(gè)靜態(tài)地址和頁(yè)面路由信息配置在我們的熱發(fā)布后臺(tái)。用戶(hù)在使用App的時(shí)候就可以拿到熱發(fā)的頁(yè)面渲染劳闹。當(dāng)然再App端也是有兩種方式院究,一種是用戶(hù)主動(dòng)打開(kāi)頁(yè)面觸發(fā)更新接口拉取新數(shù)據(jù),另一種是后臺(tái)發(fā)布后推送給App進(jìn)行后臺(tái)更新本涕。
因?yàn)槲覀冋麄€(gè)策略是分為三部分儡首,所以下面詳細(xì)介紹一下各個(gè)部分所做的工作。

a.weex頁(yè)面開(kāi)發(fā)部署流程

因?yàn)槲冶旧硎强蛻?hù)端開(kāi)發(fā)偏友,對(duì)前端的開(kāi)發(fā)流程不甚了解蔬胯,所以在開(kāi)發(fā)過(guò)程中走了很多彎路。

其實(shí)前端已經(jīng)有很多年的歷史位他,很多開(kāi)發(fā)工具都很完善氛濒,目前我在項(xiàng)目中使用的也是webpack來(lái)進(jìn)行打包構(gòu)建。

因?yàn)閣eex上層的DSL選擇的是vue鹅髓,所以具體需求頁(yè)面的代碼都建議采用vue來(lái)編寫(xiě)(遇到的問(wèn)題可以參考vue的官方文檔https://vuejs.org/index.html舞竿,不過(guò)weex由于是在客戶(hù)端渲染,所以有些vue中俄功能無(wú)法使用到窿冯。

代碼編寫(xiě)不是重點(diǎn)骗奖,重點(diǎn)說(shuō)下webpack打包時(shí)候的配置,我目前是在package.json中配置了兩種打包方案。區(qū)分了開(kāi)發(fā)和生產(chǎn)環(huán)境执桌。在生產(chǎn)環(huán)境下可以對(duì)js文件進(jìn)行壓縮和混淆鄙皇。

通過(guò)webpack在build文件的入口處可以設(shè)置一些公共的組件,減少vue代碼中的引入:

const App = require("${relativePath}")
//全局注冊(cè)組件
Vue.component('wrapperLayout', require("components/wrapper-layout.vue"))

App.el = '#root'
new Vue(App)

我們這里配置了一個(gè)通用的頁(yè)面框架仰挣,包括導(dǎo)航條和網(wǎng)絡(luò)請(qǐng)求loading效果伴逸。

在vue文件build的過(guò)程中要設(shè)置"weex-loader":

let weexConfig = getBaseConfig()
weexConfig.output.filename = 'weex/[name].js'
weexConfig.module.loaders[1].loaders.push('weex-loader')

module.exports = [weexConfig]

build完成之后會(huì)生成對(duì)應(yīng)頁(yè)面的js文件。與java不同膘壶,這些js文件會(huì)將引入的組件和方法全部包含進(jìn)來(lái)错蝴,所以一個(gè)頁(yè)面只有一個(gè)js文件,這樣也就導(dǎo)致了這個(gè)js文件可能會(huì)比較大颓芭。目前來(lái)看顷锰,我們開(kāi)發(fā)的復(fù)雜頁(yè)面最大在2-300k上下。

打包完成后會(huì)將所有的js文件和資源文件通過(guò)構(gòu)建平臺(tái)部署在negix服務(wù)器上亡问,并且關(guān)聯(lián)到cdn馍惹,這樣在頁(yè)面設(shè)置的時(shí)候可以直接使用cdn的鏈接。

image
b.資源圖片處理過(guò)程

資源圖片目前了解到的可以采用五種方式:local,base64,CDN,iconfont,SVG玛界。目前我們采用的主要是base64和CDN的方式万矾,而前端活動(dòng)頁(yè)采用的方式是iconfont。

2.后臺(tái)接口和數(shù)據(jù)庫(kù)設(shè)計(jì)

a.后臺(tái)數(shù)據(jù)庫(kù)表結(jié)構(gòu)設(shè)計(jì)

后臺(tái)數(shù)據(jù)庫(kù)中存放bundle信息的表結(jié)構(gòu)參數(shù)為:

bundleId慎框,minSupportVersion良狈,bundleVersion,bundleModule笨枯,fileDownloadUrl薪丁,loadType,desc馅精,person严嗜,time

bundleId:當(dāng)前頁(yè)面的唯一標(biāo)識(shí);

minSupportVersion:當(dāng)前頁(yè)面最低可以支持到的App版本號(hào)洲敢;

bundleVersion:當(dāng)前bundle的發(fā)布版本漫玄;

bundleModule:當(dāng)前bundle所屬模塊;

fileDownLoadUrl:bundle的下載地址压彭;

loadType:當(dāng)前bundle頁(yè)面可以使用的加載方式睦优,1:網(wǎng)絡(luò)檢查,先使用本地壮不,二次加載最新汗盘;2:網(wǎng)絡(luò)檢查更新,當(dāng)此即加載询一,使用最新隐孽;

desc:當(dāng)前bundle更新情況的的描述信息癌椿;

person:更新者;

time:更新和上傳時(shí)間菱阵;

數(shù)據(jù)庫(kù)中的表結(jié)構(gòu)為:

bundleId minSupportVersion bundleVersion bundleModule fileDownloadUrl loadType desc person time
recommendDetail 3.9 1 seeding http://gala/3.9/recommend/recommenddetail.js 1 更新了xxx,changeLog... 張三 2017-10-16

** 其中bundleId和minSupportVersion一起作為唯一標(biāo)識(shí) **踢俄;一旦兩個(gè)有一個(gè)有變化,就做為一條新的數(shù)據(jù)

** 數(shù)據(jù)庫(kù)的操作有兩種情況: **

** 1.native無(wú)改動(dòng) **

某次更新的內(nèi)容送粱,并不依賴(lài)于WeexSdk和Native的更改,所以之前的所有版本都支持掂之,則后臺(tái)接口直接數(shù)據(jù)庫(kù)中根據(jù)bundleId和appVersion查詢(xún)到當(dāng)前這條數(shù)據(jù)抗俄,更新bundleVersion(加一),替換fileDownloadUrl為新的地址即可世舰。

例如:原來(lái)數(shù)據(jù)庫(kù)中存的是:

bundleId minSupportVersion bundleVersion bundleModule fileDownloadUrl loadType desc person time
recommendDetail 3.9 1 seeding http://gala/3.9/recommend/recommenddetail.js 1 更新了xxx,changeLog... 張三 2017-10-16

則更新成:

bundleId minSupportVersion bundleVersion bundleModule fileDownloadUrl loadType desc person time
recommendDetail 3.9 2 seeding http://gala/3.9/recommend/recommenddetail.js 1 更新了xxx,changeLog... 張三 2017-10-16

只是文件和版本變了动雹,其他都不變;這樣3.9和4.0版本的App都可以使用此次開(kāi)發(fā)的新功能跟压。

** 2.native有改動(dòng) **

之前的某個(gè)版本在數(shù)據(jù)庫(kù)中有一條當(dāng)前頁(yè)面的數(shù)據(jù)胰蝠。新版本這次更新的內(nèi)容,最新版本才可以用震蒋,之前所有的舊版本都無(wú)法使用茸塞,則在數(shù)據(jù)庫(kù)中插入一條新數(shù)據(jù)。

例如:原來(lái)數(shù)據(jù)庫(kù)中存的是:

bundleId minSupportVersion bundleVersion bundleModule fileDownloadUrl loadType desc person time
recommendDetail 3.9 1 seeding http://gala/3.9/recommend/recommenddetail.js 1 更新了xxx,changeLog... 張三 2017-10-15

則更新成:

bundleId minSupportVersion bundleVersion bundleModule fileDownloadUrl loadType desc person time
recommendDetail 3.9 1 seeding http://gala/3.9/recommend/recommenddetail.js 1 更新了xxx,changeLog... 張三 2017-10-15
recommendDetail 4.0 1 seeding http://gala/4.0/recommend/recommenddetail.js 1 更新了xxx,changeLog... 張三 2017-10-16

此次更新之后查剖,數(shù)據(jù)庫(kù)中針對(duì)recommendDetail的bundleId會(huì)存在兩條信息钾虐,第一條給3.9到4.0版本之間的App使用,第二條給4.0版本之后的App使用笋庄。

b.后臺(tái)接口設(shè)計(jì)

app中檢測(cè)更新的接口:

requestParams:bundleId效扫,appVersion;

后臺(tái)接口需根據(jù)bundleId直砂,appVersion在數(shù)據(jù)庫(kù)中查詢(xún)得到不大于appVersion的minSupportVersion最大的一條數(shù)據(jù)返回菌仁;

response:

{
    "bundleId":"recommendDetail",
    "minSupportVersion":3.9,
    "bundleVersion":1,
    "fileDownloadUrl":"http://gala/3.9/recommend/recommendDetail.js",
    "loadType":1
}

例如:
1.如果當(dāng)前App的版本是3.9,

針對(duì)上面的第一種情況静暂,后臺(tái)要返回給我最新的bundleVersoin為2的recommendDetail.js文件

針對(duì)第二種情況济丘,后臺(tái)要返回給我3.9版本可用的recommendDetail.js文件,

2.如果當(dāng)前App的版本是4.0洽蛀,

針對(duì)上面的第一種情況闪盔,后臺(tái)要返回給我minSupportVersion為3.9,

針對(duì)第二種情況辱士,后臺(tái)要返回給我4.0版本可用的recommendDetail.js文件泪掀。

c.后臺(tái)配置管理系統(tǒng)
image

3.App端更新展示策略

a.更新邏輯整體架構(gòu)
Alt pic

通過(guò)熱發(fā)后臺(tái)我們可以根據(jù)對(duì)應(yīng)的bundleId拿到需要顯示的Bundle信息,那么我們的native頁(yè)面又是如何知道要用那個(gè)bundleId去請(qǐng)求颂碘,以及顯示的呢异赫?下面看下我們App端的策略椅挣,這個(gè)圖是我們整個(gè)App端的架構(gòu),其中又分為兩大部分塔拳,一部分是路由策略鼠证,一部分是檢測(cè)更新策略。

路由策略
Alt pic

整個(gè)weex頁(yè)面都是基于路由功能來(lái)進(jìn)行展示和跳轉(zhuǎn)的靠抑。也就是說(shuō)每個(gè)weex頁(yè)面都會(huì)有一個(gè)唯一的uri量九。舉一個(gè)例子,比如在App中的A頁(yè)面颂碧,這時(shí)候點(diǎn)了一個(gè)按鈕跳轉(zhuǎn)到B頁(yè)面荠列,而B(niǎo)頁(yè)面是一個(gè)weex頁(yè)面,那么A就會(huì)將B的路由信息傳遞給Router载城,Router會(huì)解析這個(gè)路由信息將他對(duì)應(yīng)的bundleId傳給weexVersionManager肌似,即weex版本管理器,在管理器里拿到bundle進(jìn)行顯示诉瓦,如果B頁(yè)面再出現(xiàn)了跳轉(zhuǎn)邏輯川队,就會(huì)通過(guò)weex和Native的橋接器再將路由信息傳遞給Router進(jìn)行下一次跳轉(zhuǎn)。

顯示更新策略
Alt pic

上面這部分就是Bundle加載和檢測(cè)更新的部分睬澡,具體流程可以看下下面的流程圖固额,這里主要分為兩部分,一部分是顯示策略煞聪,一部分是檢測(cè)更新策略对雪。
先看一下顯示的流程,根據(jù)之前的流程米绕,路由中將頁(yè)面對(duì)應(yīng)的bundleId傳給VersionManager瑟捣,versionManager在拿到bundleId之后會(huì)先在本地檢查是否有可以使用的緩存,如果有緩存會(huì)先取緩存來(lái)加載栅干,如果本地沒(méi)有緩存迈套,則會(huì)去熱發(fā)布后臺(tái)請(qǐng)求最新的bundle,請(qǐng)求回來(lái)之后再判斷是否需 要刷新當(dāng)前頁(yè)面來(lái)進(jìn)行顯示碱鳞。如果網(wǎng)絡(luò)失敗了也會(huì)給用戶(hù)一個(gè)網(wǎng)絡(luò)錯(cuò)誤的提示桑李。
右邊這部分就是檢測(cè)更新的流程,檢測(cè)更新的過(guò)程是在后臺(tái)執(zhí)行的窿给,不會(huì)影響用戶(hù)前臺(tái)的交互贵白。在開(kāi)始檢測(cè)的時(shí)候會(huì)去后臺(tái)查詢(xún)是否有新的bundle可用,拿到返回的數(shù)據(jù)后會(huì)判斷當(dāng)前這個(gè)bundle是否已經(jīng)下載過(guò)了崩泡,如果已經(jīng)下載過(guò)了說(shuō)明本地就是最新的禁荒,則不會(huì)再做其他事情,也不會(huì)影響用戶(hù)的使用角撞。如果 本地沒(méi)有下載過(guò)呛伴,說(shuō)明需要更新和覆蓋之前的緩存勃痴,那么就會(huì)去下載這個(gè)jsBundle,下載成功后將jsBUndle緩存起來(lái)热康。再根據(jù)之前協(xié)議規(guī)則中設(shè)置的loadType進(jìn)行區(qū)分沛申。之前提到了loadType是分為當(dāng)次加載和二次加載,如果是當(dāng)次加載會(huì)直接刷新頁(yè)面姐军,如果是二次加載則等到用戶(hù)第二次進(jìn)入 的時(shí)候才會(huì)使用這個(gè)最新的铁材。

四、線上頁(yè)面及數(shù)據(jù)情況

在考拉AndroidApp中奕锌,目前weex頁(yè)面在考拉App中的占比達(dá)到了10%著觉。目前上線的功能是種草社區(qū)和小考拉問(wèn)答絕大部分頁(yè)面。如下圖:

Alt pic

Alt pic

Alt pic

性能情況:整個(gè)頁(yè)面的渲染時(shí)長(zhǎng)可以維持在1秒內(nèi)歇攻。其中下載js時(shí)長(zhǎng)是:100-200ms固惯。正常頁(yè)面渲染時(shí)長(zhǎng)在150-300ms左右

五梆造、一些經(jīng)驗(yàn)總結(jié)

1.關(guān)于.9圖片的使用:
在img標(biāo)簽里可以使用.9圖片缴守,但是要將resize屬性設(shè)置為stretch,如下:

<img class="comment-reply-bg" src="local: //res/bg_comment_reply" resize="stretch"/>

2.關(guān)于class樣式切換:

<div class="focus-common" :class="[focusStatus?'focused-container':'focus-container']" >

3.style樣式切換:

:style="{color: focusStatus?'#999999':'#8CAA5E'}"`

4.父組件調(diào)用子組件的方法和data:

在子組件中設(shè)置ref即id镇辉,在父組件中即可通過(guò)ref來(lái)獲取到對(duì)應(yīng)的子view調(diào)用子view的方法:

父vue:
<recommendDetailPage ref="detailPage"></recommendDetailPage>
this.$refs.detailPage.setData(this.$refs.detailPage[0].recommendDetail)

5.子組件給父組件回調(diào):

//子組件通過(guò)emit通知父組件屡穗,event中傳參數(shù)

showGoBack(event) {
    this.$emit('showgoback',event);
},

//父組件使用子組件時(shí),html中聲明這個(gè)方法忽肛,js中調(diào)用方法

<bridgeWebview :loadUrl="url" class="webview_style" @showgoback="showGoBack"></bridgeWebview>

showGoBack(event) {
    console.log("event.canGoBack2:"+event.canGoBack);
},

6.text顯示問(wèn)題

text標(biāo)簽中的內(nèi)容不能換行村砂,否則在手機(jī)上顯示會(huì)出現(xiàn)換行;下面代碼中第二個(gè)會(huì)顯示兩行屹逛。例如:

1. <text >hello world</text> 

2. <text >hello world
    </text>

六础废、之后還需要做的事情

1.三端共建,提高效率
我們考拉移動(dòng)端目前也在三端通用性上進(jìn)行了進(jìn)一步的調(diào)研和實(shí)現(xiàn)罕模。因?yàn)閕os和android兩端之前的底層支持情況不一樣评腺,導(dǎo)致在共建底層接口和共建組件,以及溝通上會(huì)花費(fèi)一些時(shí)間淑掌。之后的目的主要是可以完善底層的共建框架蒿讥,這樣上層的業(yè)務(wù)才可以在三端通用,提高開(kāi)發(fā)效率抛腕。

2.組件weex的熱發(fā)布
目前我的開(kāi)發(fā)的weex都是頁(yè)面級(jí)別的芋绸,后續(xù)會(huì)在組件級(jí)別上進(jìn)行一些嘗試。并且抽離這些公共組件担敌,打包成npm包摔敛,可以在多個(gè)項(xiàng)目中共用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末全封,一起剝皮案震驚了整個(gè)濱河市舷夺,隨后出現(xiàn)的幾起案子苦酱,更是在濱河造成了極大的恐慌,老刑警劉巖给猾,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疫萤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡敢伸,警方通過(guò)查閱死者的電腦和手機(jī)扯饶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)池颈,“玉大人尾序,你說(shuō)我怎么就攤上這事∏椋” “怎么了每币?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)琢歇。 經(jīng)常有香客問(wèn)我兰怠,道長(zhǎng),這世上最難降的妖魔是什么李茫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任揭保,我火速辦了婚禮,結(jié)果婚禮上魄宏,老公的妹妹穿的比我還像新娘秸侣。我一直安慰自己,他們只是感情好宠互,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布味榛。 她就那樣靜靜地躺著,像睡著了一般予跌。 火紅的嫁衣襯著肌膚如雪搏色。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天匕得,我揣著相機(jī)與錄音继榆,去河邊找鬼。 笑死汁掠,一個(gè)胖子當(dāng)著我的面吹牛略吨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播考阱,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼翠忠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了乞榨?” 一聲冷哼從身側(cè)響起秽之,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤当娱,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后考榨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跨细,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年河质,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冀惭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掀鹅,死狀恐怖散休,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乐尊,我是刑警寧澤戚丸,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站扔嵌,受9級(jí)特大地震影響限府,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜对人,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一谣殊、第九天 我趴在偏房一處隱蔽的房頂上張望拂共。 院中可真熱鬧牺弄,春花似錦、人聲如沸宜狐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抚恒。三九已至咱台,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俭驮,已是汗流浹背回溺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留混萝,地道東北人遗遵。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逸嘀,于是被迫代替她去往敵國(guó)和親车要。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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