摘要: 小程序框架...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对一、微脉、青团社等众多品牌企业。欢迎你们免费试用!