本文详解BeautyWe.js,一套专注于微信小程序的企业级开发范式。通过Core核心包装原生App/Page实现插件化,提供Storage、ListPage、Cache等官方插件解决复杂逻辑。结合Framework框架与CLI工具,提供多环境构建、全局窗口及NPM支持,助力打造简单漂亮的微信小程序项目。
简介

BeautyWe.js 概述与核心卖点
BeautyWe.js 是一套专为微信小程序打造的企业级开发范式,其核心愿景在于:
让企业级微信小程序项目中的代码实现更简洁、更优雅的呈现。
关于命名由来:
Write beautiful code for wechat mini program by the beautiful we!
这里的「We」既代表团队(我们的We),也指代微信(微信的We),寓意双方共同创造美好代码。
其核心卖点包括:
1. 专注微信小程序原生环境,确保代码原汁原味。
- 2. 因专注单一平台,源码结构相对简单。
- 3. 采用插件化编程模式,便于复杂逻辑的封装与复用。
- 此外,还提供一系列官方插件及一套开箱即用的项目框架,涵盖工程化、规范及环境适配方案。
- 再加上一些配套设施:
- 官方插件列表:
- 一套集成工程化、项目规范及小程序特有解决方案的框架。
- 配套CLI工具,支持快速创建应用、页面及组件。
架构组成:Core、Plugins 与 Framework
BeautyWe.js 主要由以下部分构成:
核心模块 - BeautyWe Core
对原生 App 和 Page 进行抽象包装,保持传统开发习惯,同时开放部分原生能力以支持插件化扩展。
官方插件集 - BeautyWe Plugins
基于 Core 的插件化特性,封装复杂逻辑并实现插拔式使用。官方提供了增强存储、发布/订阅、状态机、Logger及缓存策略等常见需求插件。
项目框架 - BeautyWe Framework
定义项目组织形式,集成 BeautyWe Core,提供全局窗口、开发规范、多环境开发、全局配置及 NPM 支持等解决方案。
命令行工具 - BeautyWe Cli
提供快速创建应用、页面、插件及项目构建的命令行功能,并支持自定义创建模板。
示例演示
安装步骤

使用 BeautyWe 包装你的应用

完成上述步骤后,即可使用 BeautyWe Plugin 提供的各项能力。

插件化机制:原生能力扩展与钩子函数
开放原生 App/Page 并支持插件化
new BtApp({...}) 的执行结果是对原生应用进行包装,内部包含「插件化」处理逻辑,最终返回一个适配原生 App() 方法的新实例。
接下来深入解析「插件化」的具体实现。
插件化主要开放了原生 App 的四种能力:
1. Data 域
将插件的 Data 域合并至原生 App 的 Data 域,这一机制直观易懂。
2. 原生钩子函数
使原生钩子函数(如 onShow, onLoad)具备插件化能力,允许原生 App 与多个插件同时监听同一钩子。具体机制如下文详述。
3. 事件钩子函数
使与 View 层交互的事件钩子函数实现插件化,尽管实现细节略有差异,但原理与「原生钩子函数」一致。
4. 自定义方法
允许插件向使用者提供 API。为确保 API 优雅,支持在调用插件 API(如 event 插件的 this.event.on(...))时,通过 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。
该设计提供以下功能:
1. 可插件化
只需向对应钩子函数的事件队列插入任务即可。
2. 支持异步
基于 Promise Series 运行,若任务返回 Promise,下一任务将等待其完成;若发生错误,则流转到原生 onError()。
3. 解决微信小程序 app.js 中 getApp() === undefined 问题
该问题本质因 App() 时原生实例未创建所致。由于 Promise 作为微任务注册于下一次循环,执行时 App() 早已完成。
官方插件详解:Storage、ListPage、Cache 与 Logger
官方插件介绍
BeautyWe 官方提供了一系列插件:
- 增强存储: Storage
- 数据列表:List Page
- 缓存策略:Cache
- 日志:Logger
- 事件发布/订阅:Event
- 状态机:Status
使用方式灵活,按需插入即可。
受篇幅限制,下文选取部分有趣插件详解,更多请参考官方文档:BeautyWe
增强存储 Storage
该功能由 @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 官方文档
数据列表 List Page
针对常见的数据列表分页业务场景, @beautywe/plugin-listpage 提供了一套打包方案:
- 满足常用「数据列表分页」业务场景
- 支持分页功能
- 支持多个数据列表
- 自动捕捉下拉重载:
onPullDownRefresh - 自动捕捉上拉加载:
onReachBottom - 内置请求锁,防止用户频繁操作导致的问题
- 提供简单优雅的 API
简单示例:
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
缓存策略 Cache
@beautywe/plugin-cache 提供了微信小程序端缓存策略,底层由 super-cache 支持。
特性
- 提供「服务端接口耗时慢,但加载性能要求高」场景的解决方案
- 满足基本缓存需求,支持读取(get)和保存(set)
- 支持针对缓存进行逻辑代理
- 支持灵活可配置的数据存储方式
工作原理
一般请求数据形式为:页面加载时从服务端获取数据,等待返回后渲染页面。

