美文网首页
taro-convert 转换流程

taro-convert 转换流程

作者: 微微笑的蜗牛 | 来源:发表于2020-04-19 16:20 被阅读0次

taro-convert 是一个命令行工具,其作用是将原生微信小程序转换成 taro 标准代码。其主要是通过src/convertor/index.ts 中的 Convertor类来实现。

初始化

在生成Convertor对象时,除了一些必要的初始化工作外,比如初始化项目根路径,生成输出文件夹等等。其还会去解析微信小程序工程。主要包括如下几方面:

  1. 读取入口文件 app.js 路径。

  2. 读取配置文件 app.json,获取如下信息:

    • pages,获取路由信息,存放到页面路由集合中。
    • sitemapLocaiton,若存在,则将 sitemap.json 拷贝到转换输出目录。
    • subpackages/subPackages,获取 subpackages 信息,添加到路由页面集合中。
  3. 读取样式文件 app.wxss

转换过程

转换流程分为以下三个步骤:

  • 入口文件的转换
  • 页面文件的转换,逐个遍历页面文件,进行转换。即在 app.json 中定义的 pages
  • 根据模板生成工程配置文件

js 代码转换

主要分为入口文件App.js和导入文件的转换。

入口文件转换

主要是在 generateEntry 方法中,其内部调用了generateScriptFiles 处理导入的文件。

主要步骤如下:

  1. 调用 taroize 生成 astwxml 中导入的模板信息。taroize 的内部处理下面会有说明。
  2. 调用 parseAst 遍历并修改 ast,并且统计 importjs 文件,作为结果返回。
  3. 调用 generateMinimalEscapeCode,根据 ast 生成代码,并写入文件到输出目录。
  4. 若入口有样式文件,则调用 traverseStyle 进行处理。
  5. 若入口文件有 import 其他 js 文件,则继续调用 generateScriptFiles 进行处理。内部逻辑在下面会讲到。
  6. 若入口配置文件中有定义 tabBar,则调用 generateTabBarIcon 进行处理。将 Icon/selectedIcon 复制到输出目录。

导入文件转换

导入文件指的是通过 require/import 引入的文件。其转换逻辑主要在 generateScriptFiles 方法,入参为 js 文件路径集合。

主要步骤如下:

  1. 遍历每个 js 文件。
  2. 调用 wxTransformer 生成 ast。其内部逻辑很复杂,但是对于微信小程序来说,只是简单返回其 ast,无其他处理。
  3. 调用 parseAst 遍历并修改 ast,并返回 importjs 文件。其逻辑下面会有说明。
  4. 调用 generateMinimalEscapeCode 生成代码,写入文件。
  5. 因为当前处理的 js 文件可能也 import 了其他 js 文件,所以递归调用 generateScriptFiles 进行处理。

taroize 方法

taroize 是比较重要的一个方法,会进行一系列的预处理。其参数中包含了配置信息 xx.jsonjs 文件内容,wxml 模板信息。具体处理如下:

  1. parseXML

    如果传入了 xml,则进行解析,包括标签的解析。

  2. parseJSON

    json 加上括号包装成表达式 (json),调用 babeltemplate 方法返回对象表达式的节点信息 ObjectExpression。会用在后续的 parsePage 中(下面会提到),主要用于填充新生成类中的 config 的值。

    比如 json{'title': 'hello'},则会返回下图中红框部分。

image.png
  1. parseScript

    设置一系列babel插件参数,将代码转换为 ast。然后做如下处理:

    1. 自定义 vistior 进行访问。

      • 遇到 BlockStatement,即方法具体实现 {}, 将 作用域scope 的值从 wx 修改为 Taro

        也就是说如果在 xx.js 最外层定义了 function,会走到这里。如下:

        //获取应用实例
        const app = Taro.getApp()
        
        function test() {
          console.log('test')
        }
        
      • 遇到 Identifier 标识符,且节点名为 wx,则替换为 Taro

      • 遇到 CallExpression 函数调用,进行标识符、属性调用的替换以及类的生成。

        1. 标识符替换

          如果IdentifiergetApp/getCurrentPages,替换成 Taro.getApp/Taro.getCurrentPages 调用。

        2. 属性调用替换

          如果为 wx.xxx 的调用,则替换为 Taro.xxx

        3. Page/Component/App 方法调用,类的生成

          如果是 Page/Component/App 方法,则说明其为微信小程序·。调用 parsePage 返回一个 ClassDecleration 结构,插入到 body 中。这样生成的文件中就会包含如下信息:

          @withWeapp({ xx })
          class _C extends Taro.Component {
               config = {
                 navigationBarTitleText: '查看启动日志'
               }
               
               render () {
               }
          }
          

          其中 parsePage中包括 configrender 方法,装饰器 withWeapp 的生成。config 为配置文件 json 中的信息。

          {
              "navigationBarTitleText": "查看启动日志",
              "usingComponents": {}
          }
          
    2. 如果不为微信小程序,则在 js 文件末尾默认加上 ;Component({}),再进行以上处理。

    3. 导入使用的组件和依赖文件,结果如下所示:

       ```
       import { Block, View, Button, Image, Text } from '@tarojs/components'
       import Taro from '@tarojs/taro'
       import withWeapp from '@tarojs/with-weapp'
       ```
      

      其中使用的组件是通过解析 wxml中的标签来计算,比如以下 xml 代码:

       ```
       <view class="container log-list">
           <block wx:for="{{logs}}" wx:for-item="log">
               <text class="log-item">{{index + 1}}. {{log}}</text>
           </block>
       </view>
       ```
      

      则会自动引入 BlockViewText 组件,其中 Block是默认就会引入的,无论在 xml 中是否使用。

parseAst 方法

可使用 https://astexplorer.net/ 查看语法树。

主要用来遍历 ast,对其进行修改,并统计 importjs 文件信息。其中语法树的修改包括头部导入 Taro 框架,调用对象的替换为Taro 等等。

首先使用 traverse 进行 ast 遍历,分为 enterexit两个过程。

enter 处理

enter 时会处理如下几种类型:

  1. ClassDeclaration,类的声明。

    内部会继续遍历 ClassMethod,类中定义的方法。如果遇到 render,继续遍历,如果存在 JSXElment,标记为 taro组件,并记录类名。

    一个 JSXElement 如下,相当于一个组件的声明。

    <Image src={require('../kkk')}></Image>
    
  2. ClassExpression,这里主要用于类被赋值给一个变量的情况,= 右边为 ClassExpression。内部处理方式同步骤1

        f = class NamedFoo {
          constructor() {}
          whoIsThere() {
            return NamedFoo.name;
          }
        }
    
  3. ExportDefaultDeclaration,处理 export default 的情况。同样包括两种情况。内部处理方式同步骤 1

    • export default class Component {}
    • export default a = class Component {}
  4. ImportDeclaration,处理 importjs/ts 文件。

    通过调用 analyzeImportUrl 分析引入的 js/ts 文件。

  5. CallExpression,处理函数调用。

    • 若调用了 require,则调用 analyzeImportUrl 分析出 importjs/ts 文件。
    • 若调用了微信小程序的 ['getApp', 'getCurrentPages', 'requirePlugin'] 这几个方法,则会替换成 Taro 调用,并标记需要引入 Taro 框架。
  6. MemberExpression,处理对象属性调用。
    如果调用对象为 wx,则替换成 Taro。同时标记需要导入 Taro 框架。

    wx.setStorageSync('logs', logs)  => Taro.setStorageSync('logs', logs)
    
exit 处理

exit 中做如下处理。

  1. 处理body节点,如果需要导入 @tarojs/taro,则加入importDeclaration节点。

    import Taro from '@tarojs/taro'
    
  2. 遍历 StringLiteral,主要处理图片路径引用。

    • 计算其绝对路径, 并将图片复制到输出目录。重新计算源文件与图片的相对路径 relativePath

    • 如果其父节点是变量声明(值为图片路径),则使用 require(relativePath)进行替换。

    • 如果其父节点是 JSX 属性,则使用 jSXExpressionContainer 进行替换,即{require(relativePath)}表达式的方式进行替换。

      在下例中, src 就是 JSX 属性。

      <Image src={require('../kkk')}></Image>
      
  3. 导入依赖文件,包括引入样式和其他依赖

    导入样式:

    import './app.scss'
    

    导入依赖组件和文件:

    import xx from 'xx'
    

    其中依赖的组件是从页面配置文件的 usingComponent 中解析出来的。

  4. 如果判断 isApptrue,则会在最后插入一段代码。

    Taro.render(<App />, document.getElementById('app'))
    

    但只有在解析入口文件时, isApp 才为 true

样式转换

通过 postcss,传入自己写的postcss-taro-unit-transform插件来进行转换的。其内部实现很简单,主要做了两件事情:

  • 10px 转换为 20px,即将数值 * 2
  • rpx 替换为 px

页面转换

包括js 文件转换 + 样式转换 + 依赖组件递归转换。与入口文件的转换类似,多了页面模板 wxml + 依赖组件的转换

其会从页面配置信息中拿到出依赖的组件信息。

组件转换

同页面转换。

根据模板生成配置文件

根据对应文件的模板生成相应的内容。

配置文件

  • index.js:通用配置
  • dev.js:开发配置,会合并 index.js
  • pro.js:发布配置,会合并 index.js
  • .gitignore
  • .editorconfig:编辑器相关配置
  • .eslintrceslint 相关配置
  • project.config.json:工程配置
  • package.json
  • src/index.html

相关文章

网友评论

      本文标题:taro-convert 转换流程

      本文链接:https://www.haomeiwen.com/subject/woombhtx.html