Skip to main content
Version: 3.x

原生项目使用 Taro

info

Taro v3.0.25 开始支持

基础混合用法

示例项目

blended-basic

用法

1. 开发环境

1.1 推荐在 Taro 项目中进行开发调试,在生产环境下再把产物移动到原生小程序中进行预览。

# 和编译普通 Taro 项目一样
$ taro build --type [platform] --watch

1.2 小程序开发者工具导入 Taro 项目进行预览。

2. 生产环境

1.1 编译项目时使用 --blended 参数以输出混合模式的代码。

# 以混合模式进行打包
$ taro build --type [platform] --blended

1.2 移动 Taro 项目的输出目录到原生项目内

也可以编写一个 Taro 插件自动移动,可以参考 plugin-mv

1.3 原生项目的 app.js 中引用 Taro 入口文件

app.config.js
// 必须引用 Taro 项目的入口文件
const taroApp = require('./taro/app.js').taroApp

App({
onShow () {
// 可选,调用 Taro 项目 app 的 onShow 生命周期
taroApp.onShow()
},

onHide () {
// 可选,调用 Taro 项目 app 的 onHide 生命周期
taroApp.onHide()
}
})

Taro 项目引用原生项目的 JS 文件

有时我们需要在 Taro 项目中引用原生项目中的公共 JS 模块(如上报 sdk)。但是 Webpack 会把这些公共模块一并打包,导致公共模块存在两份(Taro 产物中一份,原生项目中一份)。

为了优化包体积大小,我们希望不要打包到 Taro 产物中,而是直接引用原生项目中的代码,可以使用 Webpack 的 externals 配置去实现。

例子

假设以下项目结构:

├── miniapp           原生项目
| └── utils
| └── util.js
└── taro-project Taro 项目
├── config
| └── index.js
└── src
└── pages
└── index 此页面中希望引用 miniapp/utils/util.js
  1. 配置 alias,目的是让 externals 更方便地筛选出不需要打包的依赖。
  2. 配置 Webpack externals,选择出不需要打包的依赖,并计算好相对路径。
  3. 设置环境变量 process.env.NODE_ENVproduction 时,externals 生效。(当没有手动设置环境变量时,默认在 watch 模式时环境变量为 development,否则为 production
config/index.js
const config = {
alias: {
'@/utils': process.env.NODE_ENV === 'production'
// 生产环境路径计算:
// Webpack 编译发生在 taro-project 下,假设编译后的 taro-project/dist 会被移到到 miniapp/taro。
// path.resolve(__dirname, '..') 为 taro-project。taro-project/dist 之于 taro-project,相当于 miniapp/taro 之于 miniapp。
// 再根据 miniapp/utils 与 miniapp 的相对路径,得出 path.resolve(__dirname, '../utils')
? path.resolve(__dirname, '../utils')
// 开发环境直接引用原生项目下的依赖,方便开发
: path.resolve(__dirname, '../../miniapp/utils')
},
mini: {
webpackChain (chain) {
chain.merge({
externals: [
(context, request, callback) => {
const externalDirs = ['@/utils']
const externalDir = externalDirs.find(dir => request.startsWith(dir))

if (process.env.NODE_ENV === 'production' && externalDir) {
const externalDirPath = config.alias[externalDir]
const res = request.replace('@/utils', path.relative(context, externalDirPath))

return callback(null, `commonjs ${res}`)
}

callback()
},
]
})
}
}
}

效果

taro-project/src/pages/index/index.js
import { logSomething } from '@/utils/util'
logSomething()
webpack 打包结果
{
"./src/pages/index/index.jsx": (function(m, e, __webpack_require__) {
var _utils_util = __webpack_require__("@/utils/util");
// ...
}),
"@/utils/util": (function(module, exports) {
// 成功 external
module.exports = require("../../../utils/util");
})
}

Taro 项目引用原生项目的原生组件

有时我们需要在 Taro 项目中引用原生项目中的公共自定义组件。

引用原生项目的 js 文件一样,我们希望在开发环境能正确解析组件路径,在生产环境则直接引用原生项目的组件而不是重复打包,可以使用 Taro 的 alias 配置去实现。

例子

假设以下项目结构:

├── miniapp                原生项目
| └── components
| └── title
| ├── index.js
| ├── index.wxml
| ├── index.wxss
| └── index.json
└── taro-project Taro 项目
├── config
| └── index.js
└── src
├── components 小程序不支持引用根目录之外的组件,因此只能把原生项目的组件拷贝过来,让开发环境能正确解析组件
| └── title
└── pages
└── index 此页面中希望引用 miniapp/components/title
  1. 把原生项目的组件拷贝到 Taro 项目,让开发环境能正确解析组件。
  2. 根据开发环境和生产环境,正确配置 alias
config/index.js
const config = {
alias: {
'@/components': process.env.NODE_ENV === 'production'
// 生产环境路径计算:
// Webpack 编译发生在 taro-project 下,假设编译后的 taro-project/dist 会被移到到 miniapp/taro。
// path.resolve(__dirname, '..') 为 taro-project。taro-project/dist 之于 taro-project,相当于 miniapp/taro 之于 miniapp。
// 再根据 miniapp/components 与 miniapp 的相对路径,得出 path.resolve(__dirname, '../components')
? path.resolve(__dirname, '../components')
// 开发环境引用 taro-project/src 下的组件
: path.resolve(__dirname, '../src/components')
}
}
taro-project/src/pages/index/index.config.js
export default {
usingComponents: {
title: '@/components/title/index'
}
}

对 Taro 项目的部分页面分包

在原生项目中直接配置 subPackages 指向 Taro 编译后的页面即可。

依赖细分

Taro 默认会把页面共用的普通依赖打包为主包里的 common.js,node_modules 依赖打包为主包里的 vendor.js

但是在分包时,我们会希望把只有在分包中共用的依赖打包到分包中,而不是打在主包的 common.jsvendor.js 中。这就需要我们对依赖进行细分。可以借助 Webpack 的 splitChunk 和 Taro 的 addChunkPages 配置去实现。

例子

假设以下项目结构:

├── dist
| |── common.js 公共依赖
| |── vendors.js node_modules 依赖
| └── subPackages
| ├── foo
| ├── bar
| └── common.js 只有 subPackages 子包中使用的公共依赖
└── src
└── subPackages
├── foo
└── bar
  1. 使用 Webpack splitChunks 把只有 subpackages 子包独有的依赖打包到 subpackages/common.js 中。
  2. 使用 Taro addChunkPages 配置,在子包中所有页面的头部添加对 subpackages/common.js 的引用。
config/index.js
const config = {
mini: {
addChunkPages (pages) {
pages.set('subpackages/bar/index', ['subpackages/common']),
pages.set('subpackages/foo/index', ['subpackages/common'])
},
webpackChain (chain) {
chain.merge({
optimization: {
splitChunks: {
cacheGroups: {
subpackagesCommon: {
name: 'subpackages/common',
minChunks: 2,
test: (module, chunks) => {
const isNoOnlySubpackRequired = chunks.find(chunk => !(/\bsubpackages\b/.test(chunk.name)))
return !isNoOnlySubpackRequired
},
priority: 200
}
}
}
}
})
}
}
}

把 Taro 项目作为一个完整分包

示例项目

blended-apart

使用方法

1. 安装使用插件

安装插件 @tarojs/plugin-indie

npm i @tarojs/plugin-indie --save-dev

使用插件

config/index.js
const config = {
plugins: [
'@tarojs/plugin-indie'
]
}

2. 开发环境

2.1 推荐在 Taro 项目中进行开发调试,在生产环境下再把产物移动到原生小程序中进行预览。

# 和编译普通 Taro 项目一样
$ taro build --type [platform] --watch

2.2 小程序开发者工具导入 Taro 项目进行预览。

3. 生产环境

3.1 编译项目时使用 --blended 参数以输出混合模式的代码。

# 以混合模式进行打包
$ taro build --type [platform] --blended

3.2 移动 Taro 项目的输出目录到原生项目内

也可以编写一个 Taro 插件自动移动,可以参考 plugin-mv

3.3 设置原生项目的分包配置

把 Taro 项目拆分到多个分包

假设有一个 Taro 项目,它含有页面 A 和页面 B。我们需要把页面 A 加入原生项目的其中一个分包 M,把页面 B 加入到另一个分包 N。

为此,和普通打出一个分包不同的是,首先需要配置 Webpack 的 output.jsonpFunction 配置,避免 chunkid 的冲突。

config/index.js
config = {
mini: {
webpackChain (chain) {
chain.merge({
output: {
// 可以配合 npm script 和环境变量来动态修改
jsonpFunction: process.env.JSONP_NAME || "webpackJsonp"
}
})
}
}
}

然后分别对 A、B 页面使用混合模式打包,步骤和把 Taro 项目作为一个完整分包一致。

把 Taro 组件编译为原生自定义组件

info

Taro v3.1.2 开始支持,且暂时只支持 React

Taro 支持把组件编译为原生小程序自定义组件,供原生项目使用。

示例项目

blended-taro-component

使用方法

1. 配置组件路径

修改 app.config.js,增加 components 配置,指向组件入口文件的路径:

app.config.js
export default {
// ...
components: [
'pages/index/index',
'components/picker/index'
]
}

2. 开始编译

使用 taro build native-components 命令,配合参数 type,即可编译出对应平台的自定义组件。

taro build native-components --type [platform] [--watch]

props 传递

传递 props 给 Taro 编译出来的原生自定义组件时,需要统一通过 props 参数来传递:

page/index/index.js
Page({
data: {
pickerProps: {
mode: 'format',
value: [0, 0, 0],
onInitial (value, index) {
console.log('onInitial')
}
}
}
})
page/index/index.wxml
<!--index.wxml-->
<view>
<picker props="{{pickerProps}}"></picker>
</view>
Taro 组件 - Picker
function Picker ({ mode, value, onInitial }) {
return (
// ...
)
}

小程序自定义组件对象实例

开发者可以通过 props.$scope 获取到小程序的自定义组件对象实例。

使用某些小程序 API 时可能需要使用此实例,如获取视图层 DOM:

Taro.createSelectorQuery().in(props.$scope)

组件间通信与事件

支持使用两种方式进行组件间通信。

使用小程序的 triggerEvent

和小程序原生自定义组件的组件间通信与事件一样,子组件使用 triggerEvent 发送事件。

子组件
props.$scope.triggerEvent('myevent', myEventDetail, myEventOption)

通过 props 传递事件回调

父组件
Page({
data: {
childProps: {
// props 里可以传递函数
onMyEvent (value, index) {
console.log(value, index)
}
}
}
})
// 和普通 props 传递一样
<child props="{{childProps}}">
子组件
props.onMyEvent(value, index)

组件配置

info

Taro v3.3.20 开始支持

微信小程序的自定义组件支持配置 styleIsolationvirtualHost 等特性。在 Taro 中可以通过修改组件的配置文件进行设置:

index.config.js
export default {
styleIsolation: 'isolated',
virtualHost: true
}