桔妹导读:抗击疫情,桔妹提醒大家出门带好口罩,勤洗手,多通风。武汉加油!中国加油!在大家开工之际,桔妹邀您阅读来滴滴开源专栏内容,为你分享滴滴跨端框架 Chameleon 的最新分享。
点击进入chameleon项目页
1. 背景
2. 选型和思考
3. 快应用介绍
快应用简介
快应用技术方案
快应用平台服务架构
快应用技术架构
对比小程序
4. 前端拓展快应用——原理篇
参与方
新端扩展配置化实现
实现cml-quickapp-plugin
实现cml-quickapp-runtime
实现cml-quickapp-api
实现cml-quickapp-store
实现cml-quickapp-ui-builtin和实现cml-quickapp-ui
5. 接入和使用
体验快应用
接入快应用
全局安装最新的 chameleon-tool 工具
启动快应用服务
安装和更新 package
修改 app.cml
修改 chameleon.config.js 配置文件
修改项目代码
快应用启动命令
6. Bug & Tips
7. 后续快应用发展和规划
计算机技术历史发展告诉我们,每一种新技术出现都会经历 "各自为政" 的阶段,小程序技术也不例外。微信小程序作为首创者,虽然其他小程序都在技术实现原理、接口设计刻意模仿,但是作为一线开发者面对同样的应用实现往往需要重复开发、测试,从前 1 单位的工作量变成了 N 单位的工作量。
除此之外,自跨平台兴起以来,各种各样的框架层出不穷,从一开始的 Hybrid App ( PhoneGap / Cordova / Ionic ),到前两年热门的 React-Native 和 Weex,再到目前风头正盛的 Flutter,这期间还兴起了 Web App 的热潮 (PWA 和各种小程序),这还不包括 watch、TV、车载 APP 等其他 “端”。
Chameleon(简写 CML )是一款真正专注于让一套代码运行多端的跨端框架。Chameleon 团队秉承 "一套代码运行多端,一端所见即多端所见" 的初心,拥有业内先进的工程化设计、丰富的基础以及独创多态协议,提供标准的 MVVM 架构开发模式统一各类终端。在最初支持 web、weex、wx (微信小程序) 三端之后,凭借其多态协议的优秀设计思想、灵活的工程化配置以及跨端标准协议,CML 工具可以迅速扩展新端,目前已经成功扩展支持全平台小程序(微信、支付宝、百度、qq、头条)。快应用也沿用着 MVVM 的架构开发模式,因此,基于CML的跨端标准协议扩展快应用后,可以快速实现一套代码运行web、native、全平台小程序、快应用。
当前阶段在开源社区存在多种跨端解决方案,除了滴滴的 Chameleon 跨端框架,诸如京东的 Taro 、去哪网的 Nanachi 、美团的 mpvue、腾讯的 WePY、Dcloud 的 uni-app 等跨端框架也都有各自的生态和使用场景。在选型方面,我们对这些框架的生态进行了较为细致的比较和探究,对比结果如下:
除了以上对比之外
chameleon-tool 最新版本对分包进行了更大的细化,主包体积有效的较之前减少了40% 左右;具体参考 chameleon-分包
得益于chameleon的灵活的工程化配置,chameleon可以灵活的支持微信小程序的云开发,具体参考 chameleon支持云开发
设计思想方面,Chameleon 独树一帜,独创跨端标准协议、灵活的工程化配置、Chameleon-store 状态管理工具,以及丰富的多端支持(支持 Weex、快应用、Web ),此外,Chameleon 不仅仅是作为跨端解决方案,让开发者高效、低成本开发多端原生应用,而且还基于优秀的前端打包工具 Webpack,吸收了业内多年来积累的最有用的工程化设计,提供了前端基础开发脚手架命令工具,帮助端开发者从开发、联调、测试、上线等全流程高效的完成业务开发。正是基于以上种种优势,快应用团队选择和 Chameleon 团队进行合作,作为快应用官方开展从 Chameleon 到快应用的适配工作。作为快应用官方团队,我们对快应用本身的能力和限制更加熟悉和了解,对 Chameleon 转换快应用的细节点能实现地更高效和完美,对于当前暂时未实现的特性也会第一时间进行跟进并持续更新给开发者,力图第一时间完善和优化。
快应用是基于手机硬件平台的新型应用形态,覆盖 10 亿安卓设备;
快应用标准是由主流手机厂商组成的快应用联盟联合制定;
快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放;
快应用具备传统 APP 完整的应用体验,无需安装、即点即用;
快应用目前使用如下技术方案:
使⽤前端技术栈(Html / CSS / JavaScript);
使⽤前端主流的模版+数据绑定框架编写代码(Vue.js);
平台提供⼤量扩展能⼒,包括系统能⼒和服务集成能⼒;
默认使⽤原⽣ JS-Native 渲染,达到原⽣应⽤的性能和体验;
测一测{{ title }}
App: 具体小程序,采用vue.js框架语法 ———————————— JS Framework: JS框架 ———————————— JS Engine: JS引擎,目前采用Google V8 ———————————— JS-Native Bridge: JS Native通信,目前采用开源J2V8方案 |
▍参与方
快应用团队
@zheyizhifeng
@whuhenrylee
@TingKun
滴滴团队
@sgoddon
@jimwmg
@chen28683
@eraychen1984
@wanglikun7342
开源贡献者
@yylgit
@MicroConan
chameleon-tool 中对于外部扩展的 webpack 配置的源码,参考链接(请点击此处) 这里重点讲下处理 .cml 后缀文件的 mvvm-cml-loader 和 mvvm-pack 中的 MvvmGraphPlugin
配置如下:
entry: {
app: path.join(cml.projectRoot, 'src/app/app.cml')
},
module: {
rules: [
...utils.styleLoaders({
type
}),
{
test: /\.cml$/,
use: [{
loader: 'mvvm-cml-loader',
options: {
loaders: getCmlLoaders(),
cmlType: type,
media,
check: cml.config.get().check
}
}]
}
]
},
plugins: [
new MvvmGraphPlugin({
cmlType: type,
media
}, platformPlugin)
]
mvvm-cml-loader 源码参考以下链接(请点击此处)
主要作用是以 app.cml 为入口,通过内联 loader 的形式循环递归的添加依赖,将所有的依赖添加到 webpack 构建过程中。
mvvm-pack 源码参考此处(请点击此处)
mvvmGraphPlugin.js 中劫持了 webpack 的输出,通过 mvvmCompiler 生成构建图。
compiler.plugin('should-emit', function(compilation) {
try {
mvvmCompiler.run(compilation.modules);
} catch (e) {
cml.log.error(e);
}
// 返回false 不进入emit阶段
return false;
})
以上就是 CML 脚手架产生的树状结构图,递归传递给 cml-quickapp-plugin 来转义目标语法。
目标:将包含 template、script、style 等节点的 .cml 源文件编译转换成符合快应用语法的 .ux 文件
根据上面生成的构建图,编译插件 cml-quickapp-plugin 中可以对构建图中所有节点(包括 template 节点、 style节点、script 节点 、json 节点等)编译成符合快应用端的语法,然后在 pack 任务中打包输出成符合快应用端的结构。
module.exports = class DemoPlugin {
constructor(options) {
......
}
/**
* @description 注册插件
* @param {compiler} 编译对象
* */
register(compiler) {
// 编译script节点,比如做模块化
compiler.hook('compile-script', function (currentNode, parentNodeType) {})
// 编译template节点 语法转义
compiler.hook('compile-template', function (currentNode, parentNodeType) {})
// 编译style节点 比如尺寸单位转义
compiler.hook('compile-style', function (currentNode, parentNodeType) {})
// 编译结束进入打包阶段
compiler.hook('pack', function (projectGraph) {
// 遍历编译图的节点,进行各项目的拼接
// 调用writeFile方法写入文件
// compiler.writeFile()
})
......
}
}
以扩展快应用的 template 编译为例。判断原始 CML 文件中的依赖关系,改写成快应用
compiler.hook("compile-template", function (currentNode, parentNodeType) {
let {componentFiles, uximports} = currentNode.parent.extra || {};
currentNode.output = templateParser(currentNode.source);
let components = '';
if(componentFiles) {
Object.keys(componentFiles).forEach(key=>{
let targetEntry = cmlUtils.getPureEntryName(componentFiles[key], self.cmlType, cml.projectRoot);
let sourceEntry = cmlUtils.getPureEntryName(currentNode.realPath, self.cmlType, cml.projectRoot);
let relativePath = cmlUtils.handleRelativePath(sourceEntry, targetEntry);
components += ` \n`
})
// 记录引入的组件
currentNode.importComponents = components;
} else if(uximports) {
uximports.forEach(item=>{
components += ` \n`
})
// 记录引入的组件
currentNode.importComponents = components;
}
});
更为详细的开发编译插件的教程请参考这个链接(请点击此处)
目标:实现运行时,代理快应用的 createApplication、createPage、createComponent 方法和响应式系统的 data、props、computed 等系统属性以及完成 CML 到快应用的生命周期映射
运行时的主要作用是抹平各端的生命周期差异性,进行响应式数据绑定等,参考链接(请点击此处)
CML 和快应用的生命周期都包含 App、Page、Component 三个级别,映射关系如下。具体可以参考(请点击此处)
// 左侧的 key 为 CML 生命周期函数,右侧的 value 为快应用对应的生命周期函数
{
app: {
beforeCreate: "onCreate",
created: "onCreate",
beforeMount: "onCreate",
mounted: "onCreate",
beforeDestroy: "onCreate",
destroyed: "onDestroy"
},
page: {
beforeCreate: "onInit",
created: "onInit",
beforeMount: "onInit",
mounted: "onReady",
beforeDestroy: "onHide",
destroyed: "onDestroy",
onShow: "onShow",
onHide: "onHide"
},
component: {
beforeCreate: "onCreate",
created: "onCreate",
beforeMount: "onCreate",
mounted: "onReady",
beforeDestroy: "onInit",
destroyed: "onDestroy"
}
}
以上两行代码是在 mvvm-cml-loader 中插入的,具体实现参考源码中对于 script 节点的处理(请点击此处)
我们只需要实现对应端的以下几个方法:
createApp createPage createComponent
具体实现参考(请点击此处)
以 cml-quickapp-runtime 中的 createPage 实现为例(请点击此处)
cml-quickapp-runtime/index.js
import { createApp } from './src/interfaces/createApp/index.js';
import { createPage } from './src/interfaces/createPage/index.js';
import { createComponent } from './src/interfaces/createComponent/index.js';
export default {
createApp,
createPage,
createComponent
}
cml-quickapp-runtime/src/interfaces/createPage/index.js
import createPgInterface from './index.interface';
export function createPage(options) {
return createPgInterface.createPage(options)
}
cml-quickapp-runtime/src/interfaces/createPage/index.interface
//这里要将 chameleon-runtime中的 createPage接口 include 进来
目标:基于跨端协议,实现快应用对应的 API
实现 API 的部分特别简单,只需两步
引入 Chameleon 官方的标准 interface 文件
扩展实现新端,实现对应端的方法
具体实现如下:
以快应用的 alert 接口实现为例,参考(请点击此处)
// 引入官方标准interface文件
// 扩展实现新端
目标:基于 mobx 实现一套响应式数据系统
实现 cml-quickapp-store 同样只需要两步:
引入 Chameleon 官方的标准 interface 文件
扩展实现新端,实现对应端的方法
//引入官方标准 interface 文件
具体实现请参考(请点击此处)
目标:实现 CML 组件在快应用中的一致表现,可以参考(请点击此处)
实现 cml-quickapp-ui-builtin 也是需要两步:
创建和 Chameleon 官方的组件同名的 interface 文件
用新端自有的组件和语法呈现 CML 组件即可
以 CML 中的 button 组件实现为例,在快应用目前版本是不存在 button 组件的,所以需要用快应用自有的组件进行模拟实现,参考(请点击此处)
// button.interface
// button.quickapp.cml
// template 实现 button 组件的 dom 结构,script 实现 button 的逻辑,style 实现 button 的样式效果
{{text}}
目标:扩展新端本身没有的复合交互组件,如 pop-up、action-sheet、picker 等交互组件。
实现过程和 cml-quickapp-ui-builtin 如出一辙,以 c-popup 组件的实现为例,参考(请点击此处)
// c-popup.interface
// c-popup.cml
Chameleon 官方的体验 demo 项目源仓库如下:
cml-demo : 组件库&API 实例
cml-flexbox : Flex 布局案例集合
cml-yanxuan : 仿网易严选 APP
cml-todomvc : Todo-List
以上四个项目编译打包后的快应用 .rpk 文件地址如下
组件库 && API 实例 + 仿网易严选 APP
flexbox 布局案例集合
Todo-List
对于普通用户或开发者来说,如果想要在快应用端进行体验,需要满足以下条件:
拥有一台 Android 操作系统的移动设备
在移动设备上下载并安装最新版 快应用预览版 APP ,当前最新版本为1050.10
将以上 demo 项目编译打包生成的 .rpk 文件放入移动设备的 /sdcard/rpks 文件夹,再次打开预览版即可体验
在快应用端的预览效果如下:
首先要求具备一整套快应用开发工具链,参考链接(请点击此处),这其中包括快应用调试器、快应用预览版、hap-toolkit 构建工具等;运行 快应用示例代码 可以检验环境是否就绪;快应用的开发环境就绪之后才开始进行 chameleon 项目的引入和部署。
基于以下步骤配置之后,既有的 CML 项目可以直接在快应用运行
npm i -g chameleon-tool
quickapp-demo
为例命名该快应用项目,并以 ~/quickapp-demo 目录为例启动快应用服务,此外,建议开发者在快应用项目根目录 ~/quickapp-demo/
执行 hap watch
,进行代码热更新。克隆 chameleon 官方的 demo 项目到本地,此处以 cml-flexbox 项目为例。切换到 master-quickapp 分支,修改 package.json 文件。
cd ~/quickapp-demo
hap server # 启动快应用服务
# 再新打开另外一个terminal
cd ~/quickapp-demo
hap watch # 热更新
升级原有的 package 如下:
"chameleon-api": "^0.5.3",
"chameleon-bridge": "^0.2.0",
"chameleon-runtime": "0.1.4",
"chameleon-store": "0.0.3",
"chameleon-ui-builtin": "^0.4.0-mvvm.3",
"cml-ui": "^0.3.0-alpha.1",
新增引入的快应用 package 如下:
"cml-quickapp-api": "1.0.0","cml-quickapp-plugin": "1.0.0","cml-quickapp-runtime": "1.0.0","cml-quickapp-ui-builtin": "1.0.0","cml-quickapp-ui": "1.0.0","cml-quickapp-store": "1.0.0"
修改 app.cml 文件,增加快应用 manifest.json 文件对应的配置
vim ~/cml-flexbox/src/app/app.cml
找到
增加快应用需要的配置
此配置对应快应用项目中的 manifest.json 文件,详细文档参考:manifest 文件
• 修改 chameleon.config.js 配置文件
1. 引入path模块
const path = require('path')
2. 增加 builtinNpmName、extPlatform 和 babelPath 配置
builtinNpmName: 'cml-quickapp-ui-builtin',
extPlatform: {
quickapp: 'cml-quickapp-plugin',
},
babelPath: [
path.join(__dirname,'node_modules/cml-quickapp-ui-builtin'),
path.join(__dirname,'node_modules/cml-quickapp-runtime'),
path.join(__dirname,'node_modules/cml-quickapp-api'),
path.join(__dirname,'node_modules/cml-quickapp-ui'),
path.join(__dirname,'node_modules/cml-quickapp-store'),
path.join(__dirname,'node_modules/cml-quickapp-mixins'),
path.join(__dirname,'node_modules/mobx'),
],
以上配置解释
builtinNpmName:自定义的内置 npm 包名称
extPlatform:配置扩展新端的编译插件
key:端标识
value:编译插件
npm:包名称
babelPath:要过 babel 处理的 npm 包
3. 导入基础样式
如果需要引入基础样式,需要增加 quickapp: true 的配置,参考 工程配置-baseStyle
baseStyle:{wx: true,
web: true,
weex: true,
alipay: true,
baidu: true,
qq: true,
quickapp: true,
},
1. 修改项目中相关包的引用
store 和 api 的引用:
chameleon-store 改为 cml-quickapp-store
chameleon-api 改为 cml-quickapp-api
import cml from "chameleon-api";
import store from "chameleon-store";
改为
import cml from "cml-quickapp-api";
import store from "cml-quickapp-store";
组件的引用 cml-ui 改为 cml-quickapp-ui
改为
2. 多态组件在端的实现
如果存在某多态组件,以 poly-comp 为例
poly-comp.interface
poly-comp.web.cml
poly-comp.weex.cml
poly-comp.wx.cml
poly-comp.alipay.cml
poly-comp.baidu.cml
3. 多态接口在端的实现
如果存在某多态接口,以 poly-api.interface 为例
需要增加在快应用端的实现
快应用支持的命令有
cml quickapp dev
cml quickapp build
当你完成了以上的步骤之后,就可以在你的项目中执行 cml quickapp dev
进行快应用的开发了。在 CML 项目根目录 ~/cml-flexbox/
执行 cml quickapp dev
,会生成 dist/quickapp
文件夹,拷贝 /dist/quickapp
目录下所有文件到已经提前启动的快应用的项目根目录 ~/quickapp-demo/
,更新快应用代码,即可进行调试和预览。
cd ~/cml-flexbox
cml quickapp dev
cp -r dist/quickapp/* ~/quickapp-demo/
当前阶段的适配工作虽然已覆盖几乎所有 Chameleon 的功能特性,但受制于快应用和 Chameleon 之间存在的少许差异性,仍然存在一些尚未解决的问题,这些问题我们会在后续持续跟进和优化完善。
这些尚未完成的 feature 包括:
1. 动画相关。Chameleon 的动画调用方式和快应用差异颇大,当前未进行适配;
2. CSS 特性。受制于部分快应用的特性,诸如 box-sizing、box-shadow、white-space 等属性暂未支持;
3. watch 能力。当前可以进行 cml-quickapp-store 作用域内的属性 watch,对普通属性则未生效。
快应用后续会持续强化和完善基础能力,力求在体验上趋近原生 App,加速快应用商业变现,实现头部快应用开发者可盈利,并布局海外,初步实现在印度和东南亚地区业务落地。
推荐阅读
▬
更多推荐
▬
滴滴开源/ Open Source
FastLoad|Levin |AoE |Delta |Mpx | Booster |Chameleon |DDMQ |DroidAssist |Rdebug |Doraemonkit |Kemon|Mand Moblie |virtualApk|获取更多项目
技术干货 / Recommended article
高频 golang 服务接口超时排查&性能调优|一种线上系统的容量评估方法|浅谈滴滴派单算法|阅读更多