Skip to content

Commit eb68c9b

Browse files
committed
docs: 更新安装流程与 API 迁移说明
1 parent 4a30321 commit eb68c9b

File tree

2 files changed

+190
-198
lines changed

2 files changed

+190
-198
lines changed

README.md

Lines changed: 95 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,143 @@
11
# vue-router-plugin-system
22

3-
A lightweight solution providing standardized plugin system for Vue Router.
3+
Standardized plugin system and unified installation mechanism for Vue Router.
44

55
[中文文档](./README.zh_CN.md)
66

77
---
88

9-
## 🌟 Core Features
10-
11-
| Feature | Description |
12-
| -------------------------------------- | -------------------------------------------------------------------------------- |
13-
| 🧱 **Standardized Plugin Interface** | Unified plugin development specification with auto-registration/uninstallation |
14-
| 🔁 **Reactive Side-effect Management** | Automatic tracking/cleanup of plugin's reactive side-effects |
15-
| ⚖️ **Dual-mode Compatibility** | Supports both Vue Router plugin system and Vue plugin system compatibility modes |
16-
17-
---
18-
199
## 📦 Installation
2010

2111
```bash
22-
npm install vue-router-plugin-system
12+
npm i vue-router-plugin-system
2313
```
2414

2515
---
2616

27-
## 🚀 Getting Started
17+
## 🧩 Two integration approaches
2818

29-
### Mode 1: Vue Router Plugin Mode (Recommended)
19+
### Approach 1: As a “pre-installed dependency” (centrally installed by the application)
3020

31-
**1. Plugin Development**
21+
- Suitable for: registering all router plugins on the application side, ensuring each is installed only once and shares the same internal mechanism.
22+
- Plugin side
23+
- Only export the implementation of `RouterPlugin`; no need to implement an installation mechanism
24+
- Declare this package in `peerDependencies`
25+
- Application side: two ways to perform centralized installation
26+
1. The application uses this package’s `createRouter`
3227

33-
```ts
34-
import type { RouterPlugin } from 'vue-router-plugin-system'
35-
import { ref } from 'vue'
28+
```ts
29+
import { BarPlugin, FooPlugin } from 'some-libs'
30+
import { createWebHistory } from 'vue-router'
31+
import { createRouter } from 'vue-router-plugin-system'
3632

