一個(gè)簡(jiǎn)單的介紹
成都創(chuàng)新互聯(lián)公司是一家專注于成都網(wǎng)站建設(shè)、做網(wǎng)站與策劃設(shè)計(jì),冀州網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設(shè)十年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:冀州等地區(qū)。冀州做網(wǎng)站價(jià)格咨詢:18980820575
BeautyWe.js 是什么?
它是一套專注于微信小程序的企業(yè)級(jí)開(kāi)發(fā)范式,它的愿景是:
讓企業(yè)級(jí)的微信小程序項(xiàng)目中的代碼,更加簡(jiǎn)單、漂亮。
為什么要這樣命名呢?
Write beautiful code for wechat mini program by the beautiful we!
「We」 既是我們的 We,也是微信的 We,Both beautiful!
那么它有什么賣點(diǎn)呢?
它由以下幾部分組成:
一個(gè)插件化的核心 -BeautyWe Core
對(duì) App、Page 進(jìn)行抽象和包裝,保持傳統(tǒng)微信小程序開(kāi)發(fā)姿勢(shì),同時(shí)開(kāi)放部分原生能力,讓其具有「可插件化」的能力。
一些官方插件 —BeautyWe Plugins
得益于 Core 的「可插件化」特性,封裝復(fù)雜邏輯,實(shí)現(xiàn)可插拔。官方對(duì)于常見(jiàn)的需求提供了一些插件:如增強(qiáng)存儲(chǔ)、發(fā)布/訂閱、狀態(tài)機(jī)、Logger、緩存策略等。
一套開(kāi)箱即用的項(xiàng)目框架 -BeautyWe Framework
描述了一種項(xiàng)目的組織形式,開(kāi)箱即用,集成了 BeautyWe Core ,并且提供了如:全局窗口、開(kāi)發(fā)規(guī)范、多環(huán)境開(kāi)發(fā)、全局配置、NPM 等解決方案。
一個(gè)CLI工具 -BeautyWe Cli
提供快速創(chuàng)建應(yīng)用、頁(yè)面、插件,以及項(xiàng)目構(gòu)建功能的命令行工具。并且還支持自定義的創(chuàng)建模板。
一個(gè)簡(jiǎn)單的例子
下載
用 BeautyWe 包裝你的應(yīng)用
之后,你就能使用 BeautyWe Plugin 提供的能力了。
開(kāi)放原生App/Page,支持插件化
new BtApp({...})
的執(zhí)行結(jié)果是對(duì)原生的應(yīng)用進(jìn)行包裝,其中包含了「插件化」的處理,然后返回一個(gè)新的實(shí)例,這個(gè)實(shí)例適配原生的 App()
方法。
下面來(lái)講講「插件化」到底做了什么事情。
首先,插件化開(kāi)放了原生 App 的四種能力:
1.Data 域
把插件的 Data 域合并到原生 App 的 Data 域中,這一塊很容易理解。
2.原生鉤子函數(shù)
使原生鉤子函數(shù)(如 onShow
, onLoad
)可插件化。讓原生App與多個(gè)插件可以同時(shí)監(jiān)聽(tīng)同一個(gè)鉤子函數(shù)。如何工作的,下面會(huì)細(xì)說(shuō)。
3.事件鉤子函數(shù)
使事件鉤子函數(shù)(與 view 層交互的鉤子函數(shù)),盡管在實(shí)現(xiàn)上有一些差異,但是實(shí)現(xiàn)原理跟「原生鉤子函數(shù)」一樣的。
4.自定義方法
讓插件能夠給使用者提供 API。為了保證插件提供的 API 足夠的優(yōu)雅,支持當(dāng)調(diào)用插件 API 的時(shí)候(如 event 插件 this.event.on(...)
),API 方法內(nèi)部仍然能通過(guò) this
獲取到原生實(shí)例。
鉤子函數(shù)的插件化
原生鉤子函數(shù),事件鉤子函數(shù)我們統(tǒng)一稱為「鉤子函數(shù)」。
對(duì)于每一個(gè)鉤子函數(shù),內(nèi)部是維護(hù)一個(gè)以 Series Promise 方式執(zhí)行的執(zhí)行隊(duì)列。
以 onShow
為例,將會(huì)以這樣的形式執(zhí)行:
native.onShow → pluginA.onShow → pluginB.onShow → ...
下面深入一下插件化的原理:
工作原理是這樣的:
new BtApp(...)
包裝,所有的鉤子函數(shù),都會(huì)有一個(gè)獨(dú)立的執(zhí)行隊(duì)列,push
到對(duì)應(yīng)的隊(duì)列中。然后每 use 插件的時(shí)候,都會(huì)分解插件的鉤子函數(shù),往對(duì)應(yīng)的隊(duì)列 push
。Native App
(原生)觸發(fā)某個(gè)鉤子的時(shí)候,BtApp
會(huì)以 Promise Series 的形式按循序執(zhí)行對(duì)應(yīng)隊(duì)列里面的函數(shù)。onLaunch
和 onLoad
的執(zhí)行隊(duì)列中,會(huì)在隊(duì)列頂部插入一個(gè)初始化的任務(wù)(initialize
),它會(huì)以同步的方式按循序執(zhí)行 Initialize Queue
里面的函數(shù)。這正是插件生命周期函數(shù)中的 plugin.initialize
。這種設(shè)計(jì)能提供以下功能:
1.可插件化
只需要往對(duì)應(yīng)鉤子函數(shù)的事件隊(duì)列中插入任務(wù)。
2.支持異步
由于是以 Promise Series 方式運(yùn)行的,其中一個(gè)任務(wù)返回一個(gè) Promise,下一個(gè)任務(wù)會(huì)等待這個(gè)任務(wù)完成再開(kāi)始。如果發(fā)生錯(cuò)誤,會(huì)流轉(zhuǎn)到原生的 onError() 中。
3.解決了微信小程序 app.js 中 getApp() === undefinded 問(wèn)題
造成這個(gè)問(wèn)題,本質(zhì)是因?yàn)?App()
的時(shí)候,原生實(shí)例未創(chuàng)建。但是由于 Promise 在 event loop 中是一個(gè)微任務(wù),被注冊(cè)在下一次循環(huán)。所以 Promise 執(zhí)行的時(shí)候 App()
早已經(jīng)完成了。
一些官方插件
BeautyWe 官方提供了一系列的插件:
它們的使用很簡(jiǎn)單,哪里需要插哪里。
由于篇幅的原因,下面挑幾個(gè)比較有趣的來(lái)講講,更多的可以看看官方文檔:BeautyWe
增強(qiáng)存儲(chǔ) Storage
該功能由 @beautywe/plugin-storage 提供。
由于微信小程序原生的數(shù)據(jù)存儲(chǔ)生命周期跟小程序本身一致,即除用戶主動(dòng)刪除或超過(guò)一定時(shí)間被自動(dòng)清理,否則數(shù)據(jù)都一直可用。
所以該插件在 wx.getStorage/setStorage
的基礎(chǔ)上,提供了兩種擴(kuò)展能力:
一些簡(jiǎn)單的例子
安裝
import { BtApp } from '@beautywe/core'; import storage from '@beautywe/plugin-storage'; const app = new BtApp(); app.use(storage());
過(guò)期控制
// 7天后過(guò)期 app.storage.set('name', 'jc', { expire: 7 });
版本隔離
app.use({ appVersion: '0.0.1' }); app.set('name', 'jc'); // 返回 jc app.get('name'); // 當(dāng)版本更新后 app.use({ appVersion: '0.0.2' }); // 返回 undefined; app.get('name');
更多的查看 @beautywe/plugin-storage 官方文檔
數(shù)據(jù)列表 List Page
對(duì)于十分常見(jiàn)的數(shù)據(jù)列表分頁(yè)的業(yè)務(wù)場(chǎng)景, @beautywe/plugin-listpage
提供了一套打包方案:
onPullDownRefresh
onReachBottom
一個(gè)簡(jiǎn)單的例子:
import BeautyWe from '@beautywe/core'; import listpage from '@beautywe/plugin-listpage'; const page = new BeautyWe.BtPage(); // 使用 listpage 插件 page.use(listpage({ lists: [{ name: 'goods', // 數(shù)據(jù)名 pageSize: 20, // 每頁(yè)多少條數(shù)據(jù),默認(rèn) 10 // 每一頁(yè)的數(shù)據(jù)源,沒(méi)次加載頁(yè)面時(shí),會(huì)調(diào)用函數(shù),然后取返回的數(shù)據(jù)。 fetchPageData({ pageNo, pageSize }) { // 獲取數(shù)據(jù) return API.getGoodsList({ pageNo, pageSize }) // 有時(shí)候,需要對(duì)服務(wù)器的數(shù)據(jù)進(jìn)行處理,dataCooker 是你定義的函數(shù)。 .then((rawData) => dataCooker(rawData)); }, }], enabledPullDownRefresh: true, // 開(kāi)啟下拉重載, 默認(rèn) false enabledReachBottom: true, // 開(kāi)啟上拉加載, 默認(rèn) false })); // goods 數(shù)據(jù)會(huì)被加載到,goods 為上面定義的 name // this.data.listPage.goods = { // data: [...], // 視圖層,通過(guò)該字段來(lái)獲取具體的數(shù)據(jù) // hasMore: true, // 視圖層,通過(guò)該字段來(lái)識(shí)別是否有下一頁(yè) // currentPage: 1, // 視圖層,通過(guò)該字段來(lái)識(shí)別當(dāng)前第幾頁(yè) // totalPage: undefined, // }
只需要告訴 listpage
如何獲取數(shù)據(jù),它會(huì)自動(dòng)處理「下拉重載」、「上拉翻頁(yè)」的操作,然后把數(shù)據(jù)更新到 this.data.listPage.goods
下。
View 層只需要描述數(shù)據(jù)怎么展示:
... 沒(méi)有更多了
listpage 還支持多數(shù)據(jù)列表等其他更多配置,詳情看: @beautywe/plugin-listpage
緩存策略 Cache
@beautywe/plugin-cache
提供了一個(gè)微信小程序端緩存策略,其底層由 super-cache 提供支持。
特性
How it work
一般的請(qǐng)求數(shù)據(jù)的形式是,頁(yè)面加載的時(shí)候,從服務(wù)端獲取數(shù)據(jù),然后等待數(shù)據(jù)返回之后,進(jìn)行頁(yè)面渲染:
但這種模式,會(huì)受到服務(wù)端接口耗時(shí),網(wǎng)絡(luò)環(huán)境等因素影響到加載性能。
對(duì)于加載性能要求高的頁(yè)面(如首頁(yè)),一般的 Web 開(kāi)發(fā)我們有很多解決方案(如服務(wù)端渲染,服務(wù)端緩存,SSR 等)。
但是也有一些環(huán)境不能使用這種技術(shù)(如微信小程序)。
Super Cache 提供了一個(gè)中間數(shù)據(jù)緩存的解決方案:
思路:
這種解決方案,舍棄了一點(diǎn)數(shù)據(jù)的實(shí)時(shí)性(非第一次請(qǐng)求,只能獲取上一次最新數(shù)據(jù)),大大提高了前端的加載性能。
適合的場(chǎng)景:
使用
import { BtApp } from '@beautywe/core'; import cache from '@beautywe/plugin-cache'; const app = new BtApp(); app.use(cache({ adapters: [{ key: 'name', data() { return API.fetch('xxx/name'); } }] }));
假設(shè) API.fetch('xxx/name')
是請(qǐng)求服務(wù)器接口,返回?cái)?shù)據(jù):data_from_server
那么:
app.cache.get('name').then((value) => { // value: 'data_from_server' });
更多的配置,詳情看:@beautywe/plugin-cache
日志 Logger
由 @beautywe/logger-plugin
提供的一個(gè)輕量的日志處理方案,它支持:
使用
import { BtApp } from '@beautywe/core'; import logger from '@beautywe/plugin-logger'; const page = new BtApp(); page.use(logger({ // options }));
API
page.logger.info('this is info'); page.logger.warn('this is warn'); page.logger.error('this is error'); page.logger.debug('this is debug'); // 輸出 // [info] this is info // [warn] this is warn // [error] this is error // [debug] this is debug
Level control
可通過(guò)配置來(lái)控制哪些 level 該打?。?/p>
page.use(logger({ level: 'warn', }));
那么 warn
以上的 log (info, debug)
就不會(huì)被打印,這種滿足于開(kāi)發(fā)和生成環(huán)境對(duì) log 的不同需求。
level 等級(jí)如下:
Logger.LEVEL = { error: 1, warn: 2, info: 3, debug: 4, };
更多的配置,詳情看: @beautywe/plugin-logger
BeautyWe Framework
@beautywe/core
和 @beautywe/plugin-...
給小程序提供了:
但是,還有很多的開(kāi)發(fā)中實(shí)際還會(huì)遇到的痛點(diǎn),是上面兩個(gè)解決不到的。
如項(xiàng)目的組織、規(guī)范、工程化、配置、多環(huán)境等等
這些就是,「BeautyWe Framework」要解決的范疇。
它作為一套開(kāi)箱即用的項(xiàng)目框架,提供了這些功能:
也是由于篇幅原因,挑幾個(gè)有趣的來(lái)講講,更多的可以看看官方文檔:BeautyWe
快速創(chuàng)建
首先安裝 @beautywe/cli
$ npm i @beautywe/cli -g
創(chuàng)建應(yīng)用
$ beautywe new app > appName: my-app > version: 0.0.1 > appid: 123456 > 這樣可以么: > { > "appName": "my-app", > "version": "0.0.1", > "appid": "123456" > }
回答幾個(gè)問(wèn)題之后,項(xiàng)目就生成了:
my-app ├── gulpfile.js ├── package.json └── src ├── app.js ├── app.json ├── app.scss ├── assets ├── components ├── config ├── examples ├── libs ├── npm ├── pages └── project.config.json
創(chuàng)建頁(yè)面、組件、插件
頁(yè)面
beautywe new page
beautywe new page --subpkg
組件
beautywe new component
插件
beautywe new plugin
自定義模板
在 ./.templates
目錄中,存放著快速創(chuàng)建命令的創(chuàng)建模板:
$ tree .templates .templates ├── component │ ├── index.js │ ├── index.json │ ├── index.scss │ └── index.wxml ├── page │ ├── index.js │ ├── index.json │ ├── index.scss │ └── index.wxml └── plugin └── index.js
可以修改里面的模板,來(lái)滿足項(xiàng)目級(jí)別的自定義模板創(chuàng)建。
全局窗口
我們都知道微信小程序是「單窗口」的交互平臺(tái),一個(gè)頁(yè)面對(duì)應(yīng)一個(gè)窗口。
而在業(yè)務(wù)開(kāi)發(fā)中,往往會(huì)有諸如這種述求:
......
稍微不優(yōu)雅的實(shí)現(xiàn)可以是分別做成獨(dú)立的組件,然后每一個(gè)頁(yè)面都引入進(jìn)來(lái)。
這種做法,我們會(huì)有很多的重復(fù)代碼,并且每次新建頁(yè)面,都要引入一遍,后期維護(hù)也會(huì)很繁瑣。
而「全局窗口」的概念是:希望所有頁(yè)面之上有一塊地方,全局性的邏輯和交互,可以往里面擱。
global-view 組件
這是一個(gè)自定義組件,源碼在 /src/components/global-view
每個(gè)頁(yè)面的 wxml 只需要在頂層包一層:
...
需要全局實(shí)現(xiàn)的交互、樣式、組件,只需要維護(hù)這個(gè)組件就足夠了。
全局配置文件
在 src/config/
目錄中,可以存放各種全局的配置文件,并且支持以 Node.js 的方式運(yùn)行。(得益于 Node.js Power 特性)。
如 src/config/logger.js
:
const env = process.env.RUN_ENV || 'dev'; const logger = Object.assign({ prefix: 'BeautyWe', level: 'debug', }, { // 開(kāi)發(fā)環(huán)境的配置 dev: { level: 'debug', }, // 測(cè)試環(huán)境的配置 test: { level: 'info', }, // 線上環(huán)境的配置 prod: { level: 'warn', }, }[env] || {}); module.exports.logger = logger;
然后我們可以這樣讀取到 config 內(nèi)容:
import { logger } from '/config/index'; // logger.level 會(huì)根據(jù)環(huán)境不同而不同。
Beautywe Framework 默認(rèn)會(huì)把 config 集成到 getApp()
的示例中:
getApp().config;
多環(huán)境開(kāi)發(fā)
BeautyWe Framework 支持多環(huán)境開(kāi)發(fā),其中預(yù)設(shè)了三套策略:
我們可以通過(guò)命令來(lái)運(yùn)行這三個(gè)構(gòu)建策略:
beautywe run dev beautywe run test beautywe run prod
三套環(huán)境的差異
Beautywe Framework 源碼默認(rèn)在兩方面使用了多環(huán)境:
gulpfile.js/env/...
)src/config/...
)構(gòu)建任務(wù)的差異
構(gòu)建任務(wù) | 說(shuō)明 | dev | test | prod |
---|---|---|---|---|
clean | 清除dist文件 | √ | √ | √ |
copy | 復(fù)制資源文件 | √ | √ | √ |
scripts | 編譯JS文件 | √ | √ | √ |
sass | 編譯scss文件 | √ | √ | √ |
npm | 編譯npm文件 | √ | √ | √ |
nodejs-power | 編譯Node.js文件 | √ | √ | √ |
watch | 監(jiān)聽(tīng)文件修改 | √ | ||
scripts-min | 壓縮JS文件 | √ | ||
sass-min | 壓縮scss文件 | √ | ||
npm-min | 壓縮npm文件 | √ | ||
image-min | 壓縮圖片文件 | √ | ||
clean-example | 清除示例頁(yè)面 | √ |
Node.js Power
Beautywe Framework 的代碼有兩種運(yùn)行環(huán)境:
dist
文件夾的代碼。運(yùn)行過(guò)程
Node.js Power 本質(zhì)是一種靜態(tài)編譯的實(shí)現(xiàn)。
把某個(gè)文件在 Node.js 環(huán)境運(yùn)行的結(jié)果,輸出到微信小程序運(yùn)行環(huán)境中,以此來(lái)滿足特定的需求。
Node.js Power 會(huì)把項(xiàng)目中 src 目錄下類似 xxx.nodepower.js 命名的文件,以 Node.js 來(lái)運(yùn)行,
然后把運(yùn)行的結(jié)果,以「字面量對(duì)象」的形式寫到 dist 目錄下對(duì)應(yīng)的同名文件 xxx.nodepower.js 文件去。
以 src/config/index.nodepower.js
為例:
const fs = require('fs'); const path = require('path'); const files = fs.readdirSync(path.join(__dirname)); const result = {}; files .filter(name => name !== 'index.js') .forEach((name) => { Object.assign(result, require(path.join(__dirname, `./${name}`))); }); module.exports = result;
該文件,經(jīng)過(guò) Node.js Power 構(gòu)建之后:
dist/config/index.nodepower.js
:
module.exports = { "appInfo": { "version": "0.0.1", "env": "test", "appid": "wx85fc0d03fb0b224d", "name": "beautywe-framework-test-app" }, "logger": { "prefix": "BeautyWe", "level": "info" } };
這就滿足了,隨意往 src/config/ 目錄中擴(kuò)展配置文件,都能被自動(dòng)打包。
Node.js Power 已經(jīng)被集成到多環(huán)境開(kāi)發(fā)的 dev, test, prod 中去。
當(dāng)然,你可以手動(dòng)運(yùn)行這個(gè)構(gòu)建任務(wù):
$ gulp nodejs-power
NPM
BeautyWe Framework 實(shí)現(xiàn)支持 npm 的原理很簡(jiǎn)單,總結(jié)一句話:
使用 webpack 打包
src/npm/index.js
,以 commonjs 格式輸出到dist/npm/index.js
這樣做的好處:
新增 npm 依賴
在 src/npm/index.js
文件中,進(jìn)行 export:
export { default as beautywe } from '@beautywe/core';
然后在其他文件 import:
import { beautywe } from './npm/index';
更多
總的來(lái)說(shuō),BeautyWe 是一套微信小程序的開(kāi)發(fā)范式。
core 和 plugins 擴(kuò)展原生,提供復(fù)雜邏輯的封裝和插拔式使用。
而 framework 則負(fù)責(zé)提供一整套針對(duì)于微信小程序的企業(yè)級(jí)項(xiàng)目解決方案,開(kāi)箱即用。
其中還有更多的內(nèi)容,歡迎瀏覽官網(wǎng):beautywejs.com
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。