韩日午夜在线资源一区二区_成人AV综合在线网站_欧美亚洲日本国产黑白配_大臣们罚皇上带玉势上朝_全彩口工漫画无遮爱丽丝

首都青年網(wǎng) |
  • 手機客戶端
  • 微信
您的位置:首頁 > 社會 > 正文
京東到家小程序-在性能及多端能力的探索實踐|世界要聞
來源:京東云開發(fā)者 2023-06-30 06:54:56

一、前言

京東到家小程序最初只有微信小程序,隨著業(yè)務(wù)的發(fā)展,同樣的功能需要支持容器越來越多,包括支付寶小程序、京東小程序、到家APP、京東APP等,然而每個端分開實現(xiàn)要面臨研發(fā)成本高、不一致等問題。

為了提高研發(fā)效率,經(jīng)過技術(shù)選型采用了taro3+原生混合開發(fā)模式,本文主要講解我們是如何基于taro框架,進行多端能力的探索和性能優(yōu)化。

二、多端能力的探索

1.到家小程序基于taro3的架構(gòu)流程圖

?框架分層解釋

1.配置層:主要包含編譯配置、路由配置、分包加載、拓展口子。


(資料圖片)

2.視圖層:主要完成App生命周期初始化、頁面初始化、注入宿主事件、解析配置為頁面和組件綁定事件和屬性。

3.組件庫:是一個單獨維護的項目,多端組件庫包括業(yè)務(wù)組件和原子組件,可由視圖層根據(jù)配置動態(tài)加載組件。

//渲染主入口     render() {        let { configData, isDefault, isLoading } = this.state;        const pageInfo = { ...this.pageInfoValue, ...this._pageInfo }        return (            <MyContext.Provider value={pageInfo}>                <View                    className={style.bg}                >                     {//動態(tài)渲染模板組件                        configData &&                        configData.map((item, key) => {                            return this.renderComponent(item, key);                        })                    }                </View>                {isLoading && <Loading></Loading>}            </MyContext.Provider>        );    }     //渲染組件 注入下發(fā)配置事件和屬性     renderComponent(item, key) {        const AsyncComponent = BussinesComponent[item.templateName];        if (AsyncComponent) {            return (                <AsyncComponent                    key={key}                    dataSource={item.data}                    {...item.config}                    pageEvent={pageEvent}                ></AsyncComponent>            );        } else {            return null;        }    }

4.邏輯層:包括業(yè)務(wù)處理邏輯,請求、異常、狀態(tài)、性能、公共工具類,以及與基礎(chǔ)庫對接的適配能力。

5.基礎(chǔ)庫: 提供基本能力,定位、登錄、請求、埋點等基礎(chǔ)功能,主要是抹平各端基礎(chǔ)功能的差異。

2、基礎(chǔ)庫

1.統(tǒng)一接口,分端實現(xiàn),差異內(nèi)部抹平

關(guān)于基礎(chǔ)庫我們采用分端實現(xiàn)的方式,即統(tǒng)一接口的多端文件。

??基礎(chǔ)庫如何對接在項目里,修改config/index.js,結(jié)合taro提供的MultiPlatformPlugin插件編譯。

const baseLib = "@dj-lib/login"   //增加別名,便于后續(xù)基礎(chǔ)庫調(diào)整切換  alias: {    "@djmp": path.resolve(__dirname, "..", `./node_modules/${baseLib}/build`),  },  //修改webpack配置,h5和mini都要修改  webpackChain(chain, webpack) {      chain.resolve.plugin("MultiPlatformPlugin")        .tap(args => {          args[2]["include"] = [`${baseLib}`]          return args        })    }

業(yè)務(wù)里使用方式

import { goToLogin } from "@djmp/login/index";goToLogin()

2.高復用

基礎(chǔ)庫不應(yīng)該耦合框架,那么基礎(chǔ)庫應(yīng)該如何設(shè)計,使其既能滿足taro項目又能滿足原生項目使用呢?

npm基礎(chǔ)庫 在taro經(jīng)過編譯后生成為 vendors文件

npm基礎(chǔ)庫 在小程序原生項目npm構(gòu)建后 生成miniprogram_npm

??
一樣的基礎(chǔ)庫經(jīng)過編譯后會存在2種形態(tài),多占了一份空間呢。

我們對小程序包體積大小是比較敏感的,為了節(jié)約空間,那么如何讓taro使用小程序的miniprogram_npm呢?

