VUE 组件转换为微信小程序组件的方法(2)

//文件 const wxssFilePath = path.join(dirPath, `${mpFile}.wxss`); const jsFilePath = path.join(dirPath, `${mpFile}.js`); const wxmlFilePath = path.join(dirPath, `${mpFile}.wxml`); const jsonFilePath = path.join(dirPath, `${mpFile}.json`); if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath); } fs.writeFile(wxssFilePath, wxssContent, err => { if (err) throw err; //console.log(`dist目录下生成${mpFile}.wxss文件成功`); fs.writeFile(jsFilePath, jsContent, err => { if (err) throw err; // console.log(`dist目录下生成${mpFile}.js文件成功`); fs.writeFile(wxmlFilePath, wxmlContent, err => { if (err) throw err; //console.log(`dist目录下生成${mpFile}.wxml文件成功`); fs.writeFile(jsonFilePath, jsonContent, err => { if (err) throw err; console.log(`dist目录下生成${mpFile}.json文件成功`) resolve(`生成${mpFile}.json文件成功`); }) }) }); });

上方是处理得到的 WXML ,WXSS,JSON,JS,4个文件,并且生成到对应的目录下。代码实现用时较短,后续更改方案,并没有做优化,这里就不做详细展开讨论这个实现方案了。

回到正题 介绍一下,AST 抽象语法树的核心部分:

三、 抽象语法树三大法宝

Babel 是 JavaScript 编译器,更确切地说是源码到源码的编译器,通常也叫做“ 转换编译器(transpiler)”。 意思是说你为 Babel 提供一些 JavaScript 代码,Babel 更改这些代码,然后返回给你新生成的代码。

babel-core:Babel 的编译器;它暴露了 babel.transform 方法。

[1] babylon:Babylon 是 Babel 的解析器。用于生成 AST 语法树。

[2] babel-traverse:Babel 的遍历器,所有的transformers都使用该工具遍历所有的 AST (抽象语法树),维护了整棵树的状态,并且负责替换、移除和添加节点。我们可以和 Babylon 一起使用来遍历和更新节点。

[3] babel-generator:Babel 的代码生成器。它读取AST并将其转换为代码。

整个编译器就被分成了三部分:分析器、转换器、生成器,大致的流程是:

输入字符串 -> babylon分析器 parse -> 得到 AST -> 转换器 -> 得到 AST -> babel-generator -> 输出

总结核心三步:

AST 三大法宝

babylon.parse => traverse 转换 AST => generate(ast, {}, code).code) 生成

感兴趣的童鞋,可以在网上或者看参考资料都有介绍。该铺垫的都铺垫的差不多了,进入正题。

我们到底是如何通过 AST 将 VUE 组件转换为微信小程序组件的呢?

四、 VUE 组件转换为微信小程序组件中 组件的对外属性、赋值语句的转换处理

转换之前的 VUE 组件代码 Demo

export default { //组件的对外属性 props: { max: { type: Number, value: 99 } }, //组件的内部数据 data(){ return { num:10000 } }, //组件的方法 methods: { textFn() { this.num = 2 }, onMyButtonTap: function(){ this.num = 666 }, } }

处理后我们得到的微信小程序组件 JavaScript 部分代码

export default { properties: { //组件的对外属性 max: { type: Number, value: 99 } }, //组件的内部数据 data(){ return { num: 10000 } }, //组件的方法 methods: { textFn() { this.setData({ num: 2 }); }, onMyButtonTap: function () { this.setData({ num: 666 }); } } };

我们对js动了什么手脚(亦可封装成babel插件):

//to AST const ast = babylon.parse(code, { sourceType: "module", plugins: ["flow"] }); //AST 转换 node,nodetype很关键 traverse(ast, { enter(path) { //打印出node.type console.log("enter: " + path.node.type); } }) ObjectProperty(path) { //props 替换为 properties if (path.node.key.name === "props") { path.node.key.name = "properties"; } } //修改methods中使用到数据属性的方法中。this.prop至this.data.prop等 与 this.setData的处理。 MemberExpression(path) { let datasVals = datas.map((item,index) =>{ return item.key.name //拿到data属性中的第一级 }) if (//含有this的表达式 并且包含data属性 path.node.object.type === "ThisExpression" && datasVals.includes(path.node.property.name) ) { path.get("object").replaceWithSourceString("this.data"); //判断是不是赋值操作 if ( (t.isAssignmentExpression(path.parentPath) && path.parentPath.get("left") === path) || t.isUpdateExpression(path.parentPath) ) { const expressionStatement = path.findParent(parent => parent.isExpressionStatement() ); //...... } } }

转换之前的js代码的部分 AST 树:

具体的 API 使用,童鞋们看一下 babel 相关的文档了解一下。

五, VUE 组件转换为微信小程序组件中 Export Default 到 Component 构造器的转换 与 生命周期钩子函数,事件函数的处理

首先我们看一下要转换前后的语法树与代码如下(明确转换目标):

转换之前的 AST 树与代码

export default {// VUE 组件的惯用写法用于导出对象模块 data(){ }, methods:{ }, props:{ } }

转换之后的 AST 树与代码

components({//小程序组件的构造器 data(){ }, methods:{ }, props:{ } })

通过以上转换之前和转换之后代码和 AST 的对比我们明确了转换目标就是 ExportDefault 到 Component构造器的转换,下面看一下我们是如何处理的:

我们做了什么(在转换中进入到 ExportDefault 中做对应的处理):

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/05a528f1ccbb158eb13b1a8e2c63ec99.html