⚠️ For Your Infomation:本文所实践的方法非最优解,笔者也不建议使用 AST 自动生成 React Native 路由,因为 Babel 操作相对复杂且容易导致错误,笔者更建议使用模板字符串。本文主要目的是验证 AST 在自动路由生成方面的可行性,而非最佳实践指南。

问题背景

在 React Native 中,无法使用 React RouteWouter 这类基于浏览器环境的路由管理工具,因为 React Native 自身不运行在浏览器环境,所以没有浏览器的 DOM 或 BOM API。因此需要使用 React Navigation 使用系统级原生 API 创建与管理界面(在 Android 里为 Activity,在 iOS 为 UIView)

在使用 React Navigation 时,需要手动使用 Stack.Screen 声明每一个页面。它无法像 uminext.js 这类框架,通过约定式路由或路由声明文件来自动生成路由表。这是因为 React Native 里的 JS 它不运行在 node.js ,只是一个很单纯的运行时环境。

import Home from './pages/home'
import Login from './pages/login'

<Stack.Navigator initialRouteName="Home">
	<Stack.Screen name="Home" component={Home}/>
	<Stack.Screen name="Login" component={Login}/>
</Stack.Navigator>

那么这就意味着,在 React Native 无论编译时还是运行时,都无法做到自动导入,只能在 React Native 的 Metro( RN 专门的打包工具)启动前进行处理

以下内容将围绕以上问题,使用 AST 自动构建入口文件进行路由自动生成

您将需要

您将在本文实践中,使用以下第三方代码:

https://github.com/isaacs/node-glob

@babel/core

@babel/types

@babel/plugin-transform-react-jsx

1. 找到所有页面文件

一般 React Native 项目中,都会规范好页面文件的路径与命名规范,具体视您项目的规范确定,在本文将使用 /pages/${page-name}/index 规范命名

本文将使用 npm 包 glob,用于匹配文件。使用 glob 作为文件查找工具,是因为其支持通配符与类正则表达式,相比 fs 操作方式更为高效

glob(
  path.resolve(__dirname, './pages/*/?(index|index.android|index.ios).tsx'),
  (error, files) => {
    if (error) {
      return
    }
  }
)

根据以上命名规范,用于匹配的表达式为 './pages/*/?(index|index.android|index.ios).tsx'index.androidindex.ios 是 React Native 根据构建目标选择不同拓展名的文件,具体可参考:

Platform Specific Code · React Native

2. 获取页面名称