先簡單說一下思路,更改 webpack 的配置項,通過externals 配置處理公共方法和公共模塊的引入,保留這些引入的語句,并將引入方式設(shè)置成 commonjs 相對路徑的方式,詳細代碼如下所示。

const config = {  // ...  mini: {    // ...    webpackChain (chain) {      chain.merge({        externals: [          (context, request, callback) => {            const externalDirs = ["@djmp/login"]            const externalDir = externalDirs.find(dir => request.startsWith(dir))            if (process.env.NODE_ENV === "production" && externalDir) {              const res = request.replace(externalDir, `../../../../${externalDir.substr(1)}`)              return callback(null, `commonjs ${res}`)            }            callback()          },        ],      })    }    // ...  }  // ...}

3、組件庫

想要實現(xiàn)跨端組件,難點有三個

第一:如何在多個技術(shù)棧中找到最恰當?shù)哪テ椒桨福煌姆桨笗е?開發(fā)適配的成本不同,而人效提升才是我們最終想要實現(xiàn)的目的;

第二:如何在一碼多端實現(xiàn)組件之后,確保沒有對各個組件的性能產(chǎn)生影響

第三:如何在各項目中進行跨端組件的使用

基于以上,在我們已經(jīng)確定的以Taro為基礎(chǔ)開發(fā)框架的前提下,我們進行了整體跨端組件方案實現(xiàn)的規(guī)劃設(shè)計:

??在組件層面,劃分為三層:UI基礎(chǔ)組件和業(yè)務(wù)組件 為最底層;容器組件是中間層,最上層是業(yè)務(wù)模板組件;我們首先從UI基礎(chǔ)組件與業(yè)務(wù)組件入手,進行方案的最終確認;

調(diào)研過程中,UI組件和業(yè)務(wù)組件主要從API、樣式、邏輯三個方面去調(diào)研跨端的復用率:

??經(jīng)過以上調(diào)研得出結(jié)論:API層面仍需要使用各自技術(shù)棧進行實踐,通過屬性一致的方式進行API層面的磨平;樣式上,基礎(chǔ)都使用Sass語法,通過babel工具在轉(zhuǎn)化過程中生成各端可識別的樣式形式;邏輯上基本是平移,不需要做改動;所以當我們想做跨端組件時,我們最大工作量在于:API的磨平和樣式的跨端寫法的探索;

例:圖片組件的磨平:

??
基于以上,跨端組件的復用方案經(jīng)過調(diào)研是可行的,但是接下來,我們該如何保證轉(zhuǎn)化后的組件能夠和原生組件的性能媲美呢?我們的跨端組件又該如何在各個項目中使用呢?

在這個過程中,我們主要調(diào)研對比兩種方案:

第一:直接利用Taro提供的跨端編輯功能進行轉(zhuǎn)換,轉(zhuǎn)換編譯成RN . 微信小程序 以及H5;

第二:通過babel進行編譯,直接轉(zhuǎn)換成RN原生代碼,微信小程序原生代碼,以及H5原生代碼

對比方向

原碼大小

編譯成本

生成的組件性能

Taro直接編譯

大(攜帶了Taro環(huán)境)

中(Taro直接提供,但需要各端調(diào)試)

與原生相同

通過babel轉(zhuǎn)義

?。ㄖ挥挟斍敖M件的源碼代碼)

中(需要開發(fā)Babel轉(zhuǎn)義組件)

與原生相同

經(jīng)過以上幾組對比,我們最終選用了babel轉(zhuǎn)義的方式。在項目中使用時,發(fā)布到Npm服務(wù)器上,供各個項目進行使用。

方案落地與未來規(guī)劃:

在確認整體的方案方向之后,我們進行了項目的落地,首先搭建了跨端組件庫的運行項目:能夠支持預覽京東小程序、微信小程序以及H5的組件生成的頁面;以下是整個組件從生成到發(fā)布到對應(yīng)項目的全部流程。

??目前已經(jīng)完成了個5種UI組件的實現(xiàn),4種業(yè)務(wù)組件;其中優(yōu)惠券模塊已經(jīng)落地在到家小程序項目中,并已經(jīng)沉淀了跨端組件的設(shè)計規(guī)則和方案。未來一年中,會繼續(xù)跨端組件的實現(xiàn)與落地,從UI、業(yè)務(wù)層到復雜容器以及復雜頁面中。

