新框架太多?学不动啦?有这一套跨端标准,从此不再用学习新框架了。html
各个小程序按本身喜爱“各自为政”?有了这套标准,不再用重复开发各类新平台啦。前端
现在前端比较流行的 React Native、Weex、Flutter 等跨平台开发框架,对于开发来讲属于技术方案的选择,好比,咱们会考虑用这个技术开发,性能会不会超过 h5,开发效率会不会超过原生开发等等。git
可是从 2017 年微信推出小程序,到至今各大厂商都推出本身的小程序,跨端开发就不只仅是技术的问题了。已经变成了必争的流量入口。如今的小程序大战像极了当前的浏览器大战。大战中受苦的是咱们一线开发者,一样的应用要开发 N 次,面对了史无前例的挑战,因此跨端框架的产生是大趋势下的必然产物。github
chameleon 基于对跨端工做的积累, 规范了一套跨端标准,称之为 MVVM+协议;开发者只须要按照标准扩展流程,便可快速扩展任意 MVVM 架构模式的终端。并让已有项目无缝运行新端。因此若是你但愿让 chameleon 快速支持淘宝小程序、React Native?只需按标准实现便可扩展。npm
最终让开发者只须要用 chameleon 开发,就能够在任意端运行,不再用学习新平台框架啦。json
滴滴、芒果 TV、阿里的同窗合做,正在按照跨端协议流程进行字节跳动小程序的共建开发。小程序
快应用官方研发团队也正在接入中api
跨端框架最核心的工做是统一,chameleon 定义了标准的跨端协议,经过编译时+运行时的手段去实现各端的代码和功能,其实现原理以下图所示。浏览器
其中运行时和基础库部分利用多态协议实现各端的独立性与框架的统一性。chameleon 目前支持的端都是采用这种方式,咱们定义了扩展一个新端所须要实现的全部标准,用户只须要按照这些标准实现便可完成一个新端的扩展。微信
咱们再来看一张 chameleon 的设计图,可以实现标准化的扩展新端,得益于多态协议中对各层代码进行了接口的定义,各端代码按照接口定义进行实现,向用户代码提供统一调用,同时还提供”多态协议“让用户代码保障可维护性的前提下,直接触达各端原生能力的方式。
简单来讲只须要实现 6 个 npm 包。
chameleon-api
提供了网络请求,数据存储,获取系统信息,交互反馈等方法,用户须要建立一个 npm 包,结构参考cml-demo-api。将chameleon-api
中提供的每一个方法利用多态接口扩展语法扩展新端的实现。
以扩展一个alert
方法为例,chameleon-api
中alert
方法的接口定义文件为chameleon-api/src/interfaces/alert.interface
,其中的接口定义内容以下:
<script cml-type="interface"> type alertOpt = { message: String, confirmTitle: String } type successCallBack = (result: String) => void; type failCallBack = (result: String) => void; interface uiInterface { alert(opt: alertOpt, successCallBack: successCallBack, failCallBack: failCallBack): void, } </script>
用户实现的interface
文件中采用<include></include>
语法引入chameleon-api
中alert
方法的 interface 文件, 实现uiInterface
。
// 引入官方标准interface文件 <include src="chameleon-api/src/interfaces/alert/index.interface"></include> // 扩展实现新端(以头条小程序为例,假设端扩展标识为:tt) <script cml-type="tt"> class Method implements uiInterface { alert(opt, successCallBack, failCallBack) { // 根据头条小程序实现alert弹窗 let { message, confirmTitle} = opt; tt.showModal({ content: message, confirmText: confirmTitle, ...... }); } } export default new Method(); </script>
组件分为内置组件chameleon-ui-builtin和扩展组件cml-ui。因此用户须要建立两个 npm 包分别实现这两个组件库,结构参考cml-demo-ui-builtin和cml-demo-ui。利用多态组件扩展语法,对原有组件库中的每个组件进行新端的实现。
原有组件库中的组件也分为两种,一种为各端都有分别实现的多态组件,例如chameleon-ui-builtin
中的button
组件。实现起来新端基本上也是要单独实现。另外一种例如chameleon-ui-builtin
中的radio
组件,各端的实现都是用的chameleon-ui-builtin/components/radio/radio.cml
。因此新端基本也能够复用这个实现,(还须要测试状况确实是否能够复用)。
例如:
编写 my-ui-builtin/components/button/button.interface
// 引入官方标准interface文件 <include src="chameleon-ui-builtin/components/button/button.interface" />
编写 my-ui-builtin/components/button/button.demo.cml
<template> <origin-button c-bind:tap="onclick" open-type="{{openType}}"> </origin-button> </template> <script> // js实现部分 </script> <style scoped> // 样式部分 </style> <script cml-type="json"> // json配置 </script>
独立实现的my-ui-builtin/components/button/button.demo.cml
文件属于多态组件的灰度层,能够调用各端底层组件和 api,具体例子参见button和scroller的实现。
编写 my-ui-builtin/components/radio/button.interface
// 引入官方标准interface文件 <include src="chameleon-ui-builtin/components/radio/radio.interface"></include> // 复用官方的实现 <script cml-type="demo" src="chameleon-ui-builtin/components/radio/radio.cml"></script>
chameleon 内部会将整个项目文件编译为以下编译图结构,节点中的内容通过了标准编译,好比script
节点的babel
处理,style
节点的less
与stylus
处理等等。
节点的数据结构以下:
class CMLNode { constructor(options = {}) { this.realPath; // 文件物理地址 会带参数 this.moduleType; // template/style/script/json/asset this.dependencies = []; // 该节点的直接依赖 app.cml依赖pages.cml pages.cml依赖components.cml js依赖js this.childrens = []; // 子模块 cml文件才有子模块 this.source; // 模块源代码 this.output; // 模块输出 各类过程操做该字段 ...... } }
用户只须要实现一个编译插件类,利用钩子方法实现对节点的编译,全部节点编译完后再进行文件的组织。编译类以下:
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() }) ...... } }
运行时主要是对 cml 文件的逻辑对象进行适配,chameleon 内部将 cml 文件的逻辑对象分为三类 App、Page、Component。对应会调用用户运行时 npm 包的createApp、createPage、createComponent
方法,因此对外只须要实现这三个方法。
例如一个 Page 的逻辑对象以下:
class PageIndex { data = { name: 'chameleon' } computed = { sayName () { return 'Hello' + this.name; } } mounted() { } } export default new PageIndex();
编译时就会自动插入用户的运行时方法处理逻辑对象,例如cml-demo-runtime
:
class PageIndex { ...... } export default new PageIndex(); // 编译时自动插入用户配置的运行时方法 import {createPage} from 'cml-demo-runtime'; createPage(exports.default);
createApp、createPage、createComponent
方法,参考cml-demo-runtime的结构进行实现,须要include
chameleon-runtime
中相应的接口进行实现,才可以实现对chameleon-runtime
的扩展。用户的工做量主要在于对逻辑对象的处理,能够参考chameleon-runtime中的实现方式,通常须要以下方面的适配工做。
从宏观来看,运行时处理可分为:
从微观来看,有如下处理:
例如: createPage 方法的实现
<include src="chameleon-runtime/src/interfaces/createPage/index.interface"></include> <script cml-type="demo"> class Method implements createPageInterface { createPage(options) { // 各端自行实现adapter adapter(options); //例如调用小程序原生页面构造函数 Page(options); return {}; } } export default new Method(); </script>
chameleon-store
提供了相似 Vuex 的数据管理解决方案,具体标准参见数据管理。一样利用多态协议实现其功能。
期待更多人的加入开源。想了解更多 chameleon 信息请访问官网 cmljs.org
预告:chameleon 1.0正式版即将到来