入口文件

首先入口文件就是配置 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>
    )
  }
}

这里的入口文件有几个错误,具体如下:

  1. <Route key="D" component={E}/> 这里的 E 是由const E = someHOC(D), 注意静态代码分析并不能准确的知道 someHOC 是什么,这必须在运行期才能准确知晓。所以当转化引擎分析到 E 这里的时候,不能准确的获取路径,因而无法生成 app.json 文件

  2. <Route key={Ckey} component={C}/> 这里的 keyconst Ckey = getCkey() , 同样的原因无法在静态分析的时候获取准确的 key 字符串进而无法生成 _historyConfig 属性。

  3. 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>
        );
    }
}

最后

  1. 以上说明只针对需要转化微信小程序的RN应用,对于没有转化需要的RN应用,写法没有任何限制
  2. RN 端支持 initRoute 属性,用来指定初始页,而小程序会完全忽略这个属性
  3. 以上说明的 app.json 文件是小程序系统必不可少的文件,当前没有绕过的方案,所以入口文件的限制不会随着版本的迭代而消失。
  4. 如此静态的限制,会让开发者在开发的时候不经意间出错,所以一定要足够的重视,好在依赖 AST 静态分析的内容不多。所有限制已经全部列在了静态限制中。

results matching ""

    No results matching ""