前言
从16年微信小程序内测到现在,各大公司对小程序的开发业务需求越来越大,但是开发者用原生去开发小程序很难受,尤其是业务比较复杂的项目如果用原生开发很难去管理和迭代
使用原生开发的问题:
- 小程序本身不支持常用的css预编译器
- 不支持ES7以上的高级语法,如async await等特性;
- 不支持工程化,如环境、变量等管理
- 缺少统一的request拦截请求
- 缺少统一的本地缓存读取管理
使用框架可以解决的问题:
- 支持css预编译器
- 支持ES7以上语法
- 支持工程化
- 支持脚手架,一键生成项目模板
- 大部分框架支持多端,一套代码多端复用
既然框架可以帮助我们解决这么多问题,那么我们要选择一个框架去使用,在引入开源框架之前需要进行选型,进行充分的分析进而选择最适合的框架。选择开源框架主要从业务功能的满足度、接入成本、项目性能、可维护性等多方面考虑
框架介绍
Wepy
WePY (发音: /'wepi/)是一款让小程序支持组件化开发的框架,通过预编译的手段让开发者可以选择自己喜欢的开发风格去开发小程序。框架的细节优化,Promise,Async Functions的引入都是为了能让开发小程序项目变得更加简单,高效
Mpvue
mpvue 是一个使用 Vue.js 开发小程序的前端框架。框架基于 Vue.js 核心,mpvue 修改了 Vue.js 的 runtime 和 compiler 实现,使其可以运行在小程序环境中,从而为小程序开发引入了整套 Vue.js 开发体验。
主要特性
- 彻底的组件化开发能力:提高代码复用性
- 完整的 Vue.js 开发体验
- 方便的 Vuex 数据管理方案:方便构建复杂应用
- 快捷的 webpack 构建机制:自定义构建策略、开发阶段 hotReload
- 支持使用 npm 外部依赖
- 使用 Vue.js 命令行工具 vue-cli 快速初始化项目
- H5 代码转换编译成小程序目标代码的能力
Taro
Taro 是一套遵循 React 语法规范的 多端开发 解决方案
Uni-app
uni-app 是一个使用 Vue.js 开发跨平台应用的前端框架。
Chamelon
Chameleon/kəˈmiːlɪən/,简写CML,中文名卡梅龙;中文意思变色龙,意味着就像变色龙一样能适应不同环境的跨端整体解决方案。
主要特性
- 目录结构:提供规范化的项目结构,适合于企业级大型应用的开发。
- 视图层:视图层由CML与CMSS编写,核心是一个标准响应式数据驱动视图更新。
- 逻辑层:逻辑层由javascript编写,逻辑层将处理数据后自动更新视图,提供视图层的事件响应方法。
- 多态协议:提供了跨端时各端底层组件与接口统一的解决方案。
- 规范校验:为了提高开发的效率与代码的可维护性,提供了全面的代码规范与校验。
框架选型
业务功能的满足度
一般公司开发团队对业务功能的需求有两种:
-
1、小程序原生基本业务功能的开发,包括用户登录、内容展示、页面交互、图片文档查看等等
-
2、页面开发一版支持微信小程序、百度小程序、H5或快应用等多端兼容需求
基本业务功能
Wepy、Mpvue、Taro、Uni-app、Chamelon几种框架已经支持小程序原生的大部分组件、API,在一般业务功能的开发上没有太大的差异性,在新功能的支持力度上就略有差异
| Wepy | Mpvue | Taro | Uni-app | Chameleon |
|---------------|------------|---------|-----------|----------|--------------|
| latest: 2 year ago | latest: a year ago | latest: 4 days ago | latest: a month ago | latest: 2 month ago |
从上面最新包的发布时间可以看出,Taro、Uni-app和Chameleon对新功能的支持力度比较好,尤其Taro框架支持了小程序原生的写法,这样即使框架不支持的小程序API也可以在不修改项目框架的前提下使用
多端兼容需求
| Wepy | Mpvue | Taro | Uni-app | Chameleon |
|---------------|------------|---------|-----------|----------|--------------|
| 微信小程序 | 微信小程序、支付宝小程序、百度小程序、头条小程序 | H5、微信小程序、支付宝小程序、百度小程序、头条小程序、React Native、快应用、QQ小程序 | H5、微信小程序、支付宝小程序、百度小程序、头条小程序、QQ小程序、Android版、IOS版 | H5、微信小程序、APP端(Chameleon Playground App、Weex playground) |
从框架对各端的兼容性来看,Taro和Uni-app对各端的兼容能力较强
接入成本
选择框架并接入到团队内,需要两种成本:
- 代码成本-新项目建立项目模板成本、老项目代码迁移成本
- 学习成本-团队内的开发人员从0到1熟练使用框架的成本
wepy
给新起项目提供了cli能力
$ npm install @wepy/cli -g # 全局安装 WePY CLI 工具
$ wepy init standard myproj # 使用 standard 模板初始化项目
$ cd myproj # 进入到项目目录
$ npm install # 安装项目依赖包
$ npm run dev # 监听并且编译项目
未给老项目迁移提供能力,只能手动迁移代码
学习成本:wepy有一个比较简单的开源文档,wepy的语法糖是类Vue,基本项目结构和原生小程序类似,对熟悉vue和小程序的同学来说学习成本很低
一个简单的wepy代码示例:
<style lang="less">
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
</style>
<script>
import wepy from 'wepy'
export default class extends wepy.app {
config = {
pages: [
'pages/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: '日历',
navigationBarTextStyle: 'black'
}
}
constructor () {
super()
}
}
</script>
mpvue
给新起项目提供了cli能力
# 1. 全局安装 vue-cli
$ npm install --global vue-cli@2.9
# 2. 创建一个基于 mpvue-quickstart 模板的新项目
$ vue init mpvue/mpvue-quickstart my-project
# 3. 安装依赖,走你
$ cd my-project
$ npm install
$ npm run dev
未给老项目迁移提供能力,只能手动迁移代码
学习成本:mpvue的文档在2018.8.10后再也没有更新过,文档的内容较老也比较简单,其语法糖是vue,为开发者提供了整体的vue的开发体验,对熟悉vue的同学接入成本较低
一个简单的mpvue代码示例:
<template>
<div @click="clickHandle">
<div class="userinfo" @click="bindViewTap">
<img class="userinfo-avatar" v-if="userInfo.avatarUrl" :src="userInfo.avatarUrl" background-size="cover" />
<img class="userinfo-avatar" src="/static/images/user.png" background-size="cover" />
<div class="userinfo-nickname">
<card :text="userInfo.nickName"></card>
</div>
</div>
<form class="form-container">
<input type="text" class="form-control" :value="motto" placeholder="v-model" />
<input type="text" class="form-control" v-model="motto" placeholder="v-model" />
<input type="text" class="form-control" v-model.lazy="motto" placeholder="v-model.lazy" />
</form>
<a href="/pages/counter/main" class="counter">去往Vuex示例页面</a>
</div>
</template>
<script>
import card from '@/components/card'
export default {
data () {
return {
motto: 'Hello miniprograme',
userInfo: {
nickName: 'mpvue',
avatarUrl: 'http://mpvue.com/assets/logo.png'
}
}
},
components: {
card
},
methods: {
bindViewTap () {
const url = '../logs/main'
if (mpvuePlatform === 'wx') {
mpvue.switchTab({ url })
} else {
mpvue.navigateTo({ url })
}
},
clickHandle (ev) {
console.log('clickHandle:', ev)
// throw {message: 'custom test'}
}
},
created () {
// let app = getApp()
}
}
</script>
<style scoped>
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
}
</style>
taro
给新起项目提供了cli能力
# 使用 npm 安装 CLI
$ npm install -g @tarojs/cli
# 使用命令创建模板项目
$ taro init myApp
给老的原生小程序项目提供了代码一键转换的指令
$ taro convert
学习成本:taro有一个完善的开源文档,详细的描述了taro的组件、API支持情况和使用、进阶指南,taro的语法糖是React,对熟悉React同学来说学习成本很低
一个简单的taro代码示例:
import Taro, { Component } from "@tarojs/taro";
import { View, Button } from "@tarojs/components";
export default class Index extends Component {
constructor() {
super(...arguments);
this.state = {
title: "首页",
list: [1, 2, 3]
};
}
componentWillMount() {}
componentDidMount() {}
componentWillUpdate(nextProps, nextState) {}
componentDidUpdate(prevProps, prevState) {}
shouldComponentUpdate(nextProps, nextState) {
return true;
}
add = e => {
// dosth
};
render() {
return (
<View className="index">
<View className="title">{this.state.title}</View>
<View className="content">
{this.state.list.map(item => {
return <View className="item">{item}</View>;
})}
<Button className="add" onClick={this.add}>
添加
</Button>
</View>
</View>
);
}
}
uni-app
给新起项目提供了两种生产项目模板方式
- 通过 HBuilderX 可视化界面,在点击工具栏里的文件 -> 新建 -> 项目
- 通过vue-cli命令行
# 全局安装vue-cli
$ npm install -g @vue/cli
# 创建uni-app
$ vue create -p dcloudio/uni-preset-vue my-project
给小程序原生、wepy、mpvue提供了详细的迁移步骤文档
学习成本:uni-app有一个完善的开源文档,其语法糖是Vue,对熟悉vue的同学来说学习成本很低,在开发工具上官方对HBuilderX更友好,对熟悉HBuilderX使用的入手成本较低
一个简单的uni-app代码示例:
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view>
<text class="title">{{title}}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
},
methods: {
}
}
</script>
<style>
.content {
text-align: center;
height: 400upx;
}
.logo {
height: 200upx;
width: 200upx;
margin-top: 200upx;
}
.title {
font-size: 36upx;
color: #8f8f94;
}
</style>
chameleon
给新起项目提供了cli能力
# 全局安装cli
$ npm i -g chameleon-tool
# 初始化项目
$ cml init project
给小程序原生、vue、weex提供了CML的迁移指南
学习成本:chameleon有一个相对完善的开源文档,其语法糖是类Vue,对熟悉vue的同学来说学习成本很低
一个简单的chameleon代码示例:
<template>
<view>
<!-- 数据绑定与计算属性 -->
<text>{{ message }}</text>
<text class="class1">{{ message2 }}</text>
<!-- 条件与循环渲染 -->
<view c-if="{{showlist}}">
<view c-for="{{array}}" c-for-index="idx" c-for-item="itemName" c-key="city">
<text> {{ idx }}: {{ itemName.city }}</text>
</view>
</view>
<!-- 事件绑定 -->
<view c-bind:tap="changeShow"><text>切换展示</text></view>
</view>
</template>
<script>
class Index {
data = {
message: 'HelloCML',
array: [
{
city: '北京',
},
{
city: '上海',
},
{
city: '广州',
},
],
showlist: true,
};
computed = {
message2: function() {
return 'computed' + this.message;
},
};
watch = {
showlist(newVal, oldVal) {
console.log(`showlist changed:` + newVal);
},
};
methods = {
changeShow() {
this.showlist = !this.showlist;
},
};
created() {
console.log('生命周期');
}
}
export default new Index();
</script>
<style scoped>
.class1 {
color: #f00;
}
</style>
<script cml-type="json">
{
}
</script>
项目性能
本文主要研讨的应用方向是微信小程序,所以选型的框架需要对微信小程序的兼容性很高且产出的项目有较高的性能,多端框架很多都是基于微信小程序的API开发的,所以对微信小程序的兼容性很高,下面我们来看一下一个简单的日历组件应用到各框架产出的微信小程序性能数据对比
微信原生
小程序包大小:22.868 字节
微信基础库版本:2.6.2 (以下框架相同)
测试数据记录:
| 内存 | 页面切换耗时 | 启动耗时 | 初次渲染耗时 | 再次渲染耗时 | 数据缓存 | |---------|-----------|----------|--------------|------------|------------|-----------| | 252m | 146ms | 1163ms | 26ms | 94ms | 0B | | 244m | 606ms | 1293ms | 38ms | 60ms | 0B | | 256m | 159ms | 1293ms | 26ms | 131ms| 0B | | 235m | 708ms | 1403ms | 49ms | 58ms | 0B | | 245m | 571ms | 1163ms | 32ms | 56ms | 0B |
Wepy
小程序包大小:131,957 字节
wepy版本:1.6.0
测试数据记录:
| 内存 | 页面切换耗时 | 启动耗时 | 初次渲染耗时 | 再次渲染耗时 | 数据缓存 | |---------|-----------|----------|--------------|------------|------------|-----------| | 253m | 436ms | 1049ms | 29ms | 35ms | 0B | | 259m | 542ms | 1340ms | 33ms | 61ms | 0B | | 267m | 466ms | 1113ms | 22ms | 37ms | 0B | | 260m | 447ms | 1160ms | 22ms | 50ms | 0B | | 254m | 459ms | 1036ms | 30ms | 40ms | 0B |
Mpvue
小程序包大小:197,601 字节
mpvue版本:2.0.6
测试数据记录:
| 内存 | 页面切换耗时 | 启动耗时 | 初次渲染耗时 | 再次渲染耗时 | 数据缓存 | |---------|-----------|----------|--------------|------------|------------|-----------| | 225m | 247ms | 896ms | 24ms | 62ms | 0B | | 239m | 253ms | 910ms | 22ms | 58ms | 0B | | 235m | 446ms | 1591ms | 27ms | 62ms | 0B | | 237m | 269ms | 979ms | 21ms | 60ms | 0B | | 243m | 270ms | 908ms | 23ms | 57ms | 0B |
Taro
小程序包大小:167,080 字节
taro版本:1.3.2
测试数据记录:
| 内存 | 页面切换耗时 | 启动耗时 | 初次渲染耗时 | 再次渲染耗时 | 数据缓存 | |---------|-----------|----------|--------------|------------|------------|-----------| | 246m | 231ms | 718ms | 16ms | 224ms| 0B | | 241m | 297ms | 1007ms | 19ms | 246ms| 0B | | 246m | 256ms | 868ms | 16ms | 288ms| 0B | | 242m | 227ms | 829ms | 17ms | 224ms| 0B | | 237m | 231ms | 869ms | 17ms | 229ms| 0B |
uni-app
小程序包大小:292,831 字节
uni-app版本:2.0.0
测试数据记录:
| 内存 | 页面切换耗时 | 启动耗时 | 初次渲染耗时 | 再次渲染耗时 | 数据缓存 | |---------|-----------|----------|--------------|------------|------------|-----------| | 239m | 440ms | 987ms | 34ms | 178ms| 34B| | 237m | 529ms | 1365ms | 34ms | 182ms| 34B| | 232m | 531ms | 1133ms | 39ms | 183ms| 34B| | 236m | 487ms | 1154ms | 32ms | 178ms| 34B| | 239m | 486ms | 1051ms | 33ms | 190ms| 34B|
chameleon
小程序包大小:671,702 字节
chameleon版本:1.0.3
测试数据记录:
| 内存 | 页面切换耗时 | 启动耗时 | 初次渲染耗时 | 再次渲染耗时 | 数据缓存 | |---------|-----------|----------|--------------|------------|------------|-----------| | 223m | 550ms | 1043ms | 46ms | 60ms | 0B | | 231m | 597ms | 1326ms | 36ms | 60ms | 0B | | 225m | 631ms | 1338ms | 37ms | 58ms | 0B | | 237m | 658ms | 1289ms | 47ms | 68ms | 0B | | 245m | 611ms | 1241ms | 35ms | 66ms | 0B |
数据汇总 (平均值)
| 框架 | 包大小 | 内存 | 页面切换耗时 | 启动耗时 | 初次渲染耗时 | 再次渲染耗时 | 数据缓存 | |---------------|------------|---------|-----------|----------|--------------|------------|------------|-----------| | taro | 167,080 字节 | 242m | 248ms | 858ms | 17ms | 242ms | 0B | | mpvue | 197,601 字节 | 236m | 297ms | 1057m | 23m | 60m | 0B | | uni-app | 292,831 字节 | 237m | 495ms | 1138ms | 34ms | 182ms | 34B | | wepy | 131,957 字节 | 259m | 470ms | 1140m | 27m | 45m | 0B | | chameleon | 671,702 字节| 232m | 609ms | 1247ms | 40ms | 62ms | 0B | | 原生 | 22.868 字节 | 246m | 438ms | 1263ms | 34ms | 80ms | 0B |
就包大小而言:原生 < wepy < taro < mpvue < uni-app < chameleon
就微信小程序的性能而言:taro > mpvue > uni-app > wepy > chamelon > 未优化过的原生代码
框架使用后比原生的性能更好,这简直逆天了,后来研究发现微信原生框架耗时主要在setData调用上,开发者若不单独优化,则每次都会传递大量数据;而 uni-app、taro等都在调用setData之前自动做diff计算,每次仅传递变动的数据
可维护性
团队选型框架后最担心的事情就是后期的维护性,在需求开发的过程中,开发了一个业务需求发现框架本身有问题,怎么解决?框架使用过程中,突然发现该框架无人维护了,新的API和问题没有人跟进了,怎么办?所以在选型框架中,框架的可维护性是大部分团队所关注的事情
框架的star数
| Wepy | Mpvue | Taro | Uni-app | Chameleon |
|---------------|------------|---------|-----------|----------|--------------|
| 18854 | 18605 | 21740 | 12484 | 6521 |
从框架现有的star数可以看出Wepy、Mpvue和Taro的开源关注度比较高,这说明这几个框架的论坛活跃度更高,相关问题的解决方法更多
wepy
无论坛、无交流群,解决问题途径只能通过搜索或者提issues
mpvue
无论坛、无交流群,解决问题途径只能通过搜索或者提issues
taro
有论坛、社区、交流群等,解决问题可以通过论坛、社区查找或交流群提问,论坛最新更新贴在近一周内,也可以通过搜索或者提issues
uni-app
官方文档提供了论坛、社区、交流群等,论坛最新更新贴在近一天内,交流群很多且回复及时
chameleon
官方文档提供了微信、QQ交流群、顺风公鹿等
以上可以看出wepy和mpvue已经很久没人维护了,所以后续的可维护性较差,建议使用其他的框架
框架停止维护问题
框架的可维护性很大的问题可能出现无人维护的尴尬局面,这是选型框架的后续维护成本最大的问题,而当这种问题出现的时候,我们一般的处理方案有两种:
- 1、项目迁移到原生或其他框架
- 2、团队自己维护该框架
项目框架迁移的话,由于wepy、mpvue、uni-app、chameleon都是类Vue的语法糖,所以几种框架的的迁移成本略低,而taro是react的语法糖,所以迁移成本较高
团队自己维护该框架的话,就需要框架的源代码都是开源的,wepy、mpvue、taro、chameleon都是完全开源的,团队可以根据自己需求把代码拷贝出来自己维护,而uni-app是半开源的,团队无法把源代码拷贝出来
总结
通过以上业务功能的满足度、接入成本、项目性能、可维护性等多方面对比可以看出各个框架在各个方面有不同的优缺点,由于wepy和mpvue已长期不再维护,不建议团队选择。团队可以根据自己的实际业务需求和内部的技术栈情况选择,react系的可以选择taro框架,vue系的可以选择uni-app或者chameleon
文章摘要
从16年微信小程序内测到现在,各大公司对小程序的开发业务需求越来越大,技术大环境下的小程序开源框架越来越多,选择一个好的开源框架使用成为每个团队内部的难题。本文对现有的一些小程序开源框架进行简单介绍,从业务功能的满足度、接入成本、项目性能、可维护性等多方面对比分析