Taro 小程序路由全自动配置

1,137 阅读3分钟

前言

使用过 Umi 框架的人一定会对它的约定式路由印象深刻。在约定式路由模式下,pages 目录下新建文件,其他页面即可直接书写链接进行跳转。

Taro 框架中自带了路由功能,但是每新建一个页面文件后,需要在 app.config.ts 文件中配置页面地址,在进行页面跳转时,还需要带上长长的一串链接,书写麻烦的同时还容易出错。

navigateTo({
  url: `/package-appointment/pages/manage-appointments/index?roomId=${roomId}&appointmentId=${appointmentId}&scriptId=${scriptId}`
})

将页面地址维护到一个映射表中,方便管理和使用。

navigateTo({
  url: `${URLs.ManageAppointment}?roomId=${roomId}&appointmentId=${appointmentId}&scriptId=${scriptId}`
})

但是又带来的新的问题,开发一个页面,不仅要维护 app.config.ts 还要维护映射表文件。且参数又长又不美观。

如何解决这些问题呢?

经过我不断摸索,可以做到新建页面文件后,0配置,其他页面直接调用类似下面的API,即可进行跳转

routerService.toManageAppointments({ roomId, appointmentId, scriptId })

下图演示了,删除分包页面后,自动更新 app.config.ts

正文

实现原理很简单:1.监听页面文件创建。2.执行脚本修改和生成代码。

监听页面文件/文件夹创建

说到监听,我们首先会想到 webpack -watch 模式。但要注意的是,webpack 只监听代码依赖树中的文件,即新建的文件或文件夹是不会被 webpack 监听的。那如何实现监听页面文件的创建呢?Node 有 watch API 可以实现这一点,但在各个平台可能存在各种各样的问题,因而我使用了 chokidar 去监听文件创建。

工具是有了,但怎么整合到项目中呢?总不能打开两个控制台,一个跑项目,一个跑文件监听吧。webpack-plugin-chokidar插件可以解决问题,通过 taro 的 webpackChain 配置,可以很容易监听文件/文件夹修改。

插件监听配置实例如下

const basePath = path.resolve(__dirname, '../src');

...
new WebPackPluginChokidar({
  chokidarConfigList: [
    {
      file:  basePath + '/**/pages/**/index.tsx',	// 监听路径(支持主包和分包)
      opt: { persistent: true, ignoreInitial: true },	// 监听配置选项( 配置项参考chokidar)
      actions: {
        on: {
          add: ({ compiler, compilation, watcher }, path, ...rest) => {	// 监听文件创建
            console.log(`File ${path} has been added`);
          },
        },
      },
    },
  ],
});

在上面代码中,只需要在 add 回调函数中,调用修改代码脚本即可。

代码修改与生成

这一步中,需要修改 project.config.jsonapp.config.ts,和生成 routerService.ts 文件。project.config.json 文件很好处理,直接在脚本中通过 require 引入,当做一个 JS 对象操作,最后通过 Node fs API 写入即可。

我们修改代码最常用的是直接 fs.readFile 读文件,字符串匹配更换文本,这样操作虽然简单快捷,但精度低,且不够优雅。

Babel玩的熟的,会使用 babel 解析代码成 ast,修改 ast, 最后 generate 代码,再写入文件。

ts-morph是一个新增/修改 typescript 代码的库,相比 babel 修改 ts 代码, 更简单,更易使用。

我使用了 ts-morph 修改 app.config.ts 和生成 routerService.ts。

下面的配置,是我们项目目前在使用的部分配置,嫌麻烦的,可以直接到这里下载 demo,不想安装这几个包的,可以参考modifyAppConfiggenerateRouterService 代码实现,改一改之后,编译成 js 代码,直接在监听文件变更的回调函数中使用即可。

generated

这是一个代码生成管理工具。代码很简单,它注册了一个 generated 命令,读取插件配置文件夹的配置供插件使用。我们的功能需要通过插件实现,安装该工具后进行下列配置。

1、在根目录新建 generated 配置文件 .generatedrc.ts

2、注册插件

import { GeneratedrcConfig } from 'generated'

const generatedrc: GeneratedrcConfig = {
  configDir: './gconfig', // generated 插件配置目录
  plugins: [
    'generated-plugin-taro-router-service'  // 注册插件
  ],
}

export default generatedrc

generated-plugin-taro-router-service

在这个插件中,实现了修改代码和生成routerService文件。

需要进行下列配置

1、在根目录新建 gconfig 文件夹,文件夹下新建 router.ts 配置文件.

2、写入配置

import { Config } from 'generated-plugin-taro-router-service'

const basePath = process.cwd()

export const taroRouter: Config = {
  // 源码目录
  pageDir: basePath + '/src',
  
  // app.config 路径
  appConfigPath: basePath + '/src/app.config.ts',

  // project.config.json 路径
  projectConfigPath: basePath + '/project.config.json',

  // 输出文件名
  outputFileName: 'routerService',

  /**
   * 导入组件
   * 
   * 输出的文件将导入方法
   * import { customNavigateTo } from '@/business/app'
  */
  navigateFnName: 'customNavigateTo', // 导入方法名
  navigateSpecifier: '@/business/app', // 方法导入标识符
  
  /**
   * 格式化文件名
   * 页面文件名可能会出现类似 edit-name 的写法,这种 name 无法作为类属性,所以需要 formatter 函数格式化
  */
  formatter(name) {
	return (name.split('-') || []).reduce((t, c) => t + upFirst(c), '')
  }
}

工具内部没有直接使用taro 原生的 navigateTo 方法,而是需要手动配置方法。一是因为 taro 导出的路由 API 并不好用,二是 API 封装在内部,自定义程度不够高。

shelljs 进行脚本调用

在文件监听的回调函数中,利用 shelljs 执行 generated 命令即可。

其他

本文提到的几个仓库如下: