入口文件
首先入口文件就是配置 Router 路由的页面, 每一个应用只应该存在一个入口文件。
在之前原理简介里面, 我们说过一个 React 组件会被转化为 wxml/wxss/js/json/comp.js 5个文件, 这里有一个例外:入口文件。入口文件里面定义了所有的页面,由于小程序的页面必须预先定义在 app.json 文件,json文件是静态的,无法在运行时处理,因此我们必须在转化的时候就识别出所有的页面,所以对于入口文件的文件要求是足够的静态,为了减少错误,尽量不要在入口文件处理其它逻辑,仅将入口文件用来定义路由页面。
关于这里的静态,我们将一一说明。
首先看一个常见的入口文件:
import {
Router,
Route,
TabRouter
} from '@areslabs/router'
import A from './a/index'
import B from './b/index'
import C from './c/index'
import D from './d/index' // 引入组件
import faxianPNG from '/assets/faxian.png'
import faxianCurrentPNG from '/assets/faxianCurrent.png'
import myPNG from '/assets/my.png'
import myCurrentPNG from '/assets/myCurrent.png'
class HelloWorld extends Component{
render() {
// Route指定对应的key和组件
return (
<Router>
<TabRouter text="F" image={faxianPNG} selectedImage={faxianCurrentPNG}>
<Route key="A" component={A}/>
<Route key="B" component={B}/>
<Route key="D" component={D}/>
</TabRouter>
<TabRouter text="S" image={myPNG} selectedImage={myCurrentPNG}>
<Route key="C" component={C}/>
</TabRouter>
</Router>
)
}
}
这个文件在转化的时候,会进行一次静态代码分析。在小程序上被转化为对应的app.json 文件,如下所示:
{
"pages": [
"a/index", // 对应引入路径 import A from './a/index'。 如果是目录, 会自动补全index
"c/index",
"b/index",
"d/index"
],
"tabBar": {
"list": [
{
"pagePath": "a/index",
"text": "F",
"iconPath": "/assets/faxian.png",
"selectedIconPath": "/assets/faxianCurrent.png"
},
{
"pagePath": "c/index",
"text": "S",
"iconPath": "/assets/my.png",
"selectedIconPath": "/assets/myCurrent.png"
}
]
}
}
在生成app.json 文件的同时,会在小程序全局变量 wx
上增加 _historyConfig
属性
wx._historyConfig =
{
"A": "/a/index", // key A直接对应Route属性的key,Value对应 组件引入路径 import A from './a/index',如果引入的是目录,会自动补全
"C": "/c/index",
"B": "/b/index",
"D": "/d/index"
}
生成以上 app.json 和 historyConfig 是在代码静态分析的过程中进行的,这里要求我们必须在代码静态分析的时候就能够获取到
key
值, component
路径。 假如 component
是某个函数的计算结果,那么转化引擎就无法准确的获取到组件路径,从而无法在静态分析阶段
构造出 app.json 文件。
让我们看下常见的错误入口文件:
import {
Router,
Route,
TabRouter
} from '@areslabs/router'
import A from './a/index'
import B from './b/index'
import C from './c/index'
import D from './d/index' // 引入组件
import F from './f/index'
import G from './g/index'
import faxianPNG from '/assets/faxian.png'
import faxianCurrentPNG from '/assets/faxianCurrent.png'
import myPNG from '/assets/my.png'
import myCurrentPNG from '/assets/myCurrent.png'
import someHOC from 'someHOC'
const E = someHOC(D)
const otherPageMaps = [
{
key: 'F',
component: F
},
{
key: 'G',
component: G
},
]
class JDReactFirst extends Component{
render() {
const Ckey = getCkey()
//
return (
<Router>
<TabRouter text="F" image={faxianPNG} selectedImage={faxianCurrentPNG}>
<Route key="D" component={E}/>
</TabRouter>
<TabRouter text="S" image={myPNG} selectedImage={myCurrentPNG}>
<Route key={Ckey} component={C}/>
</TabRouter>
<TabRouter text="other" image={myPNG} selectedImage={myCurrentPNG}>
{
otherPageMaps.map(item => <Route key={item.key} component={item.component} />)
}
</TabRouter>
</Router>
)
}
}
这里的入口文件有几个错误,具体如下:
<Route key="D" component={E}/>
这里的 E 是由const E = someHOC(D)
, 注意静态代码分析并不能准确的知道 someHOC 是什么,这必须在运行期才能准确知晓。所以当转化引擎分析到 E 这里的时候,不能准确的获取路径,因而无法生成 app.json 文件<Route key={Ckey} component={C}/>
这里的key
由const Ckey = getCkey()
, 同样的原因无法在静态分析的时候获取准确的key
字符串进而无法生成_historyConfig
属性。otherPageMaps.map(item => <Route key={item.key} component={item.component} />)
原因同1和2。静态分析的时候是不会执行代码,所以这里 map 返回的数组不会被分析。
配合Redux使用
一般情况下 Redux 的配置也会在入口文件,如下所示:
import React, {PureComponent} from 'react'
import {Platform} from 'react-native'
import PropTypes from 'prop-types'
import {createStore, applyMiddleware} from 'redux'
//Middleware
import promiseMiddleware from 'redux-promise'
import thunk from 'redux-thunk'
import todoApp from './reducers'
import {Provider} from 'react-redux'
import {
Router,
Route
} from '@areslabs/router'
import Index from './components/index'
// 定义Redux store
const store = createStore(todoApp, applyMiddleware(thunk, promiseMiddleware))
export default class JDReactRedux extends PureComponent {
render() {
return (
<Provider store={store}>
<Router>
<Route key="init" component={Index}/>
</Router>
</Provider>
);
}
}
最后
- 以上说明只针对需要转化微信小程序的RN应用,对于没有转化需要的RN应用,写法没有任何限制
- RN 端支持
initRoute
属性,用来指定初始页,而小程序会完全忽略这个属性 - 以上说明的 app.json 文件是小程序系统必不可少的文件,当前没有绕过的方案,所以入口文件的限制不会随着版本的迭代而消失。
- 如此静态的限制,会让开发者在开发的时候不经意间出错,所以一定要足够的重视,好在依赖 AST 静态分析的内容不多。所有限制已经全部列在了静态限制中。