@sagaroute/react
v0.0.3
Published
A conventional routing plugin for generating routes that suitable for React Router@6+
Downloads
3
Maintainers
Readme
@sagaroute/react
一款根据约定式路由规则生成路由列表的插件,生成的路由列表可直接用于react-router@6+
中
快速上手
1. 安装
npm install @sagaroute/react
2. 在路由模板文件中用注释做标记注入
路由模板文件是指要被注入路由列表的文件,我们需要通过注释来指明路由模板文件中哪个位置被注入路由列表和依赖
例如存在路由模板文件,其内容如下:
import React from 'react';
const routes = [];
const router = createBrowserRouter(routes);
export default router;
我们需要对上述文件用注释进行标记,标记后如下所示:
import React from 'react';
import { createBrowserRouter } from 'react-router-dom';
/* sagaroute-inject:imports */
/* sagaroute-inject:routes */
const routes = [];
const router = createBrowserRouter(routes);
export default router;
其中/* sagaroute-inject:imports */
用于标记依赖注入的位置,/* sagaroute-inject:routes */
用于标记路由列表注入的位置。关于这些注释的含义和路由模板文件的更多说明可看此处
3. 生成且注入路由
在项目目录中运行以下代码:
import SagaRoute from '@sagaroute/react';
const sagaRoute = new SagaRoute({
// 指定页面文件目录,默认为src/pages
dirpath: 'src/views',
// 指定路由模板文件,默认为src/routes.tsx
routeFilePath: 'src/router/index.jsx',
});
// 调用routing后,sagaroute会扫描页面文件目录且生成路由列表,把路由列表注入到路由文件中
sagaRoute.routing();
运行成功后,"src/router/index.js"
文件的内容如下所示:
import React from 'react';
import { createBrowserRouter } from 'react-router-dom';
/* sagaroute-inject:imports */
/* injected by sagaroute: start */
import PagesIndex from '../pages/index.jsx';
/* injected by sagaroute: end */
/* sagaroute-inject:routes */
const routes = [
{
path: '/',
element: <PagesIndex />,
},
];
const router = createBrowserRouter(routes);
export default router;
约定式路由规则
本插件的约定式路由规则的设计主要参考umi
和next
,关于路由规则的详细可看约定式路由规则
配置介绍
可以在初始化@sagaroute/react
实例时,传入配置项,如下所示:
import SagaRoute from '@sagaroute/react';
const sagaroute = new Sagaroute({
dirpath: 'src/views',
});
配置项类型如下所示:
interface RoutingOption {
rootPath?: string;
dirpath?: string;
layoutDirPath?: string;
routeFilePath?: string;
lazy?: boolean | LazyFn;
pathRewrite?: Record<string, string>;
onWarning?: (message: string) => void;
hooks?: {
build?: {
before?: Handler<HookBeforeBuild>;
after?: Handler<HookAfterBuild>;
};
gather?: {
before?: Handler<GatherHookBefore>;
beforeEach?: Handler<GatherHookBeforeEach>;
afterEach?: Handler<GatherHookAfterEach>;
after?: Handler<GatherHookAfter>;
};
weave?: {
before?: Handler<WeaveHookBefore>;
beforeEach?: Handler<WeaveHookBeforeEach>;
afterEach?: Handler<WeaveHookAfterEach>;
after?: Handler<WeaveHookAfter>;
};
print?: {
parse?: {
before?: Handler<PrintHookBeforeParse>;
after?: Handler<PrintHookAfterParse>;
};
inject?: {
before?: Handler<PrintHookBeforeInject>;
after?: Handler<PrintHookAfterInject>;
};
write?: {
before?: Handler<PrintHookBeforeWrite>;
after?: Handler<PrintHookAfterWrite>;
};
};
};
}
配置项中所有参数的简要说明如下所示:
| 名称 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | dirpath | 页面文件目录路径 | string | 'src/pages' | | layoutDirPath | 全局路由目录路径 | string | 'src/layouts' | | routeFilePath | 指定路由模板文件的路径 | string | 'src/route.tsx' | | lazy | 路由是否懒加载 | boolean/Function(string): boolean | false | | hooks | 执行周期的钩子函数 | object | -- | | pathRewrite | 用于对 import 语句的路径进行替换 | Object{string: string} | -- | | rootPath | 项目路径 | string | process.cwd() | | onWarning | 触发警告时的回调函数 | function(message: string): void | -- |
对上述配置参数中更详细的说明可看API
配置文件
支持往项目中添加sagaroute.config.js
或sagaroute.config.cjs
作为配置文件,在文件中以CommonJS
的格式编写和导出部分上述配置项,例如:
/** @type {import('@sagaroute/react').RoutingOption} */
module.exports = {
lazy: function (filepath) {
return filepath.includes('charts');
},
};
深入原理: 三个阶段
@sagaroute/react
从生成路由列表到将其插入到路由模板文件的整个过程中需要经历三个的执行阶段,分别是gather
、weave
和print
,其分布图如下所示:
gather
gather
阶段会遍历路由文件目录下的所有文件,根据约定式路由规则过滤出符合条件的文件,并把每个符合条件的 文件对象(即包括文件和文件夹) 转换成FileNode
节点,最后组成FileNodes
列表
FileNode
的类型如下所示:
interface FileNode {
name: string;
children?: FileNode[];
type: 'dir' | 'file';
layoutNode?: boolean;
props?: {
routeProps?: Record<string, any>;
routeOptions?: {
layout?: boolean;
[key: string]: any;
};
};
path: string;
dependencies?: Dependency[];
}
参数解释:
name
: 节点对应的文件对象名称children
: 如果节点对应文件夹,则children
为该文件夹下的文件对象转换后的节点列表type
:dir
代表文件对象为文件夹,file
代表文件对象为文件layoutNode
: 代表文件对象是否为全局路由文件props
: 包含文件中导出的与路由相关的两个属性routeProps和routeOptionspath
: 文件对象的绝对路径dependencies
:props
中包含的属性所附带的依赖
weave
weave
阶段会遍历gather
生成的FileNode
数组,根据react-router
的规则Routes
生成路由列表和Routes
的依赖集合Imports
Routes
的类型等同于react-router
的RouteObject
类型,如下所示:
interface RouteObject {
path?: string;
index?: boolean;
children?: React.ReactNode;
caseSensitive?: boolean;
id?: string;
loader?: LoaderFunction;
action?: ActionFunction;
element?: React.ReactNode | null;
Component?: React.ComponentType | null;
errorElement?: React.ReactNode | null;
ErrorBoundary?: React.ComponentType | null;
handle?: RouteObject['handle'];
shouldRevalidate?: ShouldRevalidateFunction;
lazy?: LazyRouteFunction<RouteObject>;
}
print
阶段会把weave
生成的Routes
和Imports
作为模板变量插入到路由模板文件对应的位置上,从而完成注册路由从扫描、生成到覆写的过程。关于路由模板文件的解释可看此处
钩子函数
gather
、weave
、print
三个阶段都可以注册钩子函数去调整整个路由列表生成的过程,利用这些钩子函数,可以实现以下场景需求:
更多详细可看钩子函数