Taro 是什么
Taro 是由凹凸实验室打造的一套遵循 React 语法规范的多端统一开发框架。
现如今市面上端的形态多种多样,Web、App 端(React Native)、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。
使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信小程序、H5、App 端等)运行的代码。同时 Taro 还提供开箱即用的语法检测和自动补全等功能,有效地提升了开发体验和开发效率。
Taro 能提供什么
Write once, run anywhere
写一套代码输出多端可运行的代码,节省了大量的学习成本及工作量。

taro遵循 React 语法标准,结合编译原理的思想,对代码文件进行一系列转换操作,最终获得可以在小程序运行的代码。而 React 最开始就是为了解决 Web 开发而生的,所以对代码稍加改动,也可以直接生成在 Web 端运行的代码,而同属 React 语法体系下的 React Native,也能够很便捷地提供支持。同理其他平台,如快应用、百度小程序等,将源码进行编译转换操作,也能获得该平台下的对应语法代码。
多端开发实践
CLI工具安装
# 使用 npm 安装 CLI
$ npm install -g @tarojs/cli
# OR 使用 yarn 安装 CLI
$ yarn global add @tarojs/cli
# OR 安装了 cnpm,使用 cnpm 安装 CLI
$ cnpm install -g @tarojs/cli
项目初始化
taro init myApp