37-
export const NavigationStatePlugin: RouterPlugin = (ctx) => {
38-
// Extend reactive navigation state
39-
ctx.router.isNavigating = ref(false)
33+
const router = createRouter({
34+
history: createWebHistory(),
35+
routes: [],
36+
plugins: [FooPlugin, BarPlugin],
37+
})
38+
```
4039

41-
// Register navigation guards
42-
ctx.router.beforeEach(() => {
43-
ctx.router.isNavigating.value = true
44-
})
45-
ctx.router.afterEach(() => {
46-
ctx.router.isNavigating.value = false
47-
})
40+
2. Use `withInstall` for installation adaptation
4841

49-
// Uninstall hook
50-
ctx.onUninstall(() => {
51-
ctx.router.isNavigating.value = false
52-
})
53-
}
54-
```
42+
```ts
43+
import { BarPlugin, FooPlugin } from 'some-libs'
44+
import { withInstall } from 'vue-router-plugin-system'
5545
56-
**2. Application Integration**
46+
const Foo = withInstall(FooPlugin)
47+
const Bar = withInstall(BarPlugin)
5748
58-
```ts
59-
import { createWebHistory } from 'vue-router'
60-
import { createRouter } from 'vue-router-plugin-system'
61-
import { NavigationStatePlugin } from './plugins'
62-
63-
const router = createRouter({
64-
history: createWebHistory(),
65-
routes: [],
66-
plugins: [NavigationStatePlugin],
67-
})
68-
69-
// Access extended property
70-
router.isNavigating.value
71-
```
49+
// Option A: install directly onto the router (can be called before app.use(router); runWithApp will be deferred)
50+
Foo.install(router)
51+
Bar.install(router)
7252
73-
### Mode 2: Vue Plugin Mode (Compatibility)
53+
// Option B: register as a Vue plugin (must call app.use(router) before app.use(Foo/Bar))
54+
app.use(router)
55+
app.use(Foo).use(Bar)
56+
```
7457

75-
**1. Plugin Development**
58+
### Approach 2: As adev dependency” (installed by the app via Vues plugin system)
7659

77-
```ts
78-
import type { RouterPlugin } from 'vue-router-plugin-system'
79-
import { ref } from 'vue'
60+
- Suitable for: exposing the plugin directly as a Vue plugin (the app only needs `app.use(plugin)`).
61+
- Plugin side
62+
- Add this package as a dev dependency, wrap the plugin with `withInstall`, and bundle it together with your build output (`dist`)
63+
- Export the wrapped plugin object
8064

81-
export const NavigationStatePlugin: RouterPlugin = (ctx) => {
82-
// Implementation logic remains the same
83-
}
84-
```
65+
```ts
66+
import { withInstall } from 'vue-router-plugin-system'
8567
86-
**2. Application Integration**
68+
export const MyPlugin = withInstall((ctx) => {
69+
// Plugin implementation
70+
})
71+
```
8772

88-
```ts
89-
// main.ts
90-
import { asVuePlugin } from 'vue-router-plugin-system'
73+
- Application side
9174

92-
const app = createApp(App)
93-
app.use(router) // Mount router first
94-
app.use(asVuePlugin(NavigationStatePlugin)) // Register plugin later
95-
```
75+
```ts
76+
// Option A: install directly onto the router (can be called before app.use(router); runWithApp will be deferred)
77+
MyPlugin.install(router)
9678
97-
---
79+
// Option B: register as a Vue plugin (must call app.use(router) before app.use(MyPlugin))
80+
app.use(router)
81+
app.use(MyPlugin)
82+
```
9883

99-
## ⚠️ Mode Comparison
84+
---
10085

101-
| Feature | Vue Router Plugin Mode | Vue Plugin Mode |
102-
| -------------------- | -------------------------- | ----------------------------- |
103-
| Initialization Order | Prioritized over app logic | Depends on client usage order |
104-
| Guard Priority | Higher priority | Depends on registration order |
105-
| Reactive Management | Auto-cleanup | Auto-cleanup |
86+
## 🔍 Detailed API and runtime model
10687

107-
---
88+
### RouterPlugin
10889

109-
## 📚 Type Definitions
90+
Each plugin is invoked once during the applications lifetime and receives the context object:
11091

11192
```ts
11293
interface RouterPluginContext {
113-
/**
114-
* Vue Router instance
115-
*/
11694
router: Router
117-
/**
118-
* Execute callback with Vue app instance
119-
*/
120-
runWithApp: (handler: RouterPluginRunWithAppHandler) => void
121-
/**
122-
* Register uninstallation callback (supports multiple calls)
123-
*/
124-
onUninstall: (handler: RouterPluginUninstallHandler) => void
95+
runWithApp: (handler: (app: App) => void) => void
96+
onUninstall: (handler: () => void) => void
12597
}
12698
127-
interface RouterPlugin {
128-
/**
129-
* Plugin initialization function
130-
*/
131-
(ctx: RouterPluginContext): void
132-
}
99+
type RouterPlugin = (ctx: RouterPluginContext) => void
133100
```
134101

135-
---
102+
### EffectScope and cleanup
103+
104+
- All plugins on the same Router instance run within a shared `effectScope` (maintained by this library).
105+
- When `app.unmount()` is called, the `effectScope` is first stopped, then all `onUninstall` handlers are invoked in registration order, and the internal queue is cleared.
106+
- This ensures reactive side effects created by plugins (`watch`, `computed`, etc.) are cleaned up reliably.
107+
108+
### `runWithApp(handler)`
109+
110+
- Use when the plugin needs access to the Vue App instance (e.g. `provide/inject`, global config).
111+
- Behavior:
112+
- If the `router` has already been installed into the `app`, the `handler` executes immediately (inside the `effectScope`).
113+
- If not yet installed, it is queued and flushed in registration order after `app.use(router)`.
114+
115+
### `onUninstall(handler)`
116+
117+
- Register one-off cleanup logic to run when the application is unmounted.
118+
- Note: Since the `effectScope` has been stopped before `onUninstall` runs, reactive effects will no longer trigger during cleanup; release non-reactive resources here (timers, subscriptions, DOM, etc.).
119+
120+
### `createRouter(options)`
121+
122+
- Equivalent to `vue-router`s `createRouter`, with an extra `options.plugins: RouterPlugin[]` to register plugins at creation time.
123+
- Installation order follows the array order; corresponding `runWithApp` handlers are flushed in the same order after `app.use(router)`.
124+
125+
### `withInstall(plugin)`
136126

137-
## 🤝 Contribution Guide
127+
- Wraps a `RouterPlugin` so it supports both installation modes:
128+
- Via Vues plugin system: `app.use(Plugin)` (the `router` must be installed first)
129+
- Install directly onto the Router: `Plugin.install(router)` (can be called before or after `app.use(router)`)
130+
- Details:
131+
- Calling `app.use(Plugin)` before the `router` is installed will throw an error
132+
- The internal wrapping of `router.install` is idempotent: each Router is wrapped only once
138133

139-
Contributions are welcome! Please ensure:
134+
### Installation order and idempotency
140135

141-
1. All unit tests pass
142-
2. TypeScript type integrity maintained
143-
3. Necessary documentation added
136+
- Plugins initialize in registration order.
137+
- `runWithApp` handlers are flushed in registration order after `app.use(router)`.
138+
- Each Router instances `install` will only be wrapped once.
139+
- This library does not de-duplicate multiple registrations of the same pluginif you need deduplication, enforce it at the call site.
144140

145141
## License
146142

147-
[MIT](./LICENSE) License © 2025 [leihaohao](https://github.com/l246804)
143+
[MIT](./LICENSE) © 2025 [leihaohao](https://github.com/l246804)

0 commit comments

Comments
 (0)