bobe-router 0.0.60 → 0.0.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bobe-router.cjs.js +47 -16
- package/dist/bobe-router.cjs.js.map +1 -1
- package/dist/bobe-router.esm.js +47 -16
- package/dist/bobe-router.esm.js.map +1 -1
- package/dist/index.d.ts +18 -4
- package/dist/index.umd.js +47 -16
- package/dist/index.umd.js.map +1 -1
- package/dist/plugin.cjs.js +241 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.d.ts +12 -0
- package/dist/plugin.esm.js +239 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/ssr-routes.d.ts +2 -0
- package/package.json +14 -2
package/dist/bobe-router.cjs.js
CHANGED
|
@@ -54,6 +54,13 @@ function match(path, map) {
|
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
let GlobalKey = function (GlobalKey) {
|
|
58
|
+
GlobalKey["Routes"] = "__BOBE_INIT_ROUTES__";
|
|
59
|
+
GlobalKey["Menus"] = "__BOBE_INIT_MENUS__";
|
|
60
|
+
GlobalKey["Path"] = "__BOBE_INIT_PATH__";
|
|
61
|
+
return GlobalKey;
|
|
62
|
+
}({});
|
|
63
|
+
|
|
57
64
|
function createRouteRecord(opts = {}) {
|
|
58
65
|
return {
|
|
59
66
|
import: opts.import,
|
|
@@ -72,40 +79,55 @@ class Router extends aoye.Store {
|
|
|
72
79
|
idleSet = new Set();
|
|
73
80
|
maxPreload = 3;
|
|
74
81
|
loadingCount = 0;
|
|
75
|
-
|
|
82
|
+
ready(cb) {
|
|
83
|
+
if (cb) {
|
|
84
|
+
if (this.#inited) {
|
|
85
|
+
cb();
|
|
86
|
+
} else {
|
|
87
|
+
this.#readyQueue.push(cb);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
return new Promise(resolve => this.ready(resolve));
|
|
92
|
+
}
|
|
93
|
+
#inited = false;
|
|
94
|
+
#readyQueue = [];
|
|
95
|
+
constructor(opt) {
|
|
76
96
|
super();
|
|
77
|
-
|
|
78
|
-
|
|
97
|
+
const routes = opt?.routes;
|
|
98
|
+
const initialPath = opt?.initialPath;
|
|
99
|
+
this.routes = routes || globalThis[GlobalKey.Routes] || {};
|
|
100
|
+
const injectedMenus = globalThis[GlobalKey.Menus];
|
|
101
|
+
if (injectedMenus) this.menus = injectedMenus;
|
|
102
|
+
const path = initialPath || globalThis[GlobalKey.Path] || (typeof location !== 'undefined' ? location.pathname : '/');
|
|
103
|
+
this.#init(path);
|
|
79
104
|
}
|
|
80
105
|
async #init(path) {
|
|
81
106
|
this.#initIdleSet();
|
|
82
107
|
const result = match(path, this.routes);
|
|
83
108
|
if (result) {
|
|
84
|
-
await this.#loadComponent(result.path);
|
|
85
109
|
const route = this.routes[result.path];
|
|
110
|
+
if (route?.component) {
|
|
111
|
+
route.status = 'loaded';
|
|
112
|
+
} else {
|
|
113
|
+
await this.#loadComponent(result.path);
|
|
114
|
+
}
|
|
86
115
|
this.active = {
|
|
87
116
|
path,
|
|
88
117
|
params: result.params,
|
|
89
|
-
component: route
|
|
118
|
+
component: route?.component
|
|
90
119
|
};
|
|
91
120
|
}
|
|
92
|
-
if (typeof window !== 'undefined') {
|
|
93
|
-
const preloaded = window.__INIT_ROUTE__?.[path];
|
|
94
|
-
if (preloaded) {
|
|
95
|
-
const route = this.routes[path];
|
|
96
|
-
if (route) {
|
|
97
|
-
route.component = preloaded;
|
|
98
|
-
route.status = 'loaded';
|
|
99
|
-
if (this.active) this.active.component = preloaded;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
121
|
this.stack = [{
|
|
104
122
|
path,
|
|
105
123
|
params: this.active?.params ?? {}
|
|
106
124
|
}];
|
|
107
125
|
this.stackIndex = 0;
|
|
108
126
|
this.#initBrowser();
|
|
127
|
+
this.#inited = true;
|
|
128
|
+
const q = this.#readyQueue;
|
|
129
|
+
this.#readyQueue = [];
|
|
130
|
+
for (const cb of q) cb();
|
|
109
131
|
}
|
|
110
132
|
#initBrowser() {
|
|
111
133
|
if (typeof window === 'undefined') return;
|
|
@@ -187,6 +209,13 @@ class Router extends aoye.Store {
|
|
|
187
209
|
if (id !== this.navId) return;
|
|
188
210
|
target.component = this.routes[target.path]?.component;
|
|
189
211
|
this.active = target;
|
|
212
|
+
const hash = new URL(target.path, location.origin).hash;
|
|
213
|
+
if (hash) {
|
|
214
|
+
const el = document.querySelector(decodeURIComponent(hash));
|
|
215
|
+
if (el) el.scrollIntoView({
|
|
216
|
+
behavior: 'smooth'
|
|
217
|
+
});
|
|
218
|
+
}
|
|
190
219
|
this.#preloadNext();
|
|
191
220
|
}
|
|
192
221
|
async #checkGuard(entry, type) {
|
|
@@ -245,6 +274,7 @@ class Router extends aoye.Store {
|
|
|
245
274
|
if (!link) return;
|
|
246
275
|
const href = link.getAttribute('href');
|
|
247
276
|
if (!href) return;
|
|
277
|
+
if (href.startsWith('#')) return;
|
|
248
278
|
try {
|
|
249
279
|
const url = new URL(href, location.origin);
|
|
250
280
|
if (url.origin !== location.origin) return;
|
|
@@ -259,6 +289,7 @@ class Router extends aoye.Store {
|
|
|
259
289
|
const current = location.pathname + location.search;
|
|
260
290
|
const idx = this.stack.findLastIndex(r => r.path === current);
|
|
261
291
|
if (idx !== -1) {
|
|
292
|
+
if (idx === this.stackIndex) return;
|
|
262
293
|
this.stackIndex = idx;
|
|
263
294
|
const entry = this.stack[idx];
|
|
264
295
|
this.#navigate(entry, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bobe-router.cjs.js","sources":["../src/match.ts","../src/router.ts"],"sourcesContent":["import type { RouteMap, MatchResult } from './type';\n\n/** 编译路径模式为正则:/post/:id → ^\\/post\\/([^/]+)$,捕获名为 id */\nfunction compilePattern(pattern: string): { regex: RegExp; params: string[] } {\n const paramNames: string[] = [];\n const regexStr = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // 转义正则特殊字符\n .replace(/:([a-zA-Z_]\\w*)/g, (_, name) => {\n paramNames.push(name);\n return '([^/]+)';\n });\n return {\n regex: new RegExp(`^${regexStr}$`),\n params: paramNames,\n };\n}\n\n/** 预编译所有路由的正则 */\ntype CompiledRoute = {\n pattern: string;\n regex: RegExp;\n paramNames: string[];\n};\n\nlet compiledCache: CompiledRoute[] | null = null;\nlet cacheKey: RouteMap | null = null;\n\nfunction compileRoutes(map: RouteMap): CompiledRoute[] {\n if (cacheKey === map && compiledCache) return compiledCache;\n compiledCache = Object.keys(map)\n .filter((k) => k !== '*') // 通配符最后匹配\n .map((pattern) => {\n const { regex, params: paramNames } = compilePattern(pattern);\n return { pattern, regex, paramNames };\n });\n // 通配符路由放最后\n if (map['*']) {\n compiledCache.push({ pattern: '*', regex: /.*/, paramNames: [] });\n }\n cacheKey = map;\n return compiledCache;\n}\n\n/**\n * 根据路径匹配路由表\n * @param path - URL 路径,如 /post/42\n * @param map - 路由表\n * @returns 匹配结果,含路径参数;null 表示 404\n */\nexport function match(path: string, map: RouteMap): MatchResult | null {\n // 确保以 / 开头\n const normalized = path.startsWith('/') ? path : `/${path}`;\n\n for (const compiled of compileRoutes(map)) {\n const m = normalized.match(compiled.regex);\n if (!m) continue;\n\n const params: Record<string, string> = {};\n for (let i = 0; i < compiled.paramNames.length; i++) {\n params[compiled.paramNames[i]] = m[i + 1];\n }\n return { path: compiled.pattern, params };\n }\n return null;\n}\n","import { Store, StoreIgnoreKeys } from 'aoye';\nimport type { RouteMap, RouteEntry, RouteRecord, GuardResult, Menu } from './type';\nimport { match } from './match';\n\n/** 创建带初始数据的 RouteRecord */\nexport function createRouteRecord(\n opts: Partial<Pick<RouteRecord, 'import' | 'component' | 'params'>> = {}\n): RouteRecord {\n return {\n import: opts.import,\n component: opts.component,\n status: opts.component ? 'loaded' : 'idle',\n params: opts.params,\n };\n}\n\nexport class Router extends Store {\n static [StoreIgnoreKeys] = ['routes', 'menus', 'stack', 'ready'] as string[];\n\n /** 当前激活的路由,模板用 {active.component} 渲染 */\n active: RouteEntry | null = null;\n\n /** 路由表 */\n routes: RouteMap = {};\n\n /** 目录嵌套菜单 */\n menus: Menu[] = [];\n\n /** 进入守卫 */\n enterGuard?: (to: RouteEntry) => GuardResult | Promise<GuardResult>;\n\n /** 离开守卫 */\n leaveGuard?: (from: RouteEntry) => GuardResult | Promise<GuardResult>;\n\n /** 历史栈(不响应式) */\n private stack: RouteEntry[] = [];\n private stackIndex = 0;\n\n /** 待预加载的路径集合 */\n private idleSet = new Set<string>();\n\n /** 最大并行预加载数 */\n maxPreload = 3;\n\n /** 当前正在加载的组件数 */\n private loadingCount = 0;\n\n /** 首屏初始化就绪后可继续操作 */\n ready: Promise<void>;\n\n constructor(routes?: RouteMap, initialPath?: string) {\n super();\n if (routes) this.routes = routes;\n this.ready = this.#init(initialPath ?? (typeof location !== 'undefined' ? location.pathname : '/'));\n }\n\n // ====== 初始化 ======\n async #init(path: string): Promise<void> {\n\n // 1. 初始化 idleSet(在加载首屏前,让预加载尽早启动)\n this.#initIdleSet();\n\n // 2. 预加载首屏组件\n const result = match(path, this.routes);\n if (result) {\n await this.#loadComponent(result.path);\n const route = this.routes[result.path];\n\n this.active = {\n path,\n params: result.params,\n component: route.component,\n };\n }\n\n // 2. 浏览器端从 SSR 注入获取首屏组件\n if (typeof window !== 'undefined') {\n const preloaded = (window as any).__INIT_ROUTE__?.[path];\n if (preloaded) {\n const route = this.routes[path];\n if (route) {\n route.component = preloaded;\n route.status = 'loaded';\n if (this.active) this.active.component = preloaded;\n }\n }\n }\n\n this.stack = [{ path, params: this.active?.params ?? {} }];\n this.stackIndex = 0;\n this.#initBrowser();\n }\n\n // ====== 浏览器初始化 ======\n\n #initBrowser(): void {\n if (typeof window === 'undefined') return;\n\n // 劫持容器内链接点击\n document.addEventListener('click', this.#onClick);\n\n // 浏览器前进/后退\n window.addEventListener('popstate', this.#onPopstate);\n }\n\n #initIdleSet(): void {\n for (const path of Object.keys(this.routes)) {\n if (this.routes[path].status === 'idle') {\n this.idleSet.add(path);\n }\n }\n // 移除首屏路径\n if (this.active) {\n this.idleSet.delete(this.active.path);\n }\n }\n\n // ====== 五个公开方法 ======\n\n /** 导航到新页面(追加历史记录) */\n async pushState(url: string): Promise<void> {\n const result = match(url, this.routes);\n if (!result) return;\n\n const target: RouteEntry = { path: url, params: result.params };\n // 截断当前位置之后的历史,再追加\n this.stack.length = this.stackIndex + 1;\n this.stack.push(target);\n this.stackIndex = this.stack.length - 1;\n await this.#navigate(target);\n }\n\n /** 替换当前页面(不追加历史记录) */\n async replaceState(url: string): Promise<void> {\n const result = match(url, this.routes);\n if (!result) return;\n\n const target: RouteEntry = { path: url, params: result.params };\n this.stack[this.stackIndex] = target;\n await this.#navigate(target, { replace: true });\n }\n\n /** 后退 */\n async back(): Promise<void> {\n if (this.stackIndex <= 0) return;\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n\n const target = this.stack[this.stackIndex - 1];\n if (!(await this.#checkGuard(target, 'enter'))) return;\n\n history.back(); // popstate 触发 Index 同步\n }\n\n /** 前进 */\n async forward(): Promise<void> {\n if (this.stackIndex >= this.stack.length - 1) return;\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n\n const target = this.stack[this.stackIndex + 1];\n if (!(await this.#checkGuard(target, 'enter'))) return;\n\n history.forward(); // popstate 触发 Index 同步\n }\n\n /** 跳转多步 */\n async go(delta: number): Promise<void> {\n if (delta === 0) return;\n const newIdx = this.stackIndex + delta;\n if (newIdx < 0 || newIdx >= this.stack.length) return;\n\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n if (!(await this.#checkGuard(this.stack[newIdx], 'enter'))) return;\n\n history.go(delta);\n }\n\n // ====== 内部实现 ======\n\n private navId = 0;\n\n async #navigate(target: RouteEntry, opts: { replace?: boolean } = {}): Promise<void> {\n const id = ++this.navId;\n\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n if (id !== this.navId) return; // 守卫期间有新导航,丢弃本次\n if (!(await this.#checkGuard(target, 'enter'))) return;\n if (id !== this.navId) return;\n\n // 保存当前页滚动位置\n if (this.active && this.stack[this.stackIndex]) {\n this.stack[this.stackIndex].scroll = window.scrollY;\n }\n\n if (!opts.replace) {\n history.pushState(null, '', target.path);\n } else {\n history.replaceState(null, '', target.path);\n }\n\n // 加载组件\n await this.#loadComponent(target.path);\n if (id !== this.navId) return; // 加载期间有新导航,丢弃本次\n\n target.component = this.routes[target.path]?.component;\n this.active = target;\n\n this.#preloadNext();\n }\n\n async #checkGuard(\n entry: RouteEntry,\n type: 'enter' | 'leave'\n ): Promise<boolean> {\n if (type === 'enter' && this.enterGuard) {\n const result = await this.enterGuard(entry);\n if (result === false) return false;\n if (typeof result === 'object' && !result.ok) return false;\n }\n if (type === 'leave' && this.leaveGuard) {\n const result = await this.leaveGuard(entry);\n if (result === false) return false;\n if (typeof result === 'object' && !result.ok) return false;\n }\n return true;\n }\n\n // ====== 组件异步加载 ======\n\n async #loadComponent(path: string): Promise<any> {\n const route = this.routes[path];\n if (!route) return undefined;\n\n switch (route.status) {\n case 'loaded':\n return route.component;\n case 'loading':\n return route.promise;\n case 'error':\n break; // 可重试\n case 'idle':\n break;\n }\n\n if (!route.import) {\n throw new Error(`Route \"${path}\" has no import function`);\n }\n\n this.idleSet.delete(path);\n route.status = 'loading';\n route.promise = route\n .import()\n .then((mod: any) => {\n const Comp = mod.default || mod;\n route.status = 'loaded';\n route.component = Comp;\n return route.component;\n })\n .catch((err) => {\n route.status = 'error';\n throw err;\n })\n .finally(() => {\n this.loadingCount--;\n this.#preloadNext();\n });\n\n return route.promise;\n }\n\n // ====== 空闲预加载 ======\n\n #preloadNext(): void {\n while (this.loadingCount < this.maxPreload && this.idleSet.size > 0) {\n const path = this.idleSet.values().next().value!;\n this.loadingCount++;\n const scheduler =\n typeof requestIdleCallback !== 'undefined'\n ? requestIdleCallback\n : (fn: () => void) => setTimeout(fn, 0);\n scheduler(() => {\n this.#loadComponent(path);\n });\n }\n }\n\n // ====== 链接劫持 ======\n\n #onClick = (e: MouseEvent): void => {\n const link = (e.target as Element).closest('a');\n if (!link) return;\n\n const href = link.getAttribute('href');\n if (!href) return;\n\n try {\n const url = new URL(href, location.origin);\n // 外部链接不拦截\n if (url.origin !== location.origin) return;\n // 新窗口、下载、快捷键不拦截\n if (link.target === '_blank') return;\n if (link.hasAttribute('download')) return;\n if (e.ctrlKey || e.metaKey || e.shiftKey) return;\n\n e.preventDefault();\n this.pushState(url.pathname + url.search + url.hash);\n } catch {\n // 无效 URL,不拦截\n }\n };\n\n // ====== popstate 回调 ======\n\n #onPopstate = (): void => {\n const current = location.pathname + location.search;\n const idx = this.stack.findLastIndex((r) => r.path === current);\n\n if (idx !== -1) {\n // 在栈中 → Router 产生的历史,移动指针\n this.stackIndex = idx;\n const entry = this.stack[idx];\n this.#navigate(entry, { replace: true });\n // 恢复滚动位置\n if (entry.scroll != null) {\n window.scrollTo(0, entry.scroll);\n }\n } else {\n // 不在栈中 → 外部跳转,重置栈\n const result = match(current, this.routes);\n const entry: RouteEntry = {\n path: current,\n params: result?.params ?? {},\n };\n this.stack = [entry];\n this.stackIndex = 0;\n this.active = entry;\n }\n };\n}\n"],"names":["compilePattern","pattern","paramNames","regexStr","replace","_","name","push","regex","RegExp","params","compiledCache","cacheKey","compileRoutes","map","Object","keys","filter","k","_compilePattern","match","path","normalized","startsWith","compiled","m","i","length","createRouteRecord","opts","import","component","status","Router","Store","StoreIgnoreKeys","active","routes","menus","stack","stackIndex","idleSet","Set","maxPreload","loadingCount","constructor","initialPath","ready","location","pathname","#init","result","route","window","preloaded","__INIT_ROUTE__","#initBrowser","document","addEventListener","#initIdleSet","add","delete","pushState","url","target","replaceState","back","history","forward","go","delta","newIdx","navId","#navigate","id","scroll","scrollY","#checkGuard","entry","type","enterGuard","ok","leaveGuard","#loadComponent","undefined","promise","Error","then","mod","Comp","default","catch","err","finally","#preloadNext","size","values","next","value","scheduler","requestIdleCallback","fn","setTimeout","e","link","closest","href","getAttribute","URL","origin","hasAttribute","ctrlKey","metaKey","shiftKey","preventDefault","search","hash","#onPopstate","current","idx","findLastIndex","r","scrollTo"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bobe-router.cjs.js","sources":["../src/match.ts","../src/global.ts","../src/router.ts"],"sourcesContent":["import type { RouteMap, MatchResult } from './type';\n\n/** 编译路径模式为正则:/post/:id → ^\\/post\\/([^/]+)$,捕获名为 id */\nfunction compilePattern(pattern: string): { regex: RegExp; params: string[] } {\n const paramNames: string[] = [];\n const regexStr = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // 转义正则特殊字符\n .replace(/:([a-zA-Z_]\\w*)/g, (_, name) => {\n paramNames.push(name);\n return '([^/]+)';\n });\n return {\n regex: new RegExp(`^${regexStr}$`),\n params: paramNames,\n };\n}\n\n/** 预编译所有路由的正则 */\ntype CompiledRoute = {\n pattern: string;\n regex: RegExp;\n paramNames: string[];\n};\n\nlet compiledCache: CompiledRoute[] | null = null;\nlet cacheKey: RouteMap | null = null;\n\nfunction compileRoutes(map: RouteMap): CompiledRoute[] {\n if (cacheKey === map && compiledCache) return compiledCache;\n compiledCache = Object.keys(map)\n .filter((k) => k !== '*') // 通配符最后匹配\n .map((pattern) => {\n const { regex, params: paramNames } = compilePattern(pattern);\n return { pattern, regex, paramNames };\n });\n // 通配符路由放最后\n if (map['*']) {\n compiledCache.push({ pattern: '*', regex: /.*/, paramNames: [] });\n }\n cacheKey = map;\n return compiledCache;\n}\n\n/**\n * 根据路径匹配路由表\n * @param path - URL 路径,如 /post/42\n * @param map - 路由表\n * @returns 匹配结果,含路径参数;null 表示 404\n */\nexport function match(path: string, map: RouteMap): MatchResult | null {\n // 确保以 / 开头\n const normalized = path.startsWith('/') ? path : `/${path}`;\n\n for (const compiled of compileRoutes(map)) {\n const m = normalized.match(compiled.regex);\n if (!m) continue;\n\n const params: Record<string, string> = {};\n for (let i = 0; i < compiled.paramNames.length; i++) {\n params[compiled.paramNames[i]] = m[i + 1];\n }\n return { path: compiled.pattern, params };\n }\n return null;\n}\n","/** 通过 globalThis 传递的路由全局变量名 */\nexport enum GlobalKey {\n /** 路由表:{ [url]: { import/component } } */\n Routes = '__BOBE_INIT_ROUTES__',\n /** 菜单树:Menu[] */\n Menus = '__BOBE_INIT_MENUS__',\n /** 初始路径 */\n Path = '__BOBE_INIT_PATH__',\n}\n","import { Store, StoreIgnoreKeys } from 'aoye';\nimport type { RouteMap, RouteEntry, RouteRecord, GuardResult, Menu, RouterOptions } from './type';\nimport { match } from './match';\nimport { GlobalKey } from './global';\n\n/** 创建带初始数据的 RouteRecord */\nexport function createRouteRecord(\n opts: Partial<Pick<RouteRecord, 'import' | 'component' | 'params'>> = {}\n): RouteRecord {\n return {\n import: opts.import,\n component: opts.component,\n status: opts.component ? 'loaded' : 'idle',\n params: opts.params,\n };\n}\n\nexport class Router extends Store {\n static [StoreIgnoreKeys] = ['routes', 'menus', 'stack', 'ready'] as string[];\n\n /** 当前激活的路由,模板用 {active.component} 渲染 */\n active: RouteEntry | null = null;\n\n /** 路由表 */\n routes: RouteMap = {};\n\n /** 目录嵌套菜单 */\n menus: Menu[] = [];\n\n /** 进入守卫 */\n enterGuard?: (to: RouteEntry) => GuardResult | Promise<GuardResult>;\n\n /** 离开守卫 */\n leaveGuard?: (from: RouteEntry) => GuardResult | Promise<GuardResult>;\n\n /** 历史栈(不响应式) */\n private stack: RouteEntry[] = [];\n private stackIndex = 0;\n\n /** 待预加载的路径集合 */\n private idleSet = new Set<string>();\n\n /** 最大并行预加载数 */\n maxPreload = 3;\n\n /** 当前正在加载的组件数 */\n private loadingCount = 0;\n\n /**\n * 注册首屏就绪回调。\n * - 已初始化 → 同步执行 cb\n * - 未初始化 → 入队,首屏加载完成后执行\n * 支持多次调用。\n * 无参数时返回 Promise。\n */\n ready(): Promise<void>;\n ready(cb: () => void): void;\n ready(cb?: () => void): Promise<void> | void {\n if (cb) {\n if (this.#inited) { cb(); }\n else { this.#readyQueue.push(cb); }\n return;\n }\n return new Promise<void>(resolve => this.ready(resolve));\n }\n\n #inited = false;\n #readyQueue: (() => void)[] = [];\n\n constructor(opt?: RouterOptions) {\n super();\n\n const routes = opt?.routes;\n const initialPath = opt?.initialPath;\n\n // 1. routes 优先级:用户传入 > SSR 注入 > 空\n this.routes = routes\n || (globalThis as any)[GlobalKey.Routes]\n || {};\n\n // 2. menus 优先级:SSR 注入 > 空\n const injectedMenus = (globalThis as any)[GlobalKey.Menus];\n if (injectedMenus) this.menus = injectedMenus;\n\n // 3. path 优先级:用户传入 > SSR 注入 > location > '/'\n const path = initialPath\n || (globalThis as any)[GlobalKey.Path]\n || (typeof location !== 'undefined' ? location.pathname : '/');\n\n this.#init(path);\n }\n\n // ====== 初始化 ======\n async #init(path: string): Promise<void> {\n\n // 1. 初始化 idleSet(在加载首屏前,让预加载尽早启动)\n this.#initIdleSet();\n\n // 2. 首屏:匹配路由,已有 component 则跳过 load\n const result = match(path, this.routes);\n if (result) {\n const route = this.routes[result.path];\n\n if (route?.component) {\n // SSR 注入或构造函数传入的 component,直接复用\n route.status = 'loaded';\n } else {\n await this.#loadComponent(result.path);\n }\n\n this.active = {\n path,\n params: result.params,\n component: route?.component,\n };\n }\n\n this.stack = [{ path, params: this.active?.params ?? {} }];\n this.stackIndex = 0;\n this.#initBrowser();\n\n // 就绪:执行所有排队回调\n this.#inited = true;\n const q = this.#readyQueue;\n this.#readyQueue = [];\n for (const cb of q) cb();\n }\n\n // ====== 浏览器初始化 ======\n\n #initBrowser(): void {\n if (typeof window === 'undefined') return;\n\n // 劫持容器内链接点击\n document.addEventListener('click', this.#onClick);\n\n // 浏览器前进/后退\n window.addEventListener('popstate', this.#onPopstate);\n }\n\n #initIdleSet(): void {\n for (const path of Object.keys(this.routes)) {\n if (this.routes[path].status === 'idle') {\n this.idleSet.add(path);\n }\n }\n // 移除首屏路径\n if (this.active) {\n this.idleSet.delete(this.active.path);\n }\n }\n\n // ====== 五个公开方法 ======\n\n /** 导航到新页面(追加历史记录) */\n async pushState(url: string): Promise<void> {\n const result = match(url, this.routes);\n if (!result) return;\n\n const target: RouteEntry = { path: url, params: result.params };\n // 截断当前位置之后的历史,再追加\n this.stack.length = this.stackIndex + 1;\n this.stack.push(target);\n this.stackIndex = this.stack.length - 1;\n await this.#navigate(target);\n }\n\n /** 替换当前页面(不追加历史记录) */\n async replaceState(url: string): Promise<void> {\n const result = match(url, this.routes);\n if (!result) return;\n\n const target: RouteEntry = { path: url, params: result.params };\n this.stack[this.stackIndex] = target;\n await this.#navigate(target, { replace: true });\n }\n\n /** 后退 */\n async back(): Promise<void> {\n if (this.stackIndex <= 0) return;\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n\n const target = this.stack[this.stackIndex - 1];\n if (!(await this.#checkGuard(target, 'enter'))) return;\n\n history.back(); // popstate 触发 Index 同步\n }\n\n /** 前进 */\n async forward(): Promise<void> {\n if (this.stackIndex >= this.stack.length - 1) return;\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n\n const target = this.stack[this.stackIndex + 1];\n if (!(await this.#checkGuard(target, 'enter'))) return;\n\n history.forward(); // popstate 触发 Index 同步\n }\n\n /** 跳转多步 */\n async go(delta: number): Promise<void> {\n if (delta === 0) return;\n const newIdx = this.stackIndex + delta;\n if (newIdx < 0 || newIdx >= this.stack.length) return;\n\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n if (!(await this.#checkGuard(this.stack[newIdx], 'enter'))) return;\n\n history.go(delta);\n }\n\n // ====== 内部实现 ======\n\n private navId = 0;\n\n async #navigate(target: RouteEntry, opts: { replace?: boolean } = {}): Promise<void> {\n const id = ++this.navId;\n\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n if (id !== this.navId) return; // 守卫期间有新导航,丢弃本次\n if (!(await this.#checkGuard(target, 'enter'))) return;\n if (id !== this.navId) return;\n\n // 保存当前页滚动位置\n if (this.active && this.stack[this.stackIndex]) {\n this.stack[this.stackIndex].scroll = window.scrollY;\n }\n\n if (!opts.replace) {\n history.pushState(null, '', target.path);\n } else {\n history.replaceState(null, '', target.path);\n }\n\n // 加载组件\n await this.#loadComponent(target.path);\n if (id !== this.navId) return; // 加载期间有新导航,丢弃本次\n\n target.component = this.routes[target.path]?.component;\n this.active = target;\n\n // hash 滚动\n const hash = new URL(target.path, location.origin).hash;\n if (hash) {\n const el = document.querySelector(decodeURIComponent(hash));\n if (el) (el as HTMLElement).scrollIntoView({ behavior: 'smooth' });\n }\n\n this.#preloadNext();\n }\n\n async #checkGuard(\n entry: RouteEntry,\n type: 'enter' | 'leave'\n ): Promise<boolean> {\n if (type === 'enter' && this.enterGuard) {\n const result = await this.enterGuard(entry);\n if (result === false) return false;\n if (typeof result === 'object' && !result.ok) return false;\n }\n if (type === 'leave' && this.leaveGuard) {\n const result = await this.leaveGuard(entry);\n if (result === false) return false;\n if (typeof result === 'object' && !result.ok) return false;\n }\n return true;\n }\n\n // ====== 组件异步加载 ======\n\n async #loadComponent(path: string): Promise<any> {\n const route = this.routes[path];\n if (!route) return undefined;\n\n switch (route.status) {\n case 'loaded':\n return route.component;\n case 'loading':\n return route.promise;\n case 'error':\n break; // 可重试\n case 'idle':\n break;\n }\n\n if (!route.import) {\n throw new Error(`Route \"${path}\" has no import function`);\n }\n\n this.idleSet.delete(path);\n route.status = 'loading';\n route.promise = route\n .import()\n .then((mod: any) => {\n const Comp = mod.default || mod;\n route.status = 'loaded';\n route.component = Comp;\n return route.component;\n })\n .catch((err) => {\n route.status = 'error';\n throw err;\n })\n .finally(() => {\n this.loadingCount--;\n this.#preloadNext();\n });\n\n return route.promise;\n }\n\n // ====== 空闲预加载 ======\n\n #preloadNext(): void {\n while (this.loadingCount < this.maxPreload && this.idleSet.size > 0) {\n const path = this.idleSet.values().next().value!;\n this.loadingCount++;\n const scheduler =\n typeof requestIdleCallback !== 'undefined'\n ? requestIdleCallback\n : (fn: () => void) => setTimeout(fn, 0);\n scheduler(() => {\n this.#loadComponent(path);\n });\n }\n }\n\n // ====== 链接劫持 ======\n\n #onClick = (e: MouseEvent): void => {\n const link = (e.target as Element).closest('a');\n if (!link) return;\n\n const href = link.getAttribute('href');\n if (!href) return;\n\n // 纯 hash 链接放行,浏览器原生处理滚动\n if (href.startsWith('#')) return;\n\n try {\n const url = new URL(href, location.origin);\n // 外部链接不拦截\n if (url.origin !== location.origin) return;\n // 新窗口、下载、快捷键不拦截\n if (link.target === '_blank') return;\n if (link.hasAttribute('download')) return;\n if (e.ctrlKey || e.metaKey || e.shiftKey) return;\n\n e.preventDefault();\n this.pushState(url.pathname + url.search + url.hash);\n } catch {\n // 无效 URL,不拦截\n }\n };\n\n // ====== popstate 回调 ======\n\n #onPopstate = (): void => {\n const current = location.pathname + location.search;\n const idx = this.stack.findLastIndex((r) => r.path === current);\n\n if (idx !== -1) {\n // 仅 hash 变化,浏览器已更新 URL 并处理滚动,跳过 #navigate(避免 replaceState 抹掉 hash)\n if (idx === this.stackIndex) return;\n // 在栈中 → Router 产生的历史,移动指针\n this.stackIndex = idx;\n const entry = this.stack[idx];\n this.#navigate(entry, { replace: true });\n // 恢复滚动位置\n if (entry.scroll != null) {\n window.scrollTo(0, entry.scroll);\n }\n } else {\n // 不在栈中 → 外部跳转,重置栈\n const result = match(current, this.routes);\n const entry: RouteEntry = {\n path: current,\n params: result?.params ?? {},\n };\n this.stack = [entry];\n this.stackIndex = 0;\n this.active = entry;\n }\n };\n}\n"],"names":["compilePattern","pattern","paramNames","regexStr","replace","_","name","push","regex","RegExp","params","compiledCache","cacheKey","compileRoutes","map","Object","keys","filter","k","_compilePattern","match","path","normalized","startsWith","compiled","m","i","length","GlobalKey","createRouteRecord","opts","import","component","status","Router","Store","StoreIgnoreKeys","active","routes","menus","stack","stackIndex","idleSet","Set","maxPreload","loadingCount","ready","cb","Promise","resolve","constructor","opt","initialPath","globalThis","Routes","injectedMenus","Menus","Path","location","pathname","#init","result","route","q","#initBrowser","window","document","addEventListener","#initIdleSet","add","delete","pushState","url","target","replaceState","back","history","forward","go","delta","newIdx","navId","#navigate","id","scroll","scrollY","hash","URL","origin","el","querySelector","decodeURIComponent","scrollIntoView","behavior","#checkGuard","entry","type","enterGuard","ok","leaveGuard","#loadComponent","undefined","promise","Error","then","mod","Comp","default","catch","err","finally","#preloadNext","size","values","next","value","scheduler","requestIdleCallback","fn","setTimeout","e","link","closest","href","getAttribute","hasAttribute","ctrlKey","metaKey","shiftKey","preventDefault","search","#onPopstate","current","idx","findLastIndex","r","scrollTo"],"mappings":"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"}
|
package/dist/bobe-router.esm.js
CHANGED
|
@@ -52,6 +52,13 @@ function match(path, map) {
|
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
let GlobalKey = function (GlobalKey) {
|
|
56
|
+
GlobalKey["Routes"] = "__BOBE_INIT_ROUTES__";
|
|
57
|
+
GlobalKey["Menus"] = "__BOBE_INIT_MENUS__";
|
|
58
|
+
GlobalKey["Path"] = "__BOBE_INIT_PATH__";
|
|
59
|
+
return GlobalKey;
|
|
60
|
+
}({});
|
|
61
|
+
|
|
55
62
|
function createRouteRecord(opts = {}) {
|
|
56
63
|
return {
|
|
57
64
|
import: opts.import,
|
|
@@ -70,40 +77,55 @@ class Router extends Store {
|
|
|
70
77
|
idleSet = new Set();
|
|
71
78
|
maxPreload = 3;
|
|
72
79
|
loadingCount = 0;
|
|
73
|
-
|
|
80
|
+
ready(cb) {
|
|
81
|
+
if (cb) {
|
|
82
|
+
if (this.#inited) {
|
|
83
|
+
cb();
|
|
84
|
+
} else {
|
|
85
|
+
this.#readyQueue.push(cb);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
return new Promise(resolve => this.ready(resolve));
|
|
90
|
+
}
|
|
91
|
+
#inited = false;
|
|
92
|
+
#readyQueue = [];
|
|
93
|
+
constructor(opt) {
|
|
74
94
|
super();
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
const routes = opt?.routes;
|
|
96
|
+
const initialPath = opt?.initialPath;
|
|
97
|
+
this.routes = routes || globalThis[GlobalKey.Routes] || {};
|
|
98
|
+
const injectedMenus = globalThis[GlobalKey.Menus];
|
|
99
|
+
if (injectedMenus) this.menus = injectedMenus;
|
|
100
|
+
const path = initialPath || globalThis[GlobalKey.Path] || (typeof location !== 'undefined' ? location.pathname : '/');
|
|
101
|
+
this.#init(path);
|
|
77
102
|
}
|
|
78
103
|
async #init(path) {
|
|
79
104
|
this.#initIdleSet();
|
|
80
105
|
const result = match(path, this.routes);
|
|
81
106
|
if (result) {
|
|
82
|
-
await this.#loadComponent(result.path);
|
|
83
107
|
const route = this.routes[result.path];
|
|
108
|
+
if (route?.component) {
|
|
109
|
+
route.status = 'loaded';
|
|
110
|
+
} else {
|
|
111
|
+
await this.#loadComponent(result.path);
|
|
112
|
+
}
|
|
84
113
|
this.active = {
|
|
85
114
|
path,
|
|
86
115
|
params: result.params,
|
|
87
|
-
component: route
|
|
116
|
+
component: route?.component
|
|
88
117
|
};
|
|
89
118
|
}
|
|
90
|
-
if (typeof window !== 'undefined') {
|
|
91
|
-
const preloaded = window.__INIT_ROUTE__?.[path];
|
|
92
|
-
if (preloaded) {
|
|
93
|
-
const route = this.routes[path];
|
|
94
|
-
if (route) {
|
|
95
|
-
route.component = preloaded;
|
|
96
|
-
route.status = 'loaded';
|
|
97
|
-
if (this.active) this.active.component = preloaded;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
119
|
this.stack = [{
|
|
102
120
|
path,
|
|
103
121
|
params: this.active?.params ?? {}
|
|
104
122
|
}];
|
|
105
123
|
this.stackIndex = 0;
|
|
106
124
|
this.#initBrowser();
|
|
125
|
+
this.#inited = true;
|
|
126
|
+
const q = this.#readyQueue;
|
|
127
|
+
this.#readyQueue = [];
|
|
128
|
+
for (const cb of q) cb();
|
|
107
129
|
}
|
|
108
130
|
#initBrowser() {
|
|
109
131
|
if (typeof window === 'undefined') return;
|
|
@@ -185,6 +207,13 @@ class Router extends Store {
|
|
|
185
207
|
if (id !== this.navId) return;
|
|
186
208
|
target.component = this.routes[target.path]?.component;
|
|
187
209
|
this.active = target;
|
|
210
|
+
const hash = new URL(target.path, location.origin).hash;
|
|
211
|
+
if (hash) {
|
|
212
|
+
const el = document.querySelector(decodeURIComponent(hash));
|
|
213
|
+
if (el) el.scrollIntoView({
|
|
214
|
+
behavior: 'smooth'
|
|
215
|
+
});
|
|
216
|
+
}
|
|
188
217
|
this.#preloadNext();
|
|
189
218
|
}
|
|
190
219
|
async #checkGuard(entry, type) {
|
|
@@ -243,6 +272,7 @@ class Router extends Store {
|
|
|
243
272
|
if (!link) return;
|
|
244
273
|
const href = link.getAttribute('href');
|
|
245
274
|
if (!href) return;
|
|
275
|
+
if (href.startsWith('#')) return;
|
|
246
276
|
try {
|
|
247
277
|
const url = new URL(href, location.origin);
|
|
248
278
|
if (url.origin !== location.origin) return;
|
|
@@ -257,6 +287,7 @@ class Router extends Store {
|
|
|
257
287
|
const current = location.pathname + location.search;
|
|
258
288
|
const idx = this.stack.findLastIndex(r => r.path === current);
|
|
259
289
|
if (idx !== -1) {
|
|
290
|
+
if (idx === this.stackIndex) return;
|
|
260
291
|
this.stackIndex = idx;
|
|
261
292
|
const entry = this.stack[idx];
|
|
262
293
|
this.#navigate(entry, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bobe-router.esm.js","sources":["../src/match.ts","../src/router.ts"],"sourcesContent":["import type { RouteMap, MatchResult } from './type';\n\n/** 编译路径模式为正则:/post/:id → ^\\/post\\/([^/]+)$,捕获名为 id */\nfunction compilePattern(pattern: string): { regex: RegExp; params: string[] } {\n const paramNames: string[] = [];\n const regexStr = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // 转义正则特殊字符\n .replace(/:([a-zA-Z_]\\w*)/g, (_, name) => {\n paramNames.push(name);\n return '([^/]+)';\n });\n return {\n regex: new RegExp(`^${regexStr}$`),\n params: paramNames,\n };\n}\n\n/** 预编译所有路由的正则 */\ntype CompiledRoute = {\n pattern: string;\n regex: RegExp;\n paramNames: string[];\n};\n\nlet compiledCache: CompiledRoute[] | null = null;\nlet cacheKey: RouteMap | null = null;\n\nfunction compileRoutes(map: RouteMap): CompiledRoute[] {\n if (cacheKey === map && compiledCache) return compiledCache;\n compiledCache = Object.keys(map)\n .filter((k) => k !== '*') // 通配符最后匹配\n .map((pattern) => {\n const { regex, params: paramNames } = compilePattern(pattern);\n return { pattern, regex, paramNames };\n });\n // 通配符路由放最后\n if (map['*']) {\n compiledCache.push({ pattern: '*', regex: /.*/, paramNames: [] });\n }\n cacheKey = map;\n return compiledCache;\n}\n\n/**\n * 根据路径匹配路由表\n * @param path - URL 路径,如 /post/42\n * @param map - 路由表\n * @returns 匹配结果,含路径参数;null 表示 404\n */\nexport function match(path: string, map: RouteMap): MatchResult | null {\n // 确保以 / 开头\n const normalized = path.startsWith('/') ? path : `/${path}`;\n\n for (const compiled of compileRoutes(map)) {\n const m = normalized.match(compiled.regex);\n if (!m) continue;\n\n const params: Record<string, string> = {};\n for (let i = 0; i < compiled.paramNames.length; i++) {\n params[compiled.paramNames[i]] = m[i + 1];\n }\n return { path: compiled.pattern, params };\n }\n return null;\n}\n","import { Store, StoreIgnoreKeys } from 'aoye';\nimport type { RouteMap, RouteEntry, RouteRecord, GuardResult, Menu } from './type';\nimport { match } from './match';\n\n/** 创建带初始数据的 RouteRecord */\nexport function createRouteRecord(\n opts: Partial<Pick<RouteRecord, 'import' | 'component' | 'params'>> = {}\n): RouteRecord {\n return {\n import: opts.import,\n component: opts.component,\n status: opts.component ? 'loaded' : 'idle',\n params: opts.params,\n };\n}\n\nexport class Router extends Store {\n static [StoreIgnoreKeys] = ['routes', 'menus', 'stack', 'ready'] as string[];\n\n /** 当前激活的路由,模板用 {active.component} 渲染 */\n active: RouteEntry | null = null;\n\n /** 路由表 */\n routes: RouteMap = {};\n\n /** 目录嵌套菜单 */\n menus: Menu[] = [];\n\n /** 进入守卫 */\n enterGuard?: (to: RouteEntry) => GuardResult | Promise<GuardResult>;\n\n /** 离开守卫 */\n leaveGuard?: (from: RouteEntry) => GuardResult | Promise<GuardResult>;\n\n /** 历史栈(不响应式) */\n private stack: RouteEntry[] = [];\n private stackIndex = 0;\n\n /** 待预加载的路径集合 */\n private idleSet = new Set<string>();\n\n /** 最大并行预加载数 */\n maxPreload = 3;\n\n /** 当前正在加载的组件数 */\n private loadingCount = 0;\n\n /** 首屏初始化就绪后可继续操作 */\n ready: Promise<void>;\n\n constructor(routes?: RouteMap, initialPath?: string) {\n super();\n if (routes) this.routes = routes;\n this.ready = this.#init(initialPath ?? (typeof location !== 'undefined' ? location.pathname : '/'));\n }\n\n // ====== 初始化 ======\n async #init(path: string): Promise<void> {\n\n // 1. 初始化 idleSet(在加载首屏前,让预加载尽早启动)\n this.#initIdleSet();\n\n // 2. 预加载首屏组件\n const result = match(path, this.routes);\n if (result) {\n await this.#loadComponent(result.path);\n const route = this.routes[result.path];\n\n this.active = {\n path,\n params: result.params,\n component: route.component,\n };\n }\n\n // 2. 浏览器端从 SSR 注入获取首屏组件\n if (typeof window !== 'undefined') {\n const preloaded = (window as any).__INIT_ROUTE__?.[path];\n if (preloaded) {\n const route = this.routes[path];\n if (route) {\n route.component = preloaded;\n route.status = 'loaded';\n if (this.active) this.active.component = preloaded;\n }\n }\n }\n\n this.stack = [{ path, params: this.active?.params ?? {} }];\n this.stackIndex = 0;\n this.#initBrowser();\n }\n\n // ====== 浏览器初始化 ======\n\n #initBrowser(): void {\n if (typeof window === 'undefined') return;\n\n // 劫持容器内链接点击\n document.addEventListener('click', this.#onClick);\n\n // 浏览器前进/后退\n window.addEventListener('popstate', this.#onPopstate);\n }\n\n #initIdleSet(): void {\n for (const path of Object.keys(this.routes)) {\n if (this.routes[path].status === 'idle') {\n this.idleSet.add(path);\n }\n }\n // 移除首屏路径\n if (this.active) {\n this.idleSet.delete(this.active.path);\n }\n }\n\n // ====== 五个公开方法 ======\n\n /** 导航到新页面(追加历史记录) */\n async pushState(url: string): Promise<void> {\n const result = match(url, this.routes);\n if (!result) return;\n\n const target: RouteEntry = { path: url, params: result.params };\n // 截断当前位置之后的历史,再追加\n this.stack.length = this.stackIndex + 1;\n this.stack.push(target);\n this.stackIndex = this.stack.length - 1;\n await this.#navigate(target);\n }\n\n /** 替换当前页面(不追加历史记录) */\n async replaceState(url: string): Promise<void> {\n const result = match(url, this.routes);\n if (!result) return;\n\n const target: RouteEntry = { path: url, params: result.params };\n this.stack[this.stackIndex] = target;\n await this.#navigate(target, { replace: true });\n }\n\n /** 后退 */\n async back(): Promise<void> {\n if (this.stackIndex <= 0) return;\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n\n const target = this.stack[this.stackIndex - 1];\n if (!(await this.#checkGuard(target, 'enter'))) return;\n\n history.back(); // popstate 触发 Index 同步\n }\n\n /** 前进 */\n async forward(): Promise<void> {\n if (this.stackIndex >= this.stack.length - 1) return;\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n\n const target = this.stack[this.stackIndex + 1];\n if (!(await this.#checkGuard(target, 'enter'))) return;\n\n history.forward(); // popstate 触发 Index 同步\n }\n\n /** 跳转多步 */\n async go(delta: number): Promise<void> {\n if (delta === 0) return;\n const newIdx = this.stackIndex + delta;\n if (newIdx < 0 || newIdx >= this.stack.length) return;\n\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n if (!(await this.#checkGuard(this.stack[newIdx], 'enter'))) return;\n\n history.go(delta);\n }\n\n // ====== 内部实现 ======\n\n private navId = 0;\n\n async #navigate(target: RouteEntry, opts: { replace?: boolean } = {}): Promise<void> {\n const id = ++this.navId;\n\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n if (id !== this.navId) return; // 守卫期间有新导航,丢弃本次\n if (!(await this.#checkGuard(target, 'enter'))) return;\n if (id !== this.navId) return;\n\n // 保存当前页滚动位置\n if (this.active && this.stack[this.stackIndex]) {\n this.stack[this.stackIndex].scroll = window.scrollY;\n }\n\n if (!opts.replace) {\n history.pushState(null, '', target.path);\n } else {\n history.replaceState(null, '', target.path);\n }\n\n // 加载组件\n await this.#loadComponent(target.path);\n if (id !== this.navId) return; // 加载期间有新导航,丢弃本次\n\n target.component = this.routes[target.path]?.component;\n this.active = target;\n\n this.#preloadNext();\n }\n\n async #checkGuard(\n entry: RouteEntry,\n type: 'enter' | 'leave'\n ): Promise<boolean> {\n if (type === 'enter' && this.enterGuard) {\n const result = await this.enterGuard(entry);\n if (result === false) return false;\n if (typeof result === 'object' && !result.ok) return false;\n }\n if (type === 'leave' && this.leaveGuard) {\n const result = await this.leaveGuard(entry);\n if (result === false) return false;\n if (typeof result === 'object' && !result.ok) return false;\n }\n return true;\n }\n\n // ====== 组件异步加载 ======\n\n async #loadComponent(path: string): Promise<any> {\n const route = this.routes[path];\n if (!route) return undefined;\n\n switch (route.status) {\n case 'loaded':\n return route.component;\n case 'loading':\n return route.promise;\n case 'error':\n break; // 可重试\n case 'idle':\n break;\n }\n\n if (!route.import) {\n throw new Error(`Route \"${path}\" has no import function`);\n }\n\n this.idleSet.delete(path);\n route.status = 'loading';\n route.promise = route\n .import()\n .then((mod: any) => {\n const Comp = mod.default || mod;\n route.status = 'loaded';\n route.component = Comp;\n return route.component;\n })\n .catch((err) => {\n route.status = 'error';\n throw err;\n })\n .finally(() => {\n this.loadingCount--;\n this.#preloadNext();\n });\n\n return route.promise;\n }\n\n // ====== 空闲预加载 ======\n\n #preloadNext(): void {\n while (this.loadingCount < this.maxPreload && this.idleSet.size > 0) {\n const path = this.idleSet.values().next().value!;\n this.loadingCount++;\n const scheduler =\n typeof requestIdleCallback !== 'undefined'\n ? requestIdleCallback\n : (fn: () => void) => setTimeout(fn, 0);\n scheduler(() => {\n this.#loadComponent(path);\n });\n }\n }\n\n // ====== 链接劫持 ======\n\n #onClick = (e: MouseEvent): void => {\n const link = (e.target as Element).closest('a');\n if (!link) return;\n\n const href = link.getAttribute('href');\n if (!href) return;\n\n try {\n const url = new URL(href, location.origin);\n // 外部链接不拦截\n if (url.origin !== location.origin) return;\n // 新窗口、下载、快捷键不拦截\n if (link.target === '_blank') return;\n if (link.hasAttribute('download')) return;\n if (e.ctrlKey || e.metaKey || e.shiftKey) return;\n\n e.preventDefault();\n this.pushState(url.pathname + url.search + url.hash);\n } catch {\n // 无效 URL,不拦截\n }\n };\n\n // ====== popstate 回调 ======\n\n #onPopstate = (): void => {\n const current = location.pathname + location.search;\n const idx = this.stack.findLastIndex((r) => r.path === current);\n\n if (idx !== -1) {\n // 在栈中 → Router 产生的历史,移动指针\n this.stackIndex = idx;\n const entry = this.stack[idx];\n this.#navigate(entry, { replace: true });\n // 恢复滚动位置\n if (entry.scroll != null) {\n window.scrollTo(0, entry.scroll);\n }\n } else {\n // 不在栈中 → 外部跳转,重置栈\n const result = match(current, this.routes);\n const entry: RouteEntry = {\n path: current,\n params: result?.params ?? {},\n };\n this.stack = [entry];\n this.stackIndex = 0;\n this.active = entry;\n }\n };\n}\n"],"names":["compilePattern","pattern","paramNames","regexStr","replace","_","name","push","regex","RegExp","params","compiledCache","cacheKey","compileRoutes","map","Object","keys","filter","k","_compilePattern","match","path","normalized","startsWith","compiled","m","i","length","createRouteRecord","opts","import","component","status","Router","Store","StoreIgnoreKeys","active","routes","menus","stack","stackIndex","idleSet","Set","maxPreload","loadingCount","constructor","initialPath","ready","location","pathname","#init","result","route","window","preloaded","__INIT_ROUTE__","#initBrowser","document","addEventListener","#initIdleSet","add","delete","pushState","url","target","replaceState","back","history","forward","go","delta","newIdx","navId","#navigate","id","scroll","scrollY","#checkGuard","entry","type","enterGuard","ok","leaveGuard","#loadComponent","undefined","promise","Error","then","mod","Comp","default","catch","err","finally","#preloadNext","size","values","next","value","scheduler","requestIdleCallback","fn","setTimeout","e","link","closest","href","getAttribute","URL","origin","hasAttribute","ctrlKey","metaKey","shiftKey","preventDefault","search","hash","#onPopstate","current","idx","findLastIndex","r","scrollTo"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bobe-router.esm.js","sources":["../src/match.ts","../src/global.ts","../src/router.ts"],"sourcesContent":["import type { RouteMap, MatchResult } from './type';\n\n/** 编译路径模式为正则:/post/:id → ^\\/post\\/([^/]+)$,捕获名为 id */\nfunction compilePattern(pattern: string): { regex: RegExp; params: string[] } {\n const paramNames: string[] = [];\n const regexStr = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // 转义正则特殊字符\n .replace(/:([a-zA-Z_]\\w*)/g, (_, name) => {\n paramNames.push(name);\n return '([^/]+)';\n });\n return {\n regex: new RegExp(`^${regexStr}$`),\n params: paramNames,\n };\n}\n\n/** 预编译所有路由的正则 */\ntype CompiledRoute = {\n pattern: string;\n regex: RegExp;\n paramNames: string[];\n};\n\nlet compiledCache: CompiledRoute[] | null = null;\nlet cacheKey: RouteMap | null = null;\n\nfunction compileRoutes(map: RouteMap): CompiledRoute[] {\n if (cacheKey === map && compiledCache) return compiledCache;\n compiledCache = Object.keys(map)\n .filter((k) => k !== '*') // 通配符最后匹配\n .map((pattern) => {\n const { regex, params: paramNames } = compilePattern(pattern);\n return { pattern, regex, paramNames };\n });\n // 通配符路由放最后\n if (map['*']) {\n compiledCache.push({ pattern: '*', regex: /.*/, paramNames: [] });\n }\n cacheKey = map;\n return compiledCache;\n}\n\n/**\n * 根据路径匹配路由表\n * @param path - URL 路径,如 /post/42\n * @param map - 路由表\n * @returns 匹配结果,含路径参数;null 表示 404\n */\nexport function match(path: string, map: RouteMap): MatchResult | null {\n // 确保以 / 开头\n const normalized = path.startsWith('/') ? path : `/${path}`;\n\n for (const compiled of compileRoutes(map)) {\n const m = normalized.match(compiled.regex);\n if (!m) continue;\n\n const params: Record<string, string> = {};\n for (let i = 0; i < compiled.paramNames.length; i++) {\n params[compiled.paramNames[i]] = m[i + 1];\n }\n return { path: compiled.pattern, params };\n }\n return null;\n}\n","/** 通过 globalThis 传递的路由全局变量名 */\nexport enum GlobalKey {\n /** 路由表:{ [url]: { import/component } } */\n Routes = '__BOBE_INIT_ROUTES__',\n /** 菜单树:Menu[] */\n Menus = '__BOBE_INIT_MENUS__',\n /** 初始路径 */\n Path = '__BOBE_INIT_PATH__',\n}\n","import { Store, StoreIgnoreKeys } from 'aoye';\nimport type { RouteMap, RouteEntry, RouteRecord, GuardResult, Menu, RouterOptions } from './type';\nimport { match } from './match';\nimport { GlobalKey } from './global';\n\n/** 创建带初始数据的 RouteRecord */\nexport function createRouteRecord(\n opts: Partial<Pick<RouteRecord, 'import' | 'component' | 'params'>> = {}\n): RouteRecord {\n return {\n import: opts.import,\n component: opts.component,\n status: opts.component ? 'loaded' : 'idle',\n params: opts.params,\n };\n}\n\nexport class Router extends Store {\n static [StoreIgnoreKeys] = ['routes', 'menus', 'stack', 'ready'] as string[];\n\n /** 当前激活的路由,模板用 {active.component} 渲染 */\n active: RouteEntry | null = null;\n\n /** 路由表 */\n routes: RouteMap = {};\n\n /** 目录嵌套菜单 */\n menus: Menu[] = [];\n\n /** 进入守卫 */\n enterGuard?: (to: RouteEntry) => GuardResult | Promise<GuardResult>;\n\n /** 离开守卫 */\n leaveGuard?: (from: RouteEntry) => GuardResult | Promise<GuardResult>;\n\n /** 历史栈(不响应式) */\n private stack: RouteEntry[] = [];\n private stackIndex = 0;\n\n /** 待预加载的路径集合 */\n private idleSet = new Set<string>();\n\n /** 最大并行预加载数 */\n maxPreload = 3;\n\n /** 当前正在加载的组件数 */\n private loadingCount = 0;\n\n /**\n * 注册首屏就绪回调。\n * - 已初始化 → 同步执行 cb\n * - 未初始化 → 入队,首屏加载完成后执行\n * 支持多次调用。\n * 无参数时返回 Promise。\n */\n ready(): Promise<void>;\n ready(cb: () => void): void;\n ready(cb?: () => void): Promise<void> | void {\n if (cb) {\n if (this.#inited) { cb(); }\n else { this.#readyQueue.push(cb); }\n return;\n }\n return new Promise<void>(resolve => this.ready(resolve));\n }\n\n #inited = false;\n #readyQueue: (() => void)[] = [];\n\n constructor(opt?: RouterOptions) {\n super();\n\n const routes = opt?.routes;\n const initialPath = opt?.initialPath;\n\n // 1. routes 优先级:用户传入 > SSR 注入 > 空\n this.routes = routes\n || (globalThis as any)[GlobalKey.Routes]\n || {};\n\n // 2. menus 优先级:SSR 注入 > 空\n const injectedMenus = (globalThis as any)[GlobalKey.Menus];\n if (injectedMenus) this.menus = injectedMenus;\n\n // 3. path 优先级:用户传入 > SSR 注入 > location > '/'\n const path = initialPath\n || (globalThis as any)[GlobalKey.Path]\n || (typeof location !== 'undefined' ? location.pathname : '/');\n\n this.#init(path);\n }\n\n // ====== 初始化 ======\n async #init(path: string): Promise<void> {\n\n // 1. 初始化 idleSet(在加载首屏前,让预加载尽早启动)\n this.#initIdleSet();\n\n // 2. 首屏:匹配路由,已有 component 则跳过 load\n const result = match(path, this.routes);\n if (result) {\n const route = this.routes[result.path];\n\n if (route?.component) {\n // SSR 注入或构造函数传入的 component,直接复用\n route.status = 'loaded';\n } else {\n await this.#loadComponent(result.path);\n }\n\n this.active = {\n path,\n params: result.params,\n component: route?.component,\n };\n }\n\n this.stack = [{ path, params: this.active?.params ?? {} }];\n this.stackIndex = 0;\n this.#initBrowser();\n\n // 就绪:执行所有排队回调\n this.#inited = true;\n const q = this.#readyQueue;\n this.#readyQueue = [];\n for (const cb of q) cb();\n }\n\n // ====== 浏览器初始化 ======\n\n #initBrowser(): void {\n if (typeof window === 'undefined') return;\n\n // 劫持容器内链接点击\n document.addEventListener('click', this.#onClick);\n\n // 浏览器前进/后退\n window.addEventListener('popstate', this.#onPopstate);\n }\n\n #initIdleSet(): void {\n for (const path of Object.keys(this.routes)) {\n if (this.routes[path].status === 'idle') {\n this.idleSet.add(path);\n }\n }\n // 移除首屏路径\n if (this.active) {\n this.idleSet.delete(this.active.path);\n }\n }\n\n // ====== 五个公开方法 ======\n\n /** 导航到新页面(追加历史记录) */\n async pushState(url: string): Promise<void> {\n const result = match(url, this.routes);\n if (!result) return;\n\n const target: RouteEntry = { path: url, params: result.params };\n // 截断当前位置之后的历史,再追加\n this.stack.length = this.stackIndex + 1;\n this.stack.push(target);\n this.stackIndex = this.stack.length - 1;\n await this.#navigate(target);\n }\n\n /** 替换当前页面(不追加历史记录) */\n async replaceState(url: string): Promise<void> {\n const result = match(url, this.routes);\n if (!result) return;\n\n const target: RouteEntry = { path: url, params: result.params };\n this.stack[this.stackIndex] = target;\n await this.#navigate(target, { replace: true });\n }\n\n /** 后退 */\n async back(): Promise<void> {\n if (this.stackIndex <= 0) return;\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n\n const target = this.stack[this.stackIndex - 1];\n if (!(await this.#checkGuard(target, 'enter'))) return;\n\n history.back(); // popstate 触发 Index 同步\n }\n\n /** 前进 */\n async forward(): Promise<void> {\n if (this.stackIndex >= this.stack.length - 1) return;\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n\n const target = this.stack[this.stackIndex + 1];\n if (!(await this.#checkGuard(target, 'enter'))) return;\n\n history.forward(); // popstate 触发 Index 同步\n }\n\n /** 跳转多步 */\n async go(delta: number): Promise<void> {\n if (delta === 0) return;\n const newIdx = this.stackIndex + delta;\n if (newIdx < 0 || newIdx >= this.stack.length) return;\n\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n if (!(await this.#checkGuard(this.stack[newIdx], 'enter'))) return;\n\n history.go(delta);\n }\n\n // ====== 内部实现 ======\n\n private navId = 0;\n\n async #navigate(target: RouteEntry, opts: { replace?: boolean } = {}): Promise<void> {\n const id = ++this.navId;\n\n if (!(await this.#checkGuard(this.active!, 'leave'))) return;\n if (id !== this.navId) return; // 守卫期间有新导航,丢弃本次\n if (!(await this.#checkGuard(target, 'enter'))) return;\n if (id !== this.navId) return;\n\n // 保存当前页滚动位置\n if (this.active && this.stack[this.stackIndex]) {\n this.stack[this.stackIndex].scroll = window.scrollY;\n }\n\n if (!opts.replace) {\n history.pushState(null, '', target.path);\n } else {\n history.replaceState(null, '', target.path);\n }\n\n // 加载组件\n await this.#loadComponent(target.path);\n if (id !== this.navId) return; // 加载期间有新导航,丢弃本次\n\n target.component = this.routes[target.path]?.component;\n this.active = target;\n\n // hash 滚动\n const hash = new URL(target.path, location.origin).hash;\n if (hash) {\n const el = document.querySelector(decodeURIComponent(hash));\n if (el) (el as HTMLElement).scrollIntoView({ behavior: 'smooth' });\n }\n\n this.#preloadNext();\n }\n\n async #checkGuard(\n entry: RouteEntry,\n type: 'enter' | 'leave'\n ): Promise<boolean> {\n if (type === 'enter' && this.enterGuard) {\n const result = await this.enterGuard(entry);\n if (result === false) return false;\n if (typeof result === 'object' && !result.ok) return false;\n }\n if (type === 'leave' && this.leaveGuard) {\n const result = await this.leaveGuard(entry);\n if (result === false) return false;\n if (typeof result === 'object' && !result.ok) return false;\n }\n return true;\n }\n\n // ====== 组件异步加载 ======\n\n async #loadComponent(path: string): Promise<any> {\n const route = this.routes[path];\n if (!route) return undefined;\n\n switch (route.status) {\n case 'loaded':\n return route.component;\n case 'loading':\n return route.promise;\n case 'error':\n break; // 可重试\n case 'idle':\n break;\n }\n\n if (!route.import) {\n throw new Error(`Route \"${path}\" has no import function`);\n }\n\n this.idleSet.delete(path);\n route.status = 'loading';\n route.promise = route\n .import()\n .then((mod: any) => {\n const Comp = mod.default || mod;\n route.status = 'loaded';\n route.component = Comp;\n return route.component;\n })\n .catch((err) => {\n route.status = 'error';\n throw err;\n })\n .finally(() => {\n this.loadingCount--;\n this.#preloadNext();\n });\n\n return route.promise;\n }\n\n // ====== 空闲预加载 ======\n\n #preloadNext(): void {\n while (this.loadingCount < this.maxPreload && this.idleSet.size > 0) {\n const path = this.idleSet.values().next().value!;\n this.loadingCount++;\n const scheduler =\n typeof requestIdleCallback !== 'undefined'\n ? requestIdleCallback\n : (fn: () => void) => setTimeout(fn, 0);\n scheduler(() => {\n this.#loadComponent(path);\n });\n }\n }\n\n // ====== 链接劫持 ======\n\n #onClick = (e: MouseEvent): void => {\n const link = (e.target as Element).closest('a');\n if (!link) return;\n\n const href = link.getAttribute('href');\n if (!href) return;\n\n // 纯 hash 链接放行,浏览器原生处理滚动\n if (href.startsWith('#')) return;\n\n try {\n const url = new URL(href, location.origin);\n // 外部链接不拦截\n if (url.origin !== location.origin) return;\n // 新窗口、下载、快捷键不拦截\n if (link.target === '_blank') return;\n if (link.hasAttribute('download')) return;\n if (e.ctrlKey || e.metaKey || e.shiftKey) return;\n\n e.preventDefault();\n this.pushState(url.pathname + url.search + url.hash);\n } catch {\n // 无效 URL,不拦截\n }\n };\n\n // ====== popstate 回调 ======\n\n #onPopstate = (): void => {\n const current = location.pathname + location.search;\n const idx = this.stack.findLastIndex((r) => r.path === current);\n\n if (idx !== -1) {\n // 仅 hash 变化,浏览器已更新 URL 并处理滚动,跳过 #navigate(避免 replaceState 抹掉 hash)\n if (idx === this.stackIndex) return;\n // 在栈中 → Router 产生的历史,移动指针\n this.stackIndex = idx;\n const entry = this.stack[idx];\n this.#navigate(entry, { replace: true });\n // 恢复滚动位置\n if (entry.scroll != null) {\n window.scrollTo(0, entry.scroll);\n }\n } else {\n // 不在栈中 → 外部跳转,重置栈\n const result = match(current, this.routes);\n const entry: RouteEntry = {\n path: current,\n params: result?.params ?? {},\n };\n this.stack = [entry];\n this.stackIndex = 0;\n this.active = entry;\n }\n };\n}\n"],"names":["compilePattern","pattern","paramNames","regexStr","replace","_","name","push","regex","RegExp","params","compiledCache","cacheKey","compileRoutes","map","Object","keys","filter","k","_compilePattern","match","path","normalized","startsWith","compiled","m","i","length","GlobalKey","createRouteRecord","opts","import","component","status","Router","Store","StoreIgnoreKeys","active","routes","menus","stack","stackIndex","idleSet","Set","maxPreload","loadingCount","ready","cb","Promise","resolve","constructor","opt","initialPath","globalThis","Routes","injectedMenus","Menus","Path","location","pathname","#init","result","route","q","#initBrowser","window","document","addEventListener","#initIdleSet","add","delete","pushState","url","target","replaceState","back","history","forward","go","delta","newIdx","navId","#navigate","id","scroll","scrollY","hash","URL","origin","el","querySelector","decodeURIComponent","scrollIntoView","behavior","#checkGuard","entry","type","enterGuard","ok","leaveGuard","#loadComponent","undefined","promise","Error","then","mod","Comp","default","catch","err","finally","#preloadNext","size","values","next","value","scheduler","requestIdleCallback","fn","setTimeout","e","link","closest","href","getAttribute","hasAttribute","ctrlKey","metaKey","shiftKey","preventDefault","search","#onPopstate","current","idx","findLastIndex","r","scrollTo"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Store, StoreIgnoreKeys } from 'aoye';
|
|
2
2
|
|
|
3
|
+
/** Router 构造选项 */
|
|
4
|
+
interface RouterOptions {
|
|
5
|
+
routes?: RouteMap;
|
|
6
|
+
initialPath?: string;
|
|
7
|
+
}
|
|
3
8
|
/** 路由表中每条记录 */
|
|
4
9
|
type RouteRecord = {
|
|
5
10
|
/** 异步 import 组件的函数(客户端 SPA 用) */
|
|
@@ -32,8 +37,10 @@ type Menu = {
|
|
|
32
37
|
name: string;
|
|
33
38
|
/** 文件路径,目录有 index 时等于 dir 路径,否则为空 */
|
|
34
39
|
path?: string;
|
|
40
|
+
/** 是否有对应组件(目录无 index 时为 false) */
|
|
41
|
+
hasComponent: boolean;
|
|
35
42
|
/** 子菜单 */
|
|
36
|
-
children
|
|
43
|
+
children?: Menu[];
|
|
37
44
|
};
|
|
38
45
|
/** 路由匹配结果 */
|
|
39
46
|
type MatchResult = {
|
|
@@ -78,9 +85,16 @@ declare class Router extends Store {
|
|
|
78
85
|
maxPreload: number;
|
|
79
86
|
/** 当前正在加载的组件数 */
|
|
80
87
|
private loadingCount;
|
|
81
|
-
/**
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
/**
|
|
89
|
+
* 注册首屏就绪回调。
|
|
90
|
+
* - 已初始化 → 同步执行 cb
|
|
91
|
+
* - 未初始化 → 入队,首屏加载完成后执行
|
|
92
|
+
* 支持多次调用。
|
|
93
|
+
* 无参数时返回 Promise。
|
|
94
|
+
*/
|
|
95
|
+
ready(): Promise<void>;
|
|
96
|
+
ready(cb: () => void): void;
|
|
97
|
+
constructor(opt?: RouterOptions);
|
|
84
98
|
/** 导航到新页面(追加历史记录) */
|
|
85
99
|
pushState(url: string): Promise<void>;
|
|
86
100
|
/** 替换当前页面(不追加历史记录) */
|