运行
需确保Taro CLI的版本与你的项目的依赖版本一致,否则会出现编译错误或者运行时错误。除h5以外,其它各端均需下载相应的开发者工具
1、微信小程序
# yarn
$ yarn dev:weapp
$ yarn build:weapp
# npm script
$ npm run dev:weapp
$ npm run build:weapp
2、H5
# yarn
$ yarn dev:h5
$ yarn build:h5
# npm script
$ npm run dev:h5
$ npm run build:h5
其它端运行可见官网
项目配置文件config
dev.js
module.exports = {
env: {
NODE_ENV: '"development"'
},
defineConstants: {},
mini: {},
h5: {
devServer: {
proxy: {
"/": {
target: "proxy address",
changeOrigin: true
}
}
}
}
};
index.js
const path = require('path')
const config = {
projectName: "taro-template",
date: "2020-1-26",
designWidth: 750,
deviceRatio: {
"640": 2.34 / 2,
"750": 1,
"828": 1.81 / 2
},
sourceRoot: "src",
outputRoot: `dist/taro-template-${process.env.TARO_ENV}`,
alias: {
"@/service": path.resolve(__dirname, "..", "src/service"),
"@/utils": path.resolve(__dirname, "..", "src/utils")
},
copy: {
patterns: [
{ from: "src/static/", to: `dist/taro-template-${process.env.TARO_ENV}` } // 指定需要 copy 的文件
]
},
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"
}
]
]
},
defineConstants: {},
mini: {
postcss: {
autoprefixer: {
enable: true,
config: {
browsers: ["last 3 versions", "Android >= 4.1", "ios >= 8"]
}
},
pxtransform: {
enable: true,
config: {}
},
url: {
enable: true,
config: {
limit: 10240 // 设定转换尺寸上限
}
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: "module", // 转换模式,取值为 global/module
generateScopedName: "[name]__[local]___[hash:base64:5]"
}
}
}
},
h5: {
publicPath: "/",
staticDirectory: "static",
output: {
filename: "js/[name].[hash:8].js",
chunkFilename: "js/[name].[chunkhash:8].js"
},
imageUrlLoaderOption: {
limit: 5000,
name: 'static/images/[name].[hash].[ext]'
},
miniCssExtractPluginOption: {
filename: "css/[name].[hash:8].css",
chunkFilename: "css/[name].[chunkhash:8].css"
},
postcss: {
autoprefixer: {
enable: true,
config: {
browsers: ["last 3 versions", "Android >= 4.1", "ios >= 8"]
}
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: "module", // 转换模式,取值为 global/module
generateScopedName: "[name]__[local]___[hash:base64:5]"
}
}
}
}
};
module.exports = function (merge) {
if (process.env.NODE_ENV === "development") {
return merge({}, config, require('./dev'));
}
return merge({}, config, require('./prod'));
};
prod.js
module.exports = {
env: {
NODE_ENV: '"production"'
},
defineConstants: {},
mini: {},
h5: {
/**
* 如果h5端编译后体积过大,可以使用webpack-bundle-analyzer插件对打包体积进行分析。
* 参考代码如下:
* webpackChain (chain) {
* chain.plugin('analyzer')
* .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
* }
*/
}
};
多端实践
不同端的需求多少会有差异性,会存在页面样式,交互形式,页面逻辑的区别,这个时候就需要根据编译的环境来执行不同的代码。
内置环境变量
process.env.TARO_ENV
用来判断当前编译类型,目前有weapp / swan / alipay / h5 / rn / tt / qq / quickapp 八个取值,可以通过这个变量,来编写不同环境下不同的代码。
- 不同端引用不同资源
if(process.env.TARO_ENV === 'weapp'){
require('path/to/weapp/name')
}else if(process.env.TARO_ENV === 'h5'){
require('path/to/h5/name')
}
- JSX 中使用,不同端加载不同组件
render(){
return (
<View>
{process.env.TARO_ENV === 'weapp' && <ScrollViewWeapp />}
{process.env.TARO_ENV === 'h5' && <ScrollViewH5 />}
</View>
)
}
统一接口的多端文件(1.2.17版本开始支持)
内置环境变量虽然可以解决大部分跨端的问题,但是代码中会充斥着逻辑判断的代码,影响代码的可维护性,而且也让代码变得愈发丑陋,为了解决这种问题,自 1.2.17 开始,Taro 提供了另外一种跨端开发的方式作为补充。
开发者可以通过使用统一接口的多端文件,来解决跨端差异的功能。针对这一项功能,如果多个端之间都有差异,那么开发者可以通过将文件修改成 原文件名+端类型 的命名方式,不同端的文件代码对外保持统一接口,而引用的时候仍然是import 原文件名的文件,Taro在编译时,会根据需要编译平台类型,将加载的文件变更为带有对应端类型文件名的文件,从而达到不同的端加载对应文件的目的。
端类型对应着process.env.TARO_ENV的值
通常有以下两种使用场景
1、 多端组件
假如有一个test组件存在微信小程序,h5两个个不同版本,那么就可以像如下组织代码。
test.js 文件,这是Test组件默认的形式,编译到微信小程序,h5l两端之外的端使用的版本。
test.h5.js 文件,这是Test组件的H5版本。
test.weapp.js 文件,这是Test组件的微信小程序版本。
三个文件,对外暴露的是统一的接口,它们接受一致的参数,只有内部有针对各自平台的代码的实现。使用的方式仍和之前保持一致,import的是不带端类型的文件名,在编译的时候会自动识别并添加端类型后缀
import Test from '../../components/test'
<Text argA={1} argA={2} />
2、多端脚本
与多端组件类似,假如有需要针对不同的端写不同的脚本逻辑代码,我们也可以进行类似的相应处理,遵守的唯一原则就算多端文件对外的接口保持一致。
例如微信小程序上使用Taro.setNavigationBarTitle来设置页面标题,H5使用document.title,那么可以封装一个setTitle方法来抹平两个平台的差异。
增加set_title.h5.js,代码如下
export default function setTitle(title){
document.title = title
}
增加set_title.weapp.js,代码如下
import Taro from '@tarojs/taro'
export default function setTitle(title){
Taro.setNavigationBarTitle({
title
})
}
调用的时候,如下使用
import setTitle from '../utils/set_title'
setTitle('页面标题')
app.js中使用不同的pages(1.3.11版本开始支持)
根据不同环境返回不同的pages,可以这么写
config:Config = {
"pages":preval`
module.exports = (function() {
if(process.env.TARO_ENV === 'weapp') {
return [
'/pages/index/index'
]
}
if(process.env.TARO_ENV === 'swan'){
return [
'/pages/indexswan/indexswan'
]
}
})()
`
}
样式的条件编译(1.3+版本支持)
1、样式文件条件编译
假设目录中同时存在以下文件:
-index.scss
-index.rn.scss
当JS文件中引用样式文件:import './index.scss'时,RN平台会找到并引入index.rn.scss,其他平台会引入:index.scss,方便大家书写跨端样式,更好的兼容RN(其它端使用无效)
2、样式文件的条件编译
为了方便大家书写样式跨端的样式代码,添加了样式条件编译的特性
指定平台保留
/* #ifdef %PLATFORM% */
样式代码
/* #endif */
指定平台剔除
/* #ifndef %PLATFORM% */
样式代码
/* #endif */
多个平台之间可以使用空格隔开
多端同步调试(1.3.5版本开始支持)
从1.3.5版本开始,可以在dist目录下创建一个与编译的目标平台名同名的目录,并将结果放在这个目录下,例如编译到微信小程序,最终结果是在dist/weapp目录下,这样做的好处是,各个平台使用独立的目录互不影响,从而达到多端同步调试的目的,在config/index.js配置如下:
outputRoot:`dist/${process.env.TARO_ENV}`
参考地址:
1、官网 taro.aotu.io/
2、aotu.io/notes/2018/…