npm package: @leejung/hvigor-nav-router-plugin
Description: Hvigor build plugin for @leejung/nav-router - auto-generates route_map.json from @NavRoute annotations
Author: leejung
Latest version: 1.0.0

# @leejung/hvigor-nav-router-plugin

`@leejung/nav-router` 的 hvigor 构建插件。

它负责在构建阶段自动扫描页面和弹窗入口，生成 `route_map.json`，并把模块的 `module.json5` 自动补齐 `routerMap` 配置，避免继续手工维护路由表。

## 解决的问题

从 `HMRouter` 迁移到 `Navigation + route_map.json` 后，项目会多出两类重复劳动：

1. 每个模块都要维护自己的 `src/main/resources/base/profile/route_map.json`
2. 每个模块都要在 `module.json5` 里补 `routerMap: "$profile:route_map"`

这个插件把这两件事放进 hvigor 构建流程里自动完成。

## 当前仓库的推荐约定

当前仓库的主约定是：

1. 路由名统一定义在 `features/appcommon/src/main/ets/constants/PageConstants.ets`
2. 页面文件只保留 `@Builder export function XxxBuilder()`
3. 不再在页面文件里额外维护路由装饰器或独立常量

示例：

```typescript
// features/appcommon/src/main/ets/constants/PageConstants.ets
export class PageConstants {
  public static readonly Home = 'page://HomePage'
  public static readonly StopServerNoticeDialog = 'dialog://StopServerNoticeDialog'
}
```

```typescript
// features/home/src/main/ets/pages/HomePage.ets
@Builder
export function HomePageBuilder() {
  HomePage()
}
```

插件会优先按 `Builder` 名去中央 `PageConstants` 中查找路由名。

## 插件做了什么

每次构建时，插件会：

1. 扫描模块下的 `src/main/ets/pages` 和 `src/main/ets/dialogs`
2. 找出带 `@Builder export function XxxBuilder()` 的 `.ets` 文件
3. 解析对应路由名
4. 生成或更新 `src/main/resources/base/profile/route_map.json`
5. 向 `module.json5` 注入 `"routerMap": "$profile:route_map"`

## 路由名解析优先级

主路径是中央 `PageConstants`，但为了兼容迁移过程，扫描器还保留了兜底能力。

优先级从高到低：

1. `@NavRoute({ url: ... })` 装饰器
2. `// @NavRoute({ url: '...' })` 注释
3. `export const NAV_ROUTE_NAME = ...`
4. 中央 `PageConstants` 映射
5. 按目录和文件名兜底推导

文件名兜底规则：

- `src/main/ets/pages/HomePage.ets` -> `page://HomePage`
- `src/main/ets/dialogs/StopServerNotice.ets` -> `dialog://StopServerNotice`

## 目录要求

默认扫描目录：

```text
src/main/ets/pages
src/main/ets/dialogs
```

默认输出文件：

```text
src/main/resources/base/profile/route_map.json
```

页面文件必须满足这个条件才会被识别成路由入口：

```typescript
@Builder
export function XxxBuilder() {
  XxxPage()
}
```

如果没有 `@Builder export function XxxBuilder()`，插件会直接跳过该文件。

## 在项目里的接入方式

当前仓库不是通过 npm 包名引用，而是直接在 `hvigorfile.ts` 中引用本地源码：

HAP 模块：

```typescript
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { navRouterHapPlugin } from '../libs/hvigor-nav-router-plugin/src/index';

export default {
  system: hapTasks,
  plugins: [navRouterHapPlugin()]
}
```

HAR 模块：

```typescript
import { harTasks } from '@ohos/hvigor-ohos-plugin';
import { navRouterHarPlugin } from '../../libs/hvigor-nav-router-plugin/src/index';

export default {
  system: harTasks,
  plugins: [navRouterHarPlugin()]
}
```

当前仓库里的接入点包括：

- `entry/hvigorfile.ts`
- `features/appcommon/hvigorfile.ts`
- `features/home/hvigorfile.ts`
- `features/login/hvigorfile.ts`
- `features/search/hvigorfile.ts`
- `features/cartype/hvigorfile.ts`
- `features/trip/hvigorfile.ts`
- `features/mine/hvigorfile.ts`

## 插件 API

### `navRouterHapPlugin(config?)`

给 HAP 模块使用。

### `navRouterHarPlugin(config?)`

给 HAR 模块使用。

### `PluginConfig`

```typescript
interface PluginConfig {
  scanDirs?: string[]
  routeMapPath?: string
}
```

字段说明：

- `scanDirs`: 自定义扫描目录，默认是 `pages + dialogs`
- `routeMapPath`: 自定义输出文件路径，默认是 `src/main/resources/base/profile/route_map.json`

示例：

```typescript
navRouterHarPlugin({
  scanDirs: [
    'src/main/ets/pages',
    'src/main/ets/dialogs',
    'src/main/ets/sheets'
  ],
  routeMapPath: 'src/main/resources/base/profile/route_map.json'
})
```

## 生成结果示例

```json
{
  "routerMap": [
    {
      "name": "dialog://StopServerNoticeDialog",
      "pageSourceFile": "src/main/ets/dialogs/StopServerNotice.ets",
      "buildFunction": "StopServerNoticeDialogBuilder"
    },
    {
      "name": "page://HomePage",
      "pageSourceFile": "src/main/ets/pages/HomePage.ets",
      "buildFunction": "HomePageBuilder"
    }
  ]
}
```

同时模块的 `module.json5` 会被补成：

```json5
{
  "module": {
    "name": "home",
    "type": "har",
    "routerMap": "$profile:route_map"
  }
}
```

## 与 HMRouter 插件的区别

| 项目 | HMRouter 插件 | 本插件 |
|---|---|---|
| 路由来源 | 运行时黑盒注册 | 构建期静态生成 |
| 路由表 | 框架内部维护 | `route_map.json` 可直接查看 |
| 调试方式 | 主要靠运行时排查 | 可直接核对生成产物 |
| 项目规范 | 常见是页面内分散声明 | 推荐中央 `PageConstants` |

## 调试与排障

### 1. 页面没进 `route_map.json`

优先检查：

1. 文件是否在 `pages/` 或 `dialogs/` 目录下
2. 是否存在顶层 `@Builder export function XxxBuilder()`
3. `PageConstants` 是否有对应路由常量
4. Builder 名和路由名是否能一一对应

### 2. 改了插件源码但构建还在跑旧逻辑

`src/index.ts` 已经在每次取插件实例前主动清理：

- `./plugin`
- `./scanner`
- `./ast-utils`

对应的 `require.cache`。

这样 hvigor daemon 即使复用进程，也会重新加载磁盘上的插件源码。

### 3. 改了 `PageConstants` 但生成结果没更新

扫描器在每次 `scanRouteAnnotations(moduleDir)` 开头都会清理该模块的中央路由缓存，避免 daemon 增量构建拿到过期映射。

### 4. 想强制确认产物

直接检查各模块生成的：

```text
src/main/resources/base/profile/route_map.json
```

## 最小接入清单

给一个新模块接入时，只要做这几步：

1. 在模块 `hvigorfile.ts` 注册插件
2. 在 `PageConstants` 里补路由常量
3. 在页面文件里提供 `@Builder export function XxxBuilder()`
4. 构建一次，确认生成了 `route_map.json`

## 相关文档

- [nav-router README](../nav-router/README.md)