本文意在介绍如何将uni-app项目转成微信小程序,在开始之前需要了解一些基础知识。
Gulp基础
首先了解一下如何使用gulp 打包并输出到指定目录。
项目目录
|-- output-test
|-- App.vue
|-- gulpfile.js
|-- main.js
|-- manifest.json
|-- package-lock.json
|-- package.json
|-- pages.json
|-- uni.scss
|-- pages
| |-- index
| |-- index.vue
我们要将pages/ 目录的内容输出到dist 目录。
-
安装gulp并在项目根目录下新建gulpfile文件
-
在gulpfile.js文件里键入以下内容
const gulp = require('gulp'); // 输入目录 const srcPath = "./pages/**" // 输出目录 const distPath = "./dist/"; // 定义一个任务 const parse = () => { return gulp .src([`${srcPath}/*.vue`], { since: gulp.lastRun(parse) }) .pipe(gulp.dest(distPath)) } gulp.task(parse) gulp.task( "build", gulp.series( "parse" ) ) -
在package.json中新增一条命令
"scripts": { "build": "gulp build" } -
执行
npm run build可以看到pages/目录下所有的vue文件都输出到dist目录下了。
Babel
Babel是一个通用的多功能的JavaScript 编译器,你为 Babel 提供一些 JavaScript 代码,Babel 更改这些代码,然后返回给你新生成的代码。这个处理过程的每一步都涉及到创建或是操作抽象语法树(AST),AST Explorer 可以让我们对AST节点有一个直观的认识。打开该网站,键入const a = 1 ,可以得到如下一个json对象:
{
"type": "Program",
"start": 0,
"end": 11,
"body": [
{
"type": "VariableDeclaration",
"start": 0,
"end": 11,
"declarations": [
{
"type": "VariableDeclarator",
"start": 6,
"end": 11,
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"name": "a"
},
"init": {
"type": "Literal",
"start": 10,
"end": 11,
"value": 1,
"raw": "1"
}
}
],
"kind": "const"
}
],
"sourceType": "module"
}
可以看到每个节点都有相同的结构(省略部分属性):
{
"type": "Literal",
"value": 1
}
{
"type": "Identifier",
"name": "a"
}
其中type字段表示该节点的类型,比如"Identifier" , "VariableDeclarator" 。
Babel的处理步骤
Babel 的三个主要处理步骤分别是: 解析(parse),转换(transform),生成(generate)。
babylon
Babylon 是 Babel 的解析器,用于生成抽象语法树。
babel-traverse
Babel Traverse(遍历)模块维护了整棵树的状态,并且负责替换、移除和添加节点。
babel-types
Babel Types模块用于构造、验证以及变换 AST 节点的方法。
babel-generator
Babel Generator模块是 Babel 的代码生成器,它读取AST并将其转换为代码和源码映射。
构建const a = 1
首先在AST Explorer 键入const a = 1 ,通过抽象节点树可以看到我们需要创建4个类型的节点(VariableDeclaration, VariableDeclarator, Identifier, Literal),查询文档我们可以很直观地得到创建节点的方法:
-
t.variableDeclaration(kind, declarations)- kind
:"var" | "let" | "const"` (required) declarations:Array<VariableDeclarator>(required)declare:boolean(default:null)
- kind
-
t.variableDeclarator(id, init)id:LVal(required)init:Expression(default:null)definite:boolean(default:null)
-
t.identifier(name)name:string(required)decorators:Array<Decorator>(default:null)optional:boolean(default:null)typeAnnotation:TypeAnnotation | TSTypeAnnotation | Noop(default:null)
-
t.numericLiteral(value)value:number(required)
根据抽象语法树,从内到外一层层创建节点的完整代码如下:
const babylon = require('babylon')
const t = require('@babel/types')
const generate = require('@babel/generator').default
const code = ''
const ast = babylon.parse(code) // 生成AST
const kind = "const"
const id = t.identifier("a") // a
const init = t.numericLiteral(1) // 1
const declaration = t.variableDeclarator(id, init) // a = 1
const variableDeclaration = t.variableDeclaration(kind, [declaration]) // const a = 1
ast.program.body.push(variableDeclaration)
const output = generate(ast, {}, code)
console.log(output.code) // const a = 1
将const a = 1 替换为const b = 1
Paths(路径)
Path 是表示两个节点之间连接的对象。
例如,如果有下面这样一个节点及其子节点︰
{
type: "FunctionDeclaration",
id: {
type: "Identifier",
name: "square"
},
...
}
将子节点 Identifier 表示为一个路径(Path)的话,看起来是这样的:
{
"parent": {
"type": "FunctionDeclaration",
"id": {...},
....
},
"node": {
"type": "Identifier",
"name": "square"
}
}
Path还包含添加、更新、移动和删除节点有关的其他很多方法,将const a = 1 替换为const b = 1 很简单,a 是一个Identifier 的节点,我们只需要遍历语法树,当访问到a 的时候调用path.replaceWith(node)即可替换节点。
完整代码如下:
const babylon = require('babylon')
const t = require('@babel/types')
const generate = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const code = 'const a = 1'
const ast = babylon.parse(code)
traverse(ast, {
Identifier(path) {
if (path.node.name === 'a') {
path.replaceWith(t.identifier("b"))
}
}
})
const output = generate(ast, {}, code)
console.log(output.code) // const b = 1
本文讲解了关于uni-app转成微信小程序的基础知识,下篇文章将展开详细介绍转换的方法。
参考链接: