阅读 6942

Taro 2.0:拥抱社区,拥抱变化

缘起

Taro 1.x 版本自去年 9 月份发布以来,已经陪伴大家度过了一年多的时间,在此期间 Taro 一直保持高速成长,发布了多个具有重大意义的版本,让 Taro 成为如今一个功能完善,拥有众多忠实拥趸的多端统一开发框架。

尽管 Taro 一直保持超高的迭代速度,Taro 的整体架构设计没有发生太大变化,这让 Taro 在这个时刻在变化的时代稍显佛系,且对于一个时刻想要突破自己的技术团队来说,常规性质的维护工作,显然无法安抚我们躁动的心,毕竟人的梦想,是永远不会停止的,所以我们决定启动一系列的颠覆式重构设计。

2.0

我们首先从 CLI 开始入手进行改造,大家都知道,原来 Taro CLI 的编译构建系统是自研的,整个构建系统逻辑复杂,要考虑的边际条件众多,这就导致了以下问题:

  • 维护困难,每次需要新增一个功能,例如支持解析 Markdown 文件,就需要直接改动 CLI,不够灵活
  • 难以共建,CLI 的代码非常复杂,而且逻辑分支众多,让很多想要一起共建的人难以入手
  • 可扩展性偏低,自研的构建系统,设计之初没有考虑到后续的扩展性,导致开发者想要添加自定义的功能无从下手

基于以上问题,我们决定使用 Webpack 来实现编译构建,于是诞生了 2.0。

Taro 2.0 的 CLI 将会变得非常轻量,只会做区分编译平台、处理不同平台编译入参等操作,随后再调用对应平台的 runner 编译器 做代码编译操作,而原来大量的 AST 语法操作将会改造成 Webpack Plugin 以及 Loader,交给 Webpack 来处理。

taro-cli 2.0

相较于旧的构建系统,新的小程序编译带来了以下优势:

  • 利于维护,大量的逻辑交由 Webpack 来处理,我们只需要维护一些插件
  • 更加稳定,相较于自研的构建系统,新的构建会更加稳定,降低一些奇怪错误的出现概率
  • 可扩展性强,可以通过自行加入 Webpack Loader 与 Plugin 的方式做自己想要的扩展
  • 各端编译统一,接入 Webpack 后,Taro 各端的编译配置可以实现非常大程度的统一

可以看到新的构建系统会有很大的进步。同时,更重要的是,基于 Webpack,我们可以在小程序中尝试更多的特性与技术,例如通过 tree shaking 来优化代码包大小等等,让小程序开发更加与业界发展同步,让 Taro 更加拥抱社区。

Migrate to 2.0

编译配置调整

2.0 整体上与 1.0 是完全兼容的,但是在基于 Webpack 重构后,我们对部分编译配置做了优化调整,所以如果想要将基于 1.x 的旧项目迁移至 2.0,首先需要对编译配置进行调整。

const config = {
  projectName: 'taro-framework',
  date: '2019-11-2',
  designWidth: 750,
  deviceRatio: {
    640: 2.34 / 2,
    750: 1,
    828: 1.81 / 2
  },
  sourceRoot: 'src',
  outputRoot: 'dist',
  // babel、csso、uglify 等配置从 plugins 配置中移出来
  babel: {
    sourceMap: true,
    presets: [['env', { modules: false }]],,
    plugins: [
      'transform-decorators-legacy',
      'transform-class-properties',
      'transform-object-rest-spread'
    ]
  },
  // 小程序配置从 weapp 改为 mini,可以删掉很多小配置
  mini: {
    webpackChain (chain, webpack) {},
    cssLoaderOption: {},
    postcss: {
      pxtransform: {
        enable: true,
        config: {}
      },
      url: {
        enable: true,
        config: {
          limit: 10240 // 设定转换尺寸上限
        }
      }
    }
  },
  // 可以删掉很多小配置
  h5: {
    publicPath: '/',
    staticDirectory: 'static',
    webpackChain (chain, webpack) {},
    postcss: {
      autoprefixer: {
        enable: true,
        config: {
          browsers: [
            'last 3 versions',
            'Android >= 4.1',
            'ios >= 8'
          ]
        }
      }
    }
  }
}

module.exports = function (merge) {
  if (process.env.NODE_ENV === 'development') {
    return merge({}, config, require('./dev'))
  }
  return merge({}, config, require('./prod'))
}
复制代码

具体编译配置请参考 编译配置文档

异步编程调整

Taro 2.0 中开启 async functions 支持不再需要安装 @tarojs/async-await,而是直接通过 babel 插件来获得支持。

在项目根目录下安装包 babel-plugin-transform-runtimebabel-runtime

$ yarn add babel-plugin-transform-runtime --dev
$ yarn add babel-runtime
复制代码

随后修改项目 babel 配置,配置插件 babel-plugin-transform-runtime

babel: {
  sourceMap: true,
  presets: [['env', { modules: false }]],
  plugins: [
    'transform-decorators-legacy',
    'transform-class-properties',
    'transform-object-rest-spread',
    ['transform-runtime', {
      "helpers": false,
      "polyfill": false,
      "regenerator": true,
      "moduleName": 'babel-runtime'
    }]
  ]
}
复制代码

新特性尝鲜

在基于 Webpack 改造后带来全面提升的同时,2.0 也为我们带来了以下新的特性。

主编译流程钩子

在 2.0 中,CLI 编译的主流程已经基于 Tapable 进行改造,并且对外暴露了 hooks 以供使用,在 Taro 编译配置中可以通过 plugins 来配置编译过程插件,调用这些 hooks 来实现自己的需求。

目前编译主流程暴露了两个钩子 beforeBuildafterBuild,其中,beforeBuild 将在整体编译前触发,可以获取到编译的相关配置,同时也能进行修改;afterBuild 将在 Webpack 编译完后执行,可以获取到编译后的结果。具体使用方式如下。

首先定义一个插件

class BuildPlugin {
  apply (builder) {
    builder.hooks.beforeBuild.tap('BuildPlugin', (config) => {
      console.log(config)
    })

    builder.hooks.afterBuild.tap('BuildPlugin', (stats) => {
      console.log(stats)
    })
  }
}
复制代码

接下来在 plugins 字段中进行配置

const config = {
  ...
  plugins: [
    new BuildPlugin()
  ]
  ...
}
复制代码

为小程序编译添加 Loader

我们有时候可能会面临在小程序中展示 Markdown 语法文件的需求,在 WEB 开发的时候我们可以借助 Webpack 及其 Loader,实现直接引入 md 文件并读取其内容,而在小程序开发中,通过借助 Taro 2.0,我们也能很轻松地实现这一需求。

一般我们会以如下的方式,来引入一个 .md 文件。

import mdTxt from '../../some_markdown.md'
复制代码

.md 文件默认是不能直接被识别的,我们需要通过配置相应的 Loader 来实现对这类文件的加载解析,在 Taro 中可以通过 mini.webpackChain 来为小程序配置自定义 Webpack 配置,我们也可以通过它来配置 Loader。

const config = {
  mini: {
    webpackChain (chain) {
      chain.merge({
        module: {
          rule: {
            myloader: {
              test: /\.md$/,
              use: [{
                loader: 'raw-loader',
                options: {}
              }]
            }
          }
        }
      })
    }
  }
}
复制代码

为小程序编译添加 Plugin

当我们要把打包后的小程序进行发布的时候,可能会遇到小程序过大的问题,那么我们肯定迫切希望可以看到到底是哪些文件的大小造成了这个影响,我们可以通过使用 webpack-bundle-analyzer 插件对打包体积进行分析。

mini.webpackChain 中添加如下配置。

const config = {
  mini: {
    webpackChain (chain, webpack) {
      chain.plugin('analyzer')
        .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
    }
  }
}
复制代码

在运行之后,我们就能在浏览器里看到如下分析效果。

webpack-bundle-analyzer

Taro RN 依赖升级到 0.59.9

在 2.0 中我们将 RN 端 React 依赖升级到 16.8.0,React Native 依赖升级到 0.59.9。主要原因:

  • Google 要求所有 Google Play 应用支持 64 位 so 库,而现有 RN 0.55.4 依无法支持 64 位库,为配合 64 位升级,Taro RN 端的 React Native 依赖需要同步升级
  • React 16.8.0 是第一个支持 Hook 的版本,React Native 从 0.59 版本开始支持 Hook,此前社区一直在呼吁对 RN 0.55.4 进行升级以直接支持 Hook 的写法

本次 RN 端属于无缝升级,原有的写法和配置均不变,如果使用 taro-native-shell 的,选择 0.59.9 分支即可;在原生应用集成 RN 的,需要自行升级 React Native 依赖到 0.59.9。

未来与展望

正如前文所提到的,Taro 2.0 只是一个开始。

在 10 年代最后一场 GMTC 全球大前端技术大会上,Taro 团队向大家展示了 小程序跨框架开发的探索与实践 的艰辛旅程,同时也提前曝光了正在紧密开发中的 Taro Next

那是一个完全区别于以往的版本,一条与现在 Taro 截然不同的道路,预示着 Taro 正在革自己的命。

节物风光不相待,桑田碧海须臾改。

20 年代呼啸而来,下一个 10 年,很多框架都会死去,很多技术也会焕然而生,没有什么是不变的,唯一不变的只有变化,我们能做的也只能是拥抱变化。