欢迎来到258分享网,纯净的网络源码分享基地!

258资源分享网

全部作品
全部作品
网站源码
微信源码
素材特效
源码插件
视频教程
建站学院
热门搜索: 织梦  农业种植  农业  安全设置  官方
258资源分享 > 建站学院 > 微信开发 > 2018新媒体下半年深度预测:增长恐慌,流量洼地

推荐下载

HTML5响应式自适应网咯设计

2020-05-12   浏览:740

高端HTML5响应式企业通用网

2020-05-06   浏览:521

html5响应式外贸网站英文版

2020-05-08   浏览:510

HTML5自适应律师工作室类网

2020-04-04   浏览:504

HTML5影视传媒文化公司类网

2020-05-12   浏览:500

2018新媒体下半年深度预测:增长恐慌,流量洼地

发布时间:2020-10-18  

这是本系列的第二篇,过去两周,已经有相当成果出来。本文介绍其中一部分可靠的思路,这个比京东的taro更具可靠性。如果觉得看不过瘾,可以看anu的源码,里面包含了miniapp的转换器。

微信小程序是面向配置对象编程,不暴露Page,App,Component等核心对象的原型,只提供三个工厂方法,因此无法实现继承。App,Page,Component所在的JS的依赖处理也很弱智,你需要声明在同一目录下的json文件中。

比如说

Component({ properties: {}, data: {}, onClick: function(){} })

properties与data都是同一个东西,properties只是用来定义data中的数据的默认值与类型,相当于React的defaultProps与propTypes。如何转换呢?

import {Component} form "./wechat" Class AAA extends Component{ constructor(props){ super(props); this.state = {} } static propTypes = {} static defaultProps = {} onClick(){} render(){} } export AAA;

首先我们要提供一个wechat.js文件,里面提供Component, Page, App 这几个基类,现在只是空实现,但已经足够了,保证它在调试不会出错。我们要的是`Class AAA extends Component`这个语句的内容。学了babel,对JS语法更加熟悉了。这个语句在babel6中称为ClassExpression,到babel7中又叫ClassDeclaration。babel有一个叫"babel-traverse"的包,可以将我们的代码的AST,然后根据语法的成分进行转换(详见这文章 https://yq.aliyun.com/articles/62671)。ClassDeclaration的参数为一个叫path的对象,我们通过 path.node.superClass.name 就能拿到Component这个字样。如果我们的类定义是下面的这样,path.node.superClass.name 则为App。

Class AAA extends App{ constructor(props){ super(props); this.state = {} } }

App, Page, Component对应的json差异很大,拿到这个可以方便我们区别对待。

然后我们继续定义一个ImportDeclaration处理器,将import语句去掉。

定义ExportDefaultDeclaration与ExportNamedDeclaration处理器,将export语句去掉。

到这里我不得不展示一下我的转码器的全貌了。我是通过rollup得到所有模块的路径与文件内容,然后通过babel进行转译。babel转换是通过babel.transform。babel本来就有许多叫babel-plugin-transform-xxx的插件,它是专门处理那些es5无法识别的新语法。我们需要在这后面加上一个新插件叫miniappPlugin

// https://github.com/RubyLouvre/anu/blob/master/packages/render/miniapp/translator/transform.js const syntaxClassProperties = require("babel-plugin-syntax-class-properties") const babel = require('babel-core') const visitor = require("./visitor"); var result = babel.transform(code, { babelrc: false, plugins: [ 'syntax-jsx', // "transform-react-jsx", 'transform-decorators-legacy', 'transform-object-rest-spread', miniappPlugin, ] }) function miniappPlugin(api) { return { inherits: syntaxClassProperties, visitor: visitor }; }

miniappPlugin的结构异常简单,它继承一个叫syntaxClassProperties的插件,这插件原来用来解析es6 class的属性的,因为我们的目标也是抽取React类中的defaultProps, propsTypes静态属性。

visitor的结构很简单,就是各种JS语法的描述。

const t = require("babel-types"); module.exports = { ClassDeclaration: 抽取父类的名字与转换构造器, ClassExpression: 抽取父类的名字与转换构造器, ImportDeclaration(path) { path.remove() //移除import语句,小程序会自动在外面包一层,变成AMD模块 }, ExportDefaultDeclaration(path){ path.remove() //AMD不认识export语句,要删掉,或转换成module.exports }, ExportNamedDeclaration(path){ path.remove() //AMD不认识export语句,要删掉,或转换成module.exports } }

我再介绍一下visitor的处理器是怎么用的,处理器其实会执行两次。我们的AST树每个节点会被执行两次,如果学过DFS的同学会明白,第一次访问后,做些处理,然后进行它内部的节点,处理后再访问一次。于是visitor也可以这样定义。

ClassDeclaration:{ enter(path){}, exit(path){} }

如果以函数形式定义,那么它只是作为enter来用。

AST会从上到下执行,我们先拿到类名的名字与父类的名字,我们定义一个modules的对象,保存信息。

enter(path) { let className = path.node.superClass ? path.node.superClass.name : ""; let match = className.match(/\.?(App|Page|Component)/); if (match) { //获取类的组件类型与名字 var componentType = match[1]; if (componentType === "Component") { modules.componentName = path.node.id.name; } modules.componentType = componentType; } },

我们在第二次访问这个类定义时,要将类定义转换为函数调用。即

Class AAA extends Component ---> Component({})