摘要: 小程序框架...javascript
Fundebug經受權轉載,版權歸原做者全部。css
官網:beautywejs.com Repo: beautywehtml
BeautyWe.js 是什麼?前端
它是一套專一於微信小程序的企業級開發範式,它的願景是:java
讓企業級的微信小程序項目中的代碼,更加簡單、漂亮。node
爲何要這樣命名呢?webpack
Write beautiful code for wechat mini program by the beautiful we!git
「We」 既是咱們的 We,也是微信的 We,Both beautiful!github
那麼它有什麼賣點呢?web
它由如下幾部分組成:
BeautyWe Core
,而且提供瞭如:全局窗口、開發規範、多環境開發、全局配置、NPM 等解決方案。下載
用 BeautyWe 包裝你的應用
以後,你就能使用 BeautyWe Plugin 提供的能力了。
new BtApp({...})
的執行結果是對原生的應用進行包裝,其中包含了「插件化」的處理,而後返回一個新的實例,這個實例適配原生的 App()
方法。
下面來說講「插件化」到底作了什麼事情。
首先,插件化開放了原生 App 的四種能力:
onShow
, onLoad
)可插件化。讓原生App與多個插件能夠同時監聽同一個鉤子函數。如何工做的,下面會細說。this.event.on(...)
),API 方法內部仍然能經過 this
獲取到原生實例。原生鉤子函數,事件鉤子函數咱們統一稱爲「鉤子函數」。
對於每個鉤子函數,內部是維護一個以 Series Promise 方式執行的執行隊列。
以 onShow
爲例,將會以這樣的形式執行:
native.onShow → pluginA.onShow → pluginB.onShow → ...
下面深刻一下插件化的原理:
工做原理是這樣的:
new BtApp(...)
包裝,全部的鉤子函數,都會有一個獨立的執行隊列,push
到對應的隊列中。而後每 use
插件的時候,都會分解插件的鉤子函數,往對應的隊列 push
。Native App
(原生)觸發某個鉤子的時候,BtApp
會以 Promise Series 的形式按循序執行對應隊列裏面的函數。onLaunch
和 onLoad
的執行隊列中,會在隊列頂部插入一個初始化的任務(initialize
),它會以同步的方式按循序執行 Initialize Queue
裏面的函數。這正是插件生命週期函數中的 plugin.initialize
。這種設計能提供如下功能:
onError()
中。app.js
中 getApp() === undefinded
問題。 形成這個問題,本質是由於 App()
的時候,原生實例未建立。可是因爲 Promise 在 event loop 中是一個微任務,被註冊在下一次循環。因此 Promise 執行的時候 App()
早已經完成了。BeautyWe 官方提供了一系列的插件:
它們的使用很簡單,哪裏須要插哪裏。 因爲篇幅的緣由,下面挑幾個比較有趣的來說講,更多的能夠看看官方文檔:BeautyWe
該功能由 @beautywe/plugin-storage 提供。
因爲微信小程序原生的數據存儲生命週期跟小程序自己一致,即除用戶主動刪除或超過必定時間被自動清理,不然數據都一直可用。
因此該插件在 wx.getStorage/setStorage
的基礎上,提供了兩種擴展能力:
一些簡單的例子
安裝
import { BtApp } from '@beautywe/core';
import storage from '@beautywe/plugin-storage';
const app = new BtApp();
app.use(storage());
複製代碼
過時控制
// 7天后過時
app.storage.set('name', 'jc', { expire: 7 });
複製代碼
版本隔離
app.use({ appVersion: '0.0.1' });
app.set('name', 'jc');
// 返回 jc
app.get('name');
// 當版本更新後
app.use({ appVersion: '0.0.2' });
// 返回 undefined;
app.get('name');
複製代碼
更多的查看 @beautywe/plugin-storage 官方文檔
對於十分常見的數據列表分頁的業務場景,@beautywe/plugin-listpage
提供了一套打包方案:
onPullDownRefresh
onReachBottom
一個簡單的例子:
import BeautyWe from '@beautywe/core';
import listpage from '@beautywe/plugin-listpage';
const page = new BeautyWe.BtPage();
// 使用 listpage 插件
page.use(listpage({
lists: [{
name: 'goods', // 數據名
pageSize: 20, // 每頁多少條數據,默認 10
// 每一頁的數據源,沒次加載頁面時,會調用函數,而後取返回的數據。
fetchPageData({ pageNo, pageSize }) {
// 獲取數據
return API.getGoodsList({ pageNo, pageSize })
// 有時候,須要對服務器的數據進行處理,dataCooker 是你定義的函數。
.then((rawData) => dataCooker(rawData));
},
}],
enabledPullDownRefresh: true, // 開啓下拉重載, 默認 false
enabledReachBottom: true, // 開啓上拉加載, 默認 false
}));
// goods 數據會被加載到,goods 爲上面定義的 name
// this.data.listPage.goods = {
// data: [...], // 視圖層,經過該字段來獲取具體的數據
// hasMore: true, // 視圖層,經過該字段來識別是否有下一頁
// currentPage: 1, // 視圖層,經過該字段來識別當前第幾頁
// totalPage: undefined,
// }
複製代碼
只須要告訴 listpage
如何獲取數據,它會自動處理「下拉重載」、「上拉翻頁」的操做,而後把數據更新到 this.data.listPage.goods
下。
View 層只須要描述數據怎麼展現:
<view class="good" wx:for="listPage.goods.data">
...
</view>
<view class="no-more" wx:if="listPage.goods.hasMore === false">
沒有更多了
</view>
複製代碼
listpage
還支持多數據列表等其餘更多配置,詳情看:@beautywe/plugin-listpage
@beautywe/plugin-cache
提供了一個微信小程序端緩存策略,其底層由 super-cache 提供支持。
通常的請求數據的形式是,頁面加載的時候,從服務端獲取數據,而後等待數據返回以後,進行頁面渲染:
但這種模式,會受到服務端接口耗時,網絡環境等因素影響到加載性能。
對於加載性能要求高的頁面(如首頁),通常的 Web 開發咱們有不少解決方案(如服務端渲染,服務端緩存,SSR 等)。 可是也有一些環境不能使用這種技術(如微信小程序)。
Super Cache 提供了一箇中間數據緩存的解決方案:
思路:
這種解決方案,捨棄了一點數據的實時性(非第一次請求,只能獲取上一次最新數據),大大提升了前端的加載性能。 適合的場景:
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');
}
}]
}));
複製代碼
假設 API.fetch('xxx/name')
是請求服務器接口,返回數據:data_from_server
那麼:
app.cache.get('name').then((value) => {
// value: 'data_from_server'
});
複製代碼
更多的配置,詳情看:@beautywe/plugin-cache
由 @beautywe/logger-plugin
提供的一個輕量的日誌處理方案,它支持:
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
可經過配置來控制哪些 level 該打印:
page.use(logger({
level: 'warn',
}));
複製代碼
那麼 warn
以上的 log (info
, debug
)就不會被打印,這種知足於開發和生成環境對 log 的不一樣需求。
level 等級以下:
Logger.LEVEL = {
error: 1,
warn: 2,
info: 3,
debug: 4,
};
複製代碼
更多的配置,詳情看:@beautywe/plugin-logger
@beautywe/core
和 @beautywe/plugin-...
給小程序提供了:
可是,還有不少的開發中實際還會遇到的痛點,是上面兩個解決不到的。 如項目的組織、規範、工程化、配置、多環境等等
這些就是,「BeautyWe Framework」要解決的範疇。
它做爲一套開箱即用的項目框架,提供了這些功能:
也是因爲篇幅緣由,挑幾個有趣的來說講,更多的能夠看看官方文檔:BeautyWe
首先安裝 @beautywe/cli
$ npm i @beautywe/cli -g
複製代碼
$ beautywe new app
> appName: my-app
> version: 0.0.1
> appid: 123456
> 這樣能夠麼:
> {
> "appName": "my-app",
> "version": "0.0.1",
> "appid": "123456"
> }
複製代碼
回答幾個問題以後,項目就生成了:
my-app
├── gulpfile.js
├── package.json
└── src
├── app.js
├── app.json
├── app.scss
├── assets
├── components
├── config
├── examples
├── libs
├── npm
├── pages
└── project.config.json
複製代碼
頁面
beautywe new page <path|name>
beautywe new page --subpkg <subPackageName> <path|name>
組件
beautywe new component <name>
插件
beautywe new plugin <name>
在 ./.templates
目錄中,存放着快速建立命令的建立模板:
$ tree .templates
.templates
├── component
│ ├── index.js
│ ├── index.json
│ ├── index.scss
│ └── index.wxml
├── page
│ ├── index.js
│ ├── index.json
│ ├── index.scss
│ └── index.wxml
└── plugin
└── index.js
複製代碼
能夠修改裏面的模板,來知足項目級別的自定義模板建立。
咱們都知道微信小程序是「單窗口」的交互平臺,一個頁面對應一個窗口。 而在業務開發中,每每會有諸如這種述求:
......
稍微不優雅的實現能夠是分別作成獨立的組件,而後每個頁面都引入進來。 這種作法,咱們會有不少的重複代碼,而且每次新建頁面,都要引入一遍,後期維護也會很繁瑣。
而「全局窗口」的概念是:但願全部頁面之上有一塊地方,全局性的邏輯和交互,能夠往裏面擱。
這是一個自定義組件,源碼在 /src/components/global-view
每一個頁面的 wxml 只須要在頂層包一層:
<global-view id="global-view">
...
</global-view>
複製代碼
須要全局實現的交互、樣式、組件,只須要維護這個組件就足夠了。
在 src/config/
目錄中,能夠存放各類全局的配置文件,而且支持以 Node.js 的方式運行。(得益於 Node.js Power 特性)。
如 src/config/logger.js
:
const env = process.env.RUN_ENV || 'dev';
const logger = Object.assign({
prefix: 'BeautyWe',
level: 'debug',
}, {
// 開發環境的配置
dev: {
level: 'debug',
},
// 測試環境的配置
test: {
level: 'info',
},
// 線上環境的配置
prod: {
level: 'warn',
},
}[env] || {});
module.exports.logger = logger;
複製代碼
而後咱們能夠這樣讀取到 config 內容:
import { logger } from '/config/index';
// logger.level 會根據環境不一樣而不一樣。
複製代碼
Beautywe Framework 默認會把 config 集成到 getApp()
的示例中:
getApp().config;
複製代碼
BeautyWe Framework 支持多環境開發,其中預設了三套策略:
咱們能夠經過命令來運行這三個構建策略:
beautywe run dev
beautywe run test
beautywe run prod
複製代碼
Beautywe Framework 源碼默認在兩方面使用了多環境:
gulpfile.js/env/...
)src/config/...
)構建任務 | 說明 | dev | test | prod |
---|---|---|---|---|
clean | 清除dist文件 | √ | √ | √ |
copy | 複製資源文件 | √ | √ | √ |
scripts | 編譯JS文件 | √ | √ | √ |
sass | 編譯scss文件 | √ | √ | √ |
npm | 編譯npm文件 | √ | √ | √ |
nodejs-power | 編譯Node.js文件 | √ | √ | √ |
watch | 監聽文件修改 | √ | ||
scripts-min | 壓縮JS文件 | √ | ||
sass-min | 壓縮scss文件 | √ | ||
npm-min | 壓縮npm文件 | √ | ||
image-min | 壓縮圖片文件 | √ | ||
clean-example | 清除示例頁面 | √ |
Beautywe Framework 的代碼有兩種運行環境:
dist
文件夾的代碼。運行過程
Node.js Power 本質是一種靜態編譯的實現。 把某個文件在 Node.js 環境運行的結果,輸出到微信小程序運行環境中,以此來知足特定的需求。
Node.js Power 會把項目中 src
目錄下相似 xxx.nodepower.js
命名的文件,以 Node.js 來運行, 而後把運行的結果,以「字面量對象」的形式寫到 dist
目錄下對應的同名文件 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;
複製代碼
該文件,通過 Node.js Power 構建以後:
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/
目錄中擴展配置文件,都能被自動打包。
Node.js Power 已經被集成到多環境開發的 dev, test, prod 中去。
固然,你能夠手動運行這個構建任務:
$ gulp nodejs-power
複製代碼
BeautyWe Framework 實現支持 npm 的原理很簡單,總結一句話:
使用 webpack 打包
src/npm/index.js
,以 commonjs 格式輸出到dist/npm/index.js
這樣作的好處:
ll dist/npm/index.js
命令能快速看到項目中的 npm 包使佔了多少容量。在 src/npm/index.js
文件中,進行 export:
export { default as beautywe } from '@beautywe/core';
複製代碼
而後在其餘文件 import:
import { beautywe } from './npm/index';
複製代碼
總的來講,BeautyWe 是一套微信小程序的開發範式。
core
和 plugins
擴展原生,提供複雜邏輯的封裝和插拔式使用。
而 framework
則負責提供一整套針對於微信小程序的企業級項目解決方案,開箱即用。
其中還有更多的內容,歡迎瀏覽官網:beautywejs.com
Fundebug專一於JavaScript、微信小程序、微信小遊戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有陽光保險、核桃編程、荔枝FM、掌門1對一、微脈、青團社等衆多品牌企業。歡迎你們免費試用!