Skip to content

Commit 8219d74

Browse files
committed
refactor(router): 重构路由处理逻辑和类型定义
- 将 `onOpen` 和 `onServerLocation` 合并为统一的 `location` 和 `serverLocation` 处理钩子 - 重构路由创建和任务处理流程,简化 `createRoute` 和 `createRouteTask` 实现 - 统一路由钩子类型定义,增加 `RouteHandleResult` 类型支持 - 优化路由参数处理逻辑,修复同源路由匹配问题
1 parent 6763ed9 commit 8219d74

File tree

5 files changed

+128
-142
lines changed

5 files changed

+128
-142
lines changed

packages/router/src/next/default.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import type { Route } from './types';
22

3-
export function DEFAULT_ON_OPEN(route: Route) {
3+
export function DEFAULT_ON_OPEN(to: Route, from: Route | null) {
44
try {
5-
const newWindow = window.open(route.url.href);
5+
const newWindow = window.open(to.url.href);
66
if (!newWindow) {
7-
location.href = route.url.href;
7+
location.href = to.url.href;
88
} else {
99
newWindow.opener = null; // 解除新窗口与当前窗口的关系
1010
}
1111
} catch (e) {
12-
location.href = route.url.href;
12+
location.href = to.url.href;
1313
}
1414
}

packages/router/src/next/options.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,11 @@ export function parsedOptions(options: RouterOptions): RouterParsedOptions {
2929
apps: options.apps ?? {},
3030
matcher: createMatcher(routes),
3131
normalizeURL: options.normalizeURL ?? ((url) => url),
32-
onOpen: (route: Route) => {
33-
if (isBrowser) {
34-
const result = options.onOpen?.(route);
35-
if (result !== false) {
36-
DEFAULT_ON_OPEN(route);
37-
}
38-
}
39-
return true;
32+
location: (to, from) => {
33+
return null;
4034
},
41-
onServerLocation(route) {
42-
return true;
35+
serverLocation(route) {
36+
return null;
4337
}
4438
};
4539
return result;

packages/router/src/next/route.ts

Lines changed: 54 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,133 +2,114 @@ import { parseLocation } from './location';
22
import type {
33
Awaitable,
44
Route,
5+
RouteHandleResult,
56
RouteLocationRaw,
6-
RouteMatchResult,
77
RouteType,
88
RouterParsedOptions
99
} from './types';
1010

11-
export function parseRoute(
11+
export function createRoute(
1212
navigationType: RouteType,
13+
toRaw: RouteLocationRaw,
1314
options: RouterParsedOptions,
14-
raw: RouteLocationRaw
15+
from: URL | null
1516
): Route {
1617
const { base, normalizeURL } = options;
17-
const loc = normalizeURL(parseLocation(raw, base), raw);
18-
// 处理外站逻辑
19-
if (loc.origin !== base.origin) {
20-
return createRoute(navigationType, raw, loc, base);
21-
}
22-
if (loc.pathname.length < base.pathname.length) {
23-
return createRoute(navigationType, raw, loc, base);
24-
}
25-
// 匹配路由
26-
const matched = options.matcher(loc, base);
27-
// 没有匹配任何路由
28-
if (matched.matches.length === 0) {
29-
return createRoute(navigationType, raw, loc, base);
30-
}
31-
// 重新构造 URL 参数
32-
const lastMatch = matched.matches[matched.matches.length - 1];
33-
if (typeof raw === 'object' && raw.params) {
34-
const current = loc.pathname.split('/');
35-
const next = new URL(
36-
lastMatch.compile(raw.params).substring(1),
37-
base
38-
).pathname.split('/');
39-
next.forEach((item, index) => {
40-
current[index] = item || current[index];
41-
});
42-
loc.pathname = current.join('/');
43-
Object.assign(matched.params, raw.params);
44-
}
45-
return createRoute(navigationType, raw, loc, base, matched);
46-
}
47-
48-
export function createRoute(
49-
navigationType: RouteType,
50-
raw: RouteLocationRaw,
51-
loc: URL,
52-
base: URL,
53-
match?: RouteMatchResult
54-
): Route {
18+
const to = normalizeURL(parseLocation(toRaw, base), from);
19+
const isSameOrigin = to.origin === base.origin;
20+
const isSameBase = to.pathname.length >= base.pathname.length;
21+
const match = isSameOrigin && isSameBase ? options.matcher(to, base) : null;
5522
const route: Route = {
23+
handleResult: null,
24+
req: null,
25+
res: null,
5626
type: navigationType,
57-
url: loc,
27+
url: to,
5828
params: {},
5929
query: {},
6030
queryArray: {},
61-
state: typeof raw === 'object' && raw.state ? raw.state : {},
31+
state: typeof toRaw === 'object' && toRaw.state ? toRaw.state : {},
6232
meta: {},
63-
path: loc.pathname,
64-
fullPath: loc.pathname + loc.search + loc.hash,
33+
path: to.pathname,
34+
fullPath: to.pathname + to.search + to.hash,
6535
matched: [],
6636
config: null
6737
};
6838

69-
for (const key of loc.searchParams.keys()) {
70-
const values = loc.searchParams.getAll(key);
39+
for (const key of to.searchParams.keys()) {
40+
const values = to.searchParams.getAll(key);
7141
route.query[key] = values[0] || '';
7242
route.queryArray[key] = values;
7343
}
7444
if (match) {
7545
route.config = match.matches[match.matches.length - 1];
7646
route.meta = route.config.meta || {};
77-
route.path = loc.pathname.substring(base.pathname.length - 1);
78-
route.fullPath = `${route.path}${loc.search}${loc.hash}`;
47+
route.path = to.pathname.substring(options.base.pathname.length - 1);
48+
route.fullPath = `${route.path}${to.search}${to.hash}`;
7949
route.matched = match.matches;
50+
if (typeof toRaw === 'object' && toRaw.params) {
51+
const lastMatch = match.matches[match.matches.length - 1];
52+
const current = to.pathname.split('/');
53+
const next = new URL(
54+
lastMatch.compile(toRaw.params).substring(1),
55+
options.base
56+
).pathname.split('/');
57+
next.forEach((item, index) => {
58+
current[index] = item || current[index];
59+
});
60+
to.pathname = current.join('/');
61+
Object.assign(match.params, toRaw.params);
62+
}
8063
}
8164
return route;
8265
}
8366

84-
export function createRouteTask(opts: RouteTaskOptions) {
67+
export async function createRouteTask(opts: RouteTaskOptions) {
8568
let finish = false;
86-
const ctx = {
87-
navigationType: opts.navigationType,
88-
to: parseRoute(opts.navigationType, opts.options, opts.to),
69+
const ctx: RouteTaskContext = {
70+
to: createRoute(
71+
opts.navigationType,
72+
opts.toRaw,
73+
opts.options,
74+
opts.from?.url ?? null
75+
),
8976
from: opts.from,
9077
options: opts.options,
91-
finish() {
78+
finish(result: RouteHandleResult = null) {
79+
this.to.handleResult =
80+
result && typeof result === 'object' ? result : null;
9281
finish = true;
9382
},
9483
async redirect(to: RouteLocationRaw) {
9584
finish = true;
9685
this.to = await createRouteTask({
9786
...opts,
98-
to
99-
}).run();
87+
toRaw: to
88+
});
10089
}
10190
};
10291
const list: Array<RouteTask> = [];
103-
return {
104-
add(...items: RouteTask[]) {
105-
list.push(...items);
106-
return this;
107-
},
108-
async run() {
109-
for (const item of list) {
110-
await item.task(ctx);
111-
if (finish) {
112-
break;
113-
}
114-
}
115-
return ctx.to;
92+
for (const item of list) {
93+
await item.task(ctx);
94+
if (finish) {
95+
break;
11696
}
117-
};
97+
}
98+
return ctx.to;
11899
}
119100

120101
export interface RouteTaskOptions {
121102
navigationType: RouteType;
122-
to: RouteLocationRaw;
103+
toRaw: RouteLocationRaw;
123104
from: Route | null;
124105
options: RouterParsedOptions;
106+
tasks: RouteTask[];
125107
}
126108
export interface RouteTaskContext {
127-
navigationType: RouteType;
128109
to: Route;
129110
from: Route | null;
130111
options: RouterParsedOptions;
131-
finish: () => void;
112+
finish: (result?: RouteHandleResult) => void;
132113
redirect: (to: RouteLocationRaw) => Promise<void>;
133114
}
134115

packages/router/src/next/router.ts

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import {
55
type RouteTask,
66
type RouteTaskCallback,
77
type RouteTaskContext,
8-
createRouteTask,
9-
parseRoute
8+
createRoute,
9+
createRouteTask
1010
} from './route';
1111
import { RouteType } from './types';
1212
import type {
1313
Route,
14-
RouteEnvHandle,
14+
RouteHandleHook,
1515
RouteLocationRaw,
1616
RouteState,
1717
RouterOptions,
@@ -37,7 +37,7 @@ export class Router {
3737
private _tasks = {
3838
[TaskType.outside]: (ctx: RouteTaskContext) => {
3939
if (ctx.to.matched.length === 0) {
40-
ctx.options.onOpen(ctx.to);
40+
ctx.options.location(ctx.to, ctx.from);
4141
return ctx.finish();
4242
}
4343
},
@@ -46,20 +46,22 @@ export class Router {
4646
if (!to.config || !to.config.env) {
4747
return;
4848
}
49-
let envBridge: RouteEnvHandle | null = null;
49+
let routeHandle: RouteHandleHook | null = null;
5050
if (typeof to.config.env === 'function') {
51-
envBridge = to.config.env;
51+
routeHandle = to.config.env;
5252
} else if (typeof to.config.env === 'object') {
5353
const { require, handle } = to.config.env;
54-
if (typeof require === 'function' && require(to)) {
55-
envBridge = handle || null;
54+
if (
55+
typeof require === 'function' &&
56+
require(ctx.to, ctx.from)
57+
) {
58+
routeHandle = handle || null;
5659
} else {
57-
envBridge = handle || null;
60+
routeHandle = handle || null;
5861
}
5962
}
60-
if (envBridge) {
61-
envBridge(to);
62-
ctx.finish();
63+
if (routeHandle) {
64+
ctx.finish(await routeHandle(ctx.to, ctx.from));
6365
}
6466
},
6567
[TaskType.asyncComponent]: async (ctx: RouteTaskContext) => {
@@ -83,17 +85,14 @@ export class Router {
8385
},
8486
[TaskType.applyApp]: (ctx: RouteTaskContext) => {
8587
this._route = ctx.to;
86-
this._microApp._update(
87-
this,
88-
ctx.navigationType === RouteType.reload
89-
);
88+
this._microApp._update(this, ctx.to.type === RouteType.reload);
9089
},
9190
[TaskType.applyNavigation]: (ctx: RouteTaskContext) => {
9291
this._navigation.push(ctx.to);
9392
ctx.finish();
9493
},
9594
[TaskType.applyWindow]: (ctx: RouteTaskContext) => {
96-
ctx.options.onOpen(ctx.to);
95+
ctx.options.location(ctx.to, ctx.from);
9796
ctx.finish();
9897
}
9998
} satisfies Record<string, RouteTaskCallback>;
@@ -148,28 +147,28 @@ export class Router {
148147
}
149148
);
150149
}
151-
public push(location: RouteLocationRaw): Promise<Route> {
152-
return this._transitionTo(RouteType.push, location);
150+
public push(toRaw: RouteLocationRaw): Promise<Route> {
151+
return this._transitionTo(RouteType.push, toRaw);
153152
}
154-
public replace(location: RouteLocationRaw) {
155-
return this._transitionTo(RouteType.replace, location);
153+
public replace(toRaw: RouteLocationRaw) {
154+
return this._transitionTo(RouteType.replace, toRaw);
156155
}
157-
public openWindow(location?: RouteLocationRaw): Promise<Route> {
156+
public openWindow(toRaw?: RouteLocationRaw): Promise<Route> {
158157
return this._transitionTo(
159158
RouteType.openWindow,
160-
location ?? this.route.url.href
159+
toRaw ?? this.route.url.href
161160
);
162161
}
163-
public replaceWindow(location?: RouteLocationRaw): Promise<Route> {
162+
public replaceWindow(toRaw?: RouteLocationRaw): Promise<Route> {
164163
return this._transitionTo(
165164
RouteType.replaceWindow,
166-
location ?? this.route.url.href
165+
toRaw ?? this.route.url.href
167166
);
168167
}
169-
public reload(location?: RouteLocationRaw): Promise<Route> {
168+
public reload(toRaw?: RouteLocationRaw): Promise<Route> {
170169
return this._transitionTo(
171170
RouteType.reload,
172-
location ?? this.route.url.href
171+
toRaw ?? this.route.url.href
173172
);
174173
}
175174
public async back(): Promise<Route | null> {
@@ -208,28 +207,32 @@ export class Router {
208207
state: result.state
209208
});
210209
}
211-
public resolve(loc: RouteLocationRaw): Route {
212-
return parseRoute(RouteType.resolve, this.options, loc);
210+
public resolve(toRaw: RouteLocationRaw): Route {
211+
return createRoute(
212+
RouteType.resolve,
213+
toRaw,
214+
this.options,
215+
this._route?.url ?? null
216+
);
213217
}
214218

215-
public pushLayer(loc: RouteLocationRaw) {}
216-
private _transitionTo(navigationType: RouteType, to: RouteLocationRaw) {
219+
public pushLayer(toRaw: RouteLocationRaw) {}
220+
private _transitionTo(navigationType: RouteType, toRaw: RouteLocationRaw) {
217221
const names: string[] = this._taskMaps[navigationType] ?? [];
218222
const { _tasks } = this;
219-
const tasks = names.map((name) => {
223+
const tasks: RouteTask[] = names.map((name) => {
220224
return {
221225
name,
222226
task: _tasks[name]
223227
} satisfies RouteTask;
224228
});
225229
return createRouteTask({
226230
navigationType,
227-
to,
231+
toRaw,
228232
from: this._route,
229-
options: this.options
230-
})
231-
.add(...tasks)
232-
.run();
233+
options: this.options,
234+
tasks
235+
});
233236
}
234237
public async renderToString(throwError = false): Promise<string | null> {
235238
try {

0 commit comments

Comments
 (0)