4、工程化構(gòu)建

1.構(gòu)建微信小程序

因為存在多個taro項目由不同業(yè)務(wù)負責,需要將taro聚合編譯后的產(chǎn)物,和微信原生聚合在一起,才能構(gòu)成完整的小程序項目。

下面是設(shè)計的構(gòu)建流程。

??
為了使其自動化,減少人工操作,在迪迦發(fā)布后臺(到家自研的小程序發(fā)布后臺創(chuàng)建依賴任務(wù)即可,完成整體構(gòu)建并上傳。

??
其中執(zhí)行【依賴任務(wù)】這個環(huán)節(jié)會進行,taro項目聚合編譯,并將產(chǎn)物合并到原生項目。

??迪迦發(fā)布后臺


2.構(gòu)建京東小程序

yarn deploy:jd 版本號 描述

//集成CI上傳工具 jd-miniprogram-ciconst { upload, preview } = require("jd-miniprogram-ci")const path = require("path")const privateKey = "xxxxx"http://要上傳的目錄-正式const projectPath = path.resolve(__dirname, "../../", `dist/jddist`)//要上傳的目錄-本地調(diào)試const projectPathDev = path.resolve(__dirname, "../../", `dist/jddevdist`)const version = process.argv[2] const desc = process.argv[3]//預覽版preview({    privateKey: privateKey,    projectPath: projectPathDev,    base64: false,})//體驗版upload({    privateKey: privateKey,    projectPath: projectPath,    uv: version,    desc: desc,    base64: false,})

3.構(gòu)建發(fā)布h5

yarn deploy:h5

h5的應(yīng)用通常采用 cdn資源 +html入口 這種模式。先發(fā)布cdn資源進行預熱,在發(fā)布html入口進行上線。

主要進行3個操作

1.編譯出h5dist產(chǎn)物,即html+靜態(tài)資源

2.靜態(tài)資源,利用集成 @jd/upload-oss-tools 工具上傳到 cdn。

3.觸發(fā)【行云部署編排】發(fā)布html文件入口

關(guān)于cdn: 我們集成了cdn上傳工具,輔助快速上線。

//集成 @jd/upload-oss-tools上傳工具const UploadOssPlugin = require("@jd/upload-oss-tools");const accessKey = new Buffer.from("xxx", "base64").toString()const secretKey = new Buffer.from("xxx", "base64").toString()module.exports = function (localFullPath, folder) {  return new Promise((resolve) => {    console.log("localFullPath", localFullPath)    console.log("folder", folder)    // 初始化上傳應(yīng)用    let _ploadOssPlugin = new UploadOssPlugin({      localFullPath: localFullPath, // 被上傳的本地絕對路徑,自行配置      access: accessKey, // http://oss.jd.com/user/glist 生成的 access key      secret: secretKey, // http://oss.jd.com/user/glist 生成的 secret key      site: "storage.jd.local",       cover: true, // 是否覆蓋遠程空間文件 默認true      printCdnFile: true, // 是否手動刷新cdn文件 默認false      bucket: "wxconfig", // 空間名字 僅能由小寫字母、數(shù)字、點號(.)、中劃線(-)組成      folder: folder, // 空間文件夾名稱 非必填(1、默認創(chuàng)建當前文件所在的文件夾,2、屏蔽字段或傳undefined則按照localFullPath的路徑一層層創(chuàng)建文件夾)      ignoreRegexp: "", // 排除的文件規(guī)則,直接寫正則不加雙引號,無規(guī)則時空字符串。正則字符串,匹配到的文件和文件夾都會忽略      timeout: "", // 上傳請求超時的毫秒數(shù) 單位毫秒,默認30秒      uploadStart: function (files) { }, // 文件開始上傳回調(diào)函數(shù),返回文件列表參數(shù)      uploadProgress: function (progress) { }, // 文件上傳過程回調(diào)函數(shù),返回文件上傳進度      uploadEnd:  (res) =>{        console.log("上傳完成")        resolve()      },      // 文件上傳完畢回調(diào)函數(shù),返回 {上傳文件數(shù)組、上傳文件的總數(shù),成功數(shù)量,失敗數(shù)量,未上傳數(shù)量    });    _ploadOssPlugin.upload();  })}

三、性能優(yōu)化

性能優(yōu)化是一個亙古不變的話題,總結(jié)來說優(yōu)化方向:包下載階段、js注入階段、請求階段、渲染階段。

以下主要介紹在下載階段如何優(yōu)化包體積,請求階段如何提高請求效率。

(一)體積優(yōu)化

相信使用過taro3的同學,都有個同樣的體會,就是編譯出來的產(chǎn)物過大,主包可能超2M!

1.主包是否開啟

優(yōu)化主包的體積大小 :optimizeMainPackage。

像下面這樣簡單配置之后,可以避免主包沒有引入的 module 不被提取到commonChunks中,該功能會在打包時分析 module 和 chunk 的依賴關(guān)系,篩選出主包沒有引用到的 module 把它提取到分包內(nèi)。

module.exports = {  // ...  mini: {    // ...    optimizeMainPackage: {      enable: true,    },  },}    

2.使用壓縮插件 terser-webpack-plugin

//使用壓縮插件    webpackChain(chain, webpack) {      chain.merge({        plugin: {          install: {            plugin: require("terser-webpack-plugin"),            args: [{              terserOptions: {                compress: true, // 默認使用terser壓縮                keep_classnames: true, // 不改變class名稱                keep_fnames: true // 不改變函數(shù)名稱              }            }]          }        }      })    }

3.把公共文件提取到分包。

mini.addChunkPages:為某些頁面單獨指定需要引用的公共文件。

例如在使用小程序分包的時候,為了減少主包大小,分包的頁面希望引入自己的公共文件,而不希望直接放在主包內(nèi)。那么我們首先可以通過 webpackChain 配置 來單獨抽離分包的公共文件,然后通過 mini.addChunkPages 為分包頁面配置引入分包的公共文件,其使用方式如下:

mini.addChunkPages 配置為一個函數(shù),接受兩個參數(shù)

?pages 參數(shù)為 Map 類型,用于為頁面添加公共文件

?pagesNames 參數(shù)為當前應(yīng)用的所有頁面標識列表,可以通過打印的方式進行查看頁面的標識

例如,為 pages/index/index 頁面添加 eating 和 morning 兩個抽離的公共文件:

mini: {    // ...    addChunkPages(pages: Map<string, string[]>, pagesNames: string[]) {      pages.set("pages/index/index", ["eating", "morning"])    },  },

4.代碼分析

如果以上方式,還達不到我們想要的效果,那么我們只能靜下心來分析下taro的打包邏輯。


??可以執(zhí)行 npm run dev 模式查看產(chǎn)物里的 xxx.LICENSE.txt文件,里面羅列打包了哪些文件,需要自行分析去除冗余。

以下以vendors.LICENSE.txt 為例

???runtime.js: webpack 運行時入口 ,只有2k,沒有優(yōu)化空間。

?taro.js: node_modules 中 Taro 相關(guān)依賴,112k,可以魔改源碼,否則沒有優(yōu)化空間。

?vendors.js: node_modules 除 Taro 外的公共依賴,查看vendors.js.LICENSE.txt文件分析包括哪些文件

?common.js: 項目中業(yè)務(wù)代碼公共邏輯,查看common.js.LICENSE.txt文件分析包括哪些文件

?app.js app生命周期中依賴的文件。查看app.js.LICENSE.txt文件分析包括哪些文件

?app.wxss 公共樣式文件 ,看業(yè)務(wù)需求優(yōu)化,去除非必要的全局樣式。

?base.wxml 取決于使用組件的方式,可優(yōu)化空間較小。

(二)網(wǎng)絡(luò)請求優(yōu)化:

相信大家的業(yè)務(wù)里有多種類型的請求,業(yè)務(wù)類、埋點類、行為分析、監(jiān)控、其他sdk封裝的請求。然而在不同的宿主環(huán)境有不同的并發(fā)限制,比如,微信小程序請求并發(fā)限制 10個,京東等小程序限制為5個。

如下圖,以微信小程序為例,在請求過多時,業(yè)務(wù)與埋點類的請求爭搶請求資源,造成業(yè)務(wù)請求排隊,導致頁面展示滯后,弱網(wǎng)情況甚至造成卡頓。

??那么基于以上問題,如何平衡業(yè)務(wù)請求和非業(yè)務(wù)請求呢?

這里我們有2個方案:

1.動態(tài)調(diào)度方案 https://www.cnblogs.com/rsapaper/p/15047813.html

思路就行將請求分為高優(yōu)和低優(yōu)請求,當發(fā)生阻塞時,將高優(yōu)請求放入請求隊列,低優(yōu)進入等待隊列。


??請求分發(fā)器 QueueRequest:對新的請求進行分發(fā)。

?加入等待隊列:正在進行的請求數(shù)超過設(shè)置的 threshold,且請求為低優(yōu)先級時;

?加入請求池:請求為高優(yōu)先級,或并發(fā)數(shù)未達到 threshold。

等待隊列 WaitingQueue:維護需要延時發(fā)送的請求等待隊列。在請求池空閑或請求超過最長等待時間時,補發(fā)等待請求。

請求池 RequestPool:發(fā)送請求并維護所有正在進行的請求的狀態(tài)。對外暴露正在進行的請求數(shù)量,并在有請求完成時通知等待隊列嘗試補發(fā)。

2.虛擬請求池方案

該思路是將微信的10個請求資源,分成3個請求池,業(yè)務(wù)請求:埋點類:其他請求的比例為6:2:2。比例可以自行調(diào)整。

這樣各類型請求都在自己的請求池,不存在爭搶其他請求池資源,保障了業(yè)務(wù)不被其他請求阻塞。

??實現(xiàn)方式

??方案對比

優(yōu)缺點

動態(tài)調(diào)度(方案一)

虛擬請求池(方案二)

拓展性

成本(開發(fā)、測試、維護)

請求效率

2個方案都可以完成請求資源的分配,但結(jié)合業(yè)務(wù)實際采用的是虛擬請求方案,經(jīng)測試在弱網(wǎng)情況下,請求效率可以提升15%.?

四、總結(jié)和展望

未來一定是一碼多端的方向,所以我們未來在基礎(chǔ)建設(shè)上會投入更多的精力,包括框架層升級優(yōu)化、基礎(chǔ)庫建設(shè)、組件庫建設(shè)、工程化建設(shè)快速部署多端。

在性能優(yōu)化上我們還可以探索的方向有京東小程序分包預加載、分包異步化、京東容器flutter渲染、騰訊skyLine渲染引擎等。

在團隊溝通協(xié)作上會與Taro團隊、京東小程序容器團隊、nut-ui、拼拼等團隊進行學習溝通, 也希望能與大家合作共建。

五、結(jié)束語

京東小程序開放平臺是京東自研平臺,提供豐富的開放能力和底層的引擎支持,目前有開發(fā)者工具、轉(zhuǎn)化工具、可視化拖拽等多種開發(fā)工具可供內(nèi)部研發(fā)同事使用,提升開發(fā)質(zhì)量同時快速實現(xiàn)業(yè)務(wù)功能的上線。內(nèi)部已有京東支付、京東讀書、京東居家等業(yè)務(wù)使用京東小程序作為技術(shù)框架開展其業(yè)務(wù)。

參考:

https://www.cnblogs.com/rsapaper/p/15047813.html

https://taro-docs.jd.com/docs/next/config-detail#minioptimizemainpackage

https://taro-docs.jd.com/docs/next/dynamic-import

https://zhuanlan.zhihu.com/p/396763942

關(guān)鍵詞

圖片新聞
最近更新
Copyright @ 2008-2023 m.879606.com All Rights Reserved 首都青年網(wǎng) 版權(quán)所有
文章采集互聯(lián)網(wǎng),為了傳遞信息,如有出處與本站無關(guān)。 非本站原創(chuàng),系由網(wǎng)友自助上傳或轉(zhuǎn)載、采編于其它媒體,不代表本站的觀點和和看法,一切責任由發(fā)布者承擔,與本站無關(guān)!
版權(quán)文章處理
聯(lián)系方式:QQ  39 60 29 14 2 @qq.com  備案號:皖I(lǐng)CP備2022009963號-20
云南省| 南华县| 从江县| 濉溪县| 金门县| 合作市| 三明市| 五寨县| 闻喜县| 武穴市| 大洼县| 曲沃县| 深州市| 突泉县| 民勤县| 西安市| 义乌市| 衡山县| 霍山县| 年辖:市辖区| 泾阳县| 基隆市| 奎屯市| 贵溪市| 安康市| 龙江县| 永兴县| 随州市| 额济纳旗| 克东县| 原阳县| 平顶山市| 深水埗区| 泽州县| 磴口县| 思南县| 阿鲁科尔沁旗| 奈曼旗| 紫金县| 宿迁市| 阳谷县|