此模式受服务端接口耗时、网络环境等因素影响加载性能。
对于高加载性能要求的页面(如首页),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
日志 Logger
由 @beautywe/logger-plugin 提供的轻量级日志处理方案,支持:
- 可控的 log level
- 自定义前缀
- 日志统一处理
使用示例
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 控制
可通过配置控制打印哪些 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
工程化框架:CLI、全局窗口与多环境开发
BeautyWe Framework
@beautywe/core 和 @beautywe/plugin-... 为小程序提供了:
- 开放原生,支持插件化 —— 由 core 实现
- 各类插件 —— 由 plugins 提供
然而,开发中仍有许多痛点未解决。
如项目组织、规范、工程化、配置、多环境等。
这正是「BeautyWe Framework」解决的范畴。
作为一套开箱即用的项目框架,它提供以下功能:
- 集成 BeautyWe Core
- NPM 支持
- 全局窗口
- 全局 Page,Component
- 全局配置文件
- 多环境开发
- Example Pages
- 包含正常项目标配:ES2015+, sass, uglify, watch 等
- 以及良好的项目规范(eslint,commit log,目录结构等)
受篇幅限制,选取部分有趣功能详解,更多请参考官方文档: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
可修改内部模板,以满足项目级别的自定义创建需求。
全局窗口
众所周知,微信小程序是「单窗口」交互平台,一个页面对应一个窗口。
业务开发中,常有如下需求:
- 自定义 toast 样式
- 页面底部 copyright
- 全局 loading 样式
- 全局悬浮控件
......
较不优雅的实现是分别制作独立组件,并在每个页面引入。
此做法导致大量重复代码,且每次新建页面均需引入,后期维护繁琐。
「全局窗口」概念旨在所有页面之上保留一块区域,用于放置全局性逻辑与交互。
global-view 组件
这是一个自定义组件,源码位于 /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 支持多环境开发,预设三套策略:
- dev
- test
- prod
可通过命令运行这三个构建策略:
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 | 清除示例页面 | √ |
Node.js Power
Beautywe Framework 代码包含两种运行环境:
- Node.js 运行环境,如构建任务等。
- 微信小程序运行环境,如打包至
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
NPM 支持
BeautyWe Framework 实现 npm 支持的原理简单,总结如下:
使用 webpack 打包
src/npm/index.js,以 commonjs 格式输出至dist/npm/index.js

此举好处:
- 实现简单。
- 使 npm 包集中管理,每次引入依赖时需谨慎思考,避免泛滥(尤其在多人开发中)。
- 使用 ll dist/npm/index.js 命令可快速查看项目中 npm 包占用容量。
新增 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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。