0x1 读完后希望你会
- 了解Weex中,we脚本的各个标签<template><script><style>解析实现方式,如何生成可以运行的js脚本文件。
- 基于标签tag,自己实现一套你喜欢的类似we或者微信小程序的脚本语言。
- 可以包含表达式计算
- 流程控制
0x2 背景
目前线上App接入的weex版本为0.8.X,距目前最新的0.10.X系列跨度相差较大,但是在保证目前业务稳定的前提下,不能直接升级Weex SDK到最新版。
在升级前期,不得不面对的几个问题:
- 目前已开发的大量.we页面是否可以在新版Weex运行。
- 继续使用已被废弃的we脚本开发新需求(Weex已经推荐用vue来写页面)
- Vue与Weex两大生态的联手,Weex官方也在推进vue来编写界面.
- we脚本将来很有可能面临不再被扩展维护,也就是weex很多的新特性在we中不一定会被支持,除非we与vue的feature更新节奏保持一致。
- 据说手淘与猫客已不再使用we编写weex,而是全部采用vue(求证)。
- Vue自身生态庞大,对vue更好的支持,反而更利于weex的推广。
所以在升级之前,以weex的transform流程原理为开端,展开一些前期的调研工作,顺便学习一下weex的toolkit实现原理。
据weex的同学说新版的weex是可以跑老we的,不过要保证we脚本代码的严谨性,因为新版的jsf runtime校验机制,更加严格,某些页面可能白屏(What?!!)。
老话常谈,“Talk is cheap,Show me the code”。
0x3 验证思路
一个we页面被渲染执行,可以大致拆分为两部分。
【.we脚本的打包与编译】(weex/vue loader,生成标准的js脚本)
[.we] -> [build] -> output [*.js]
【Weex JS 运行时环境(JSF)】(负责解析运行编译好的js脚本)
[*.js] -> [weex runtime] -> render [view:page]
从图中可以看出 Weex 整体的工作流程。
首先开发者编写 .we 文件。
通过 weex-toolkit 提供的工具将 .we 文件转为js。
JS Framework 接收并执行 js 的代码,执行数据绑定、模板编译等操作,然后输出 json 格式的 Virtual DOM 传递给移动端。
这篇文章主要分析第一层的transformer的实现原理。
0x4 we/vue 脚本是如何被解析的
不可不说的parse5:
weex-loader中,对we文件的解析主要依赖第三方开源npm组件,html标签解析的parse5,对输入的html标签类文本,解析后输出json对象。
关于输出的json格式,可以参考官方的在线playground,http://astexplorer.net/#/1CHlCXc4n4
weex-loader首先通过parse5 得到we文本的json 结构的树结构,
然后Weex-loader的处理流程中,针对不同标签(<template/> <script/><style/>),分别有对应的解析处理模块,
大致流程如上图,从左向右依次为:
1.输入为原始we脚本文件。
2.通过parse5组件解析出对应的jsonobject
3.根据json object中描述的各部分tag交给对应的处理模块。
例如一个template标签的json对象,在loader中是这样被处理的,
源码地址: weex-loader/lib/loader.js
不同的标签类型文本会分配给专门的parse组件.
源码地址:weex-loader/lib/parser.js
标签对应的处理模块如下:
<script> 标签 ————> weex-templater
<style > 标签 ————> weex-styler
<script> 标签 ————> weex-scripter
0x5 weex-styler 简介以及CSS预备知识
weex-styler负责处理weex所支持的css样式,以及验证开发者所写的css样式是否正确。
其中实现原理是使用开源css https://www.npmjs.com/package/css 组件,根据css代码的文本段,生成json object类型的 ast节点信息。要了解weex-styler的处理流程,势必要了解一下ast以及css的基本概念。
一张图看懂CSS构成.
A CSS rule-set consists of a selector and a declaration block:
rule-set:包含一个selector 以及多个declaration。
selector:样式选择器,主要用来定位元素
declaration:定义样式属性以及值。
了解这三个基本概念之后,看scripter也是轻车熟路了,快上车。
scripter当中,通过css parser得到AST json object,读取ast.stylesheet.rules获得到当前样式的rule-set,然后遍历所有的declaration,校验样式是否被weex所支持的(因为weex中支持css的样式有限),以及简单的value字段合法性校验。
![Uploading Paste_Image_374004.png . . .]
源码:/weex-styler/index.js
weex-styler新老版之差异。
对Pseudo class样式进行了支持。
新版weex中,支持shorthand writing写法的transition样式。
// shorthand writing
div {
transition: width 2s linear 1s;
}
div {
transition-property: width;
transition-duration: 2s;
transition-timing-function: linear;
transition-delay: 1s;
}
0x6 weex-templater 简介
解析we脚本中的<template/>标签内容,其核心节点数据结构也是基于parse5解析出的json object,同时也会做数据绑定,标签验证,自动修复common错误的处理。
<template>
<div if={{x}}>
<text onclick="toggle">Toggle: {{result}}</text>
</div>
</template>
- 数据绑定:
<text>标签内的value,”Toggle: {{result}}”,
<div>标签内的attribute if 中的 “{{x}}”,
也就这种用户可以编辑的文本段,需要对包含的表达式以及变量进行处理,这里的实现就在var exp = require('./exp’)这个模块当中,
该exp函数有2个参数,需要转换的字符串文本,以及是否需要转换成function对象。
![Uploading Paste_Image_402398.png . . .]
/weex-templater/lib/exp.js
将双引号“替换为单引号’,去除所有\n换行控制字符。
判断文本中是否包含表达式,如果不包含,直接返回原始文本。
根据生成的token列表,
文本会在两端加入单引号’
表达式在两端(),显式的加入运算优先级。
比如Toggle: {{result}} => [‘\’Toggle:\’’,’(result)’]
这样在最后,只需要把结果列表中的所有元素做一次’+’.join操作,就可以构成了一个合法的js语句。
- 事件绑定:
text中的onclick属性的值,templater会自动生成可以调用toggle函数的js代码。当标签的属性名包含on前缀时,将进行事件绑定。
weex-templater/index.js
在checkEvent方法中,通过把封装好的function描述字符串eval对象赋值给value,达到事件发生时触发函数的机制。
- 对template的内容,对元素标签(如<div/><a/><img/等>),控制语句(if,else,repeat等)做validation,针对不同标签,会有额外特殊的验证操作。
下面举几个典型例子,
- 【If】 validation: <if={{x == 1}}> 验证if中包含的value,以及value是否是一个合法的表达式。
- 【else】 validation:当遍历到一个节点中包含else时,就会验证前一个节点中是否包含了if。
- Tag(标签)validation:
Tag的验证相对多一点,因为不同的tag会有其特殊的规则,
例如最外层的<template/>只能包含一个root子节点。
container类型的标签可以嵌套标签,非container则不可。
<cell>标签可以自动补全tree属性。 - <text>标签比较特殊,因为text里面可以包含任意的字符串,变量,表达式,
例如下面的脚本。
- 修复一些简单的common问题。
举个例子,比如图像内容,既可以写成<img>也可以写成<Image>,在templater中是有处理的。
源码地址:weex-templater/lib/validator.js