@iyulab/router 0.10.1 → 0.10.3
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/CHANGELOG.md +15 -0
- package/README.md +29 -0
- package/dist/Router.d.ts +4 -1
- package/dist/components/UErrorPage.d.ts +4 -3
- package/dist/components/ULink.d.ts +4 -3
- package/dist/index.d.ts +0 -9
- package/dist/index.js +11 -5
- package/dist/react.d.ts +3 -2
- package/dist/react.js +1 -1
- package/dist/{share-C2LbLiIW.js → share-BUgoWpfZ.js} +2 -2
- package/dist/types/RouteEvent.d.ts +11 -0
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.3] - 2026-07-24
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **root 안에 `<u-outlet>` 이 없을 때 초기화 실패가 삼켜지던 문제 수정** (U-CMMS React+Vite E2E 실측, ISSUE-20260722-router-react-consumption #1). `waitOutlet` 은 타임아웃 시 서술적 오류로 reject 하지만, `Router` 생성자가 `void waitOutlet(...).then(...)` 로 거부를 처리하지 않아 폴링 타임아웃(최대 10초) 뒤 unhandled rejection 으로만 새어 나갔다 — 소비자에겐 원인 없는 빈 화면이었다. 이제 `.catch()` 로 `console.error('Router initialization failed:', …)` 에 명시적으로 표면화한다.
|
|
7
|
+
|
|
8
|
+
### Documentation
|
|
9
|
+
- README에 "React + Vite" 섹션 추가 — 아웃렛의 `react-dom/client` 동적 import 가 Vite dev 사전번들(`optimizeDeps`)에서 깨지는 CJS interop 을 `optimizeDeps.exclude: ['@iyulab/router']` + `include: ['react-dom/client']` 로 해소하는 소비 설정 명시(초안 #2).
|
|
10
|
+
- Quick Start 에 root 의 `<u-outlet>` 요구 + 부재 시 로그 메시지 명시.
|
|
11
|
+
|
|
12
|
+
## [0.10.2] - 2026-07-15
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Click interception now reuses the route match computed while deciding whether to intercept an anchor, instead of recomputing it inside `go()` — avoids a duplicate `getRoutes` call per intercepted click
|
|
16
|
+
- Bumped `@types/node`, `@types/react`, `happy-dom`, `vite`, `vite-plugin-dts`, `vitest` devDependencies
|
|
17
|
+
|
|
3
18
|
## [0.10.1] - 2026-07-02
|
|
4
19
|
|
|
5
20
|
### Documentation
|
package/README.md
CHANGED
|
@@ -29,6 +29,35 @@ const router = new Router({
|
|
|
29
29
|
router.go('/users/1');
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
> The router renders matched output into a `<u-outlet>` inside `root`. Make sure one exists:
|
|
33
|
+
>
|
|
34
|
+
> ```html
|
|
35
|
+
> <div id="app"><u-outlet></u-outlet></div>
|
|
36
|
+
> ```
|
|
37
|
+
>
|
|
38
|
+
> If `root` contains no `<u-outlet>`, the router logs
|
|
39
|
+
> `Router initialization failed: Timed out waiting for <u-outlet>` and renders nothing.
|
|
40
|
+
|
|
41
|
+
## React + Vite
|
|
42
|
+
|
|
43
|
+
The outlet renders React content by dynamically importing `react-dom/client` when a route
|
|
44
|
+
returns a React element. Under Vite's dev pre-bundling (`optimizeDeps`), this CommonJS
|
|
45
|
+
interop can break — `TypeError: createRoot is not a function` by default, or
|
|
46
|
+
`ReferenceError: module is not defined` if only the router is excluded. Pre-bundle
|
|
47
|
+
`react-dom/client` while leaving the router itself unbundled:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// vite.config.ts
|
|
51
|
+
import { defineConfig } from 'vite';
|
|
52
|
+
|
|
53
|
+
export default defineConfig({
|
|
54
|
+
optimizeDeps: {
|
|
55
|
+
exclude: ['@iyulab/router'],
|
|
56
|
+
include: ['react-dom/client'],
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
32
61
|
## Skills Usage
|
|
33
62
|
|
|
34
63
|
Install the `iyulab-router` skill for agent-friendly package guidance.
|
package/dist/Router.d.ts
CHANGED
|
@@ -29,8 +29,11 @@ export declare class Router {
|
|
|
29
29
|
* 지정한 경로의 클라이언트 라우팅을 수행합니다. 상대경로일 경우 basepath와 조합되어 이동합니다.
|
|
30
30
|
* @param href 이동할 경로
|
|
31
31
|
* @param options 네비게이션 옵션
|
|
32
|
+
* @param routes (internal) 호출자가 이미 계산한 라우트 매칭 결과가 있으면 재사용합니다.
|
|
33
|
+
* `handleRootElementClick`이 가로채기 여부 판단을 위해 미리 계산한 결과를 전달해
|
|
34
|
+
* 동일 pathname에 대한 getRoutes 중복 호출을 피하는 용도입니다. 외부에서 사용하지 마세요.
|
|
32
35
|
*/
|
|
33
|
-
go(href: string, options?: NavigateOptions): Promise<undefined>;
|
|
36
|
+
go(href: string, options?: NavigateOptions, routes?: RouteConfig[]): Promise<undefined>;
|
|
34
37
|
/** 브라우저 히스토리 이벤트가 발생시 라우팅 처리 */
|
|
35
38
|
private handleWindowPopstate;
|
|
36
39
|
/** 클릭 이벤트에서 라우터로 처리할 앵커를 찾아 클라이언트 라우팅 수행 */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
1
|
+
import { LitElement, CSSResult } from 'lit';
|
|
2
2
|
import { RouteError } from '../types/RouteError.js';
|
|
3
|
+
import { TemplateResult } from 'lit-html';
|
|
3
4
|
/**
|
|
4
5
|
* 라우팅 중 발생한 에러 정보를 사용자에게 전달하기 위한 기본 컴포넌트 입니다.
|
|
5
6
|
*/
|
|
@@ -7,10 +8,10 @@ export declare class UErrorPage extends LitElement {
|
|
|
7
8
|
constructor(error?: RouteError);
|
|
8
9
|
/** 표시할 에러 정보 */
|
|
9
10
|
error?: RouteError;
|
|
10
|
-
render():
|
|
11
|
+
render(): TemplateResult<1>;
|
|
11
12
|
/** 기본 에러 정보 반환 */
|
|
12
13
|
private getDefaultError;
|
|
13
14
|
/** 에러 코드에 따른 기본 아이콘 반환 */
|
|
14
15
|
private getErrorIcon;
|
|
15
|
-
static styles:
|
|
16
|
+
static styles: CSSResult;
|
|
16
17
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { LitElement, PropertyValues } from 'lit';
|
|
1
|
+
import { LitElement, PropertyValues, CSSResult } from 'lit';
|
|
2
|
+
import { TemplateResult } from 'lit-html';
|
|
2
3
|
/**
|
|
3
4
|
* - 클라이언트 라우팅을 지원하는 링크 엘리먼트입니다.
|
|
4
5
|
* - 내부 링크는 클라이언트 라우팅을 수행하고, 외부 링크는 브라우저 기본 네비게이션을 사용합니다.
|
|
@@ -40,7 +41,7 @@ export declare class ULink extends LitElement {
|
|
|
40
41
|
connectedCallback(): void;
|
|
41
42
|
disconnectedCallback(): void;
|
|
42
43
|
protected willUpdate(changedProperties: PropertyValues): void;
|
|
43
|
-
render():
|
|
44
|
+
render(): TemplateResult<1>;
|
|
44
45
|
/** a 태그에 주입할 href 값을 계산합니다. */
|
|
45
46
|
private compute;
|
|
46
47
|
/**
|
|
@@ -53,5 +54,5 @@ export declare class ULink extends LitElement {
|
|
|
53
54
|
private dispatchPopstate;
|
|
54
55
|
/** basepath를 state에서 꺼내는 헬퍼 */
|
|
55
56
|
private getBasepath;
|
|
56
|
-
static styles:
|
|
57
|
+
static styles: CSSResult;
|
|
57
58
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,12 +7,3 @@ export * from './types/RouterConfig';
|
|
|
7
7
|
export * from './components/UOutlet';
|
|
8
8
|
export * from './components/ULink';
|
|
9
9
|
export { Router } from './Router';
|
|
10
|
-
|
|
11
|
-
declare global {
|
|
12
|
-
interface WindowEventMap {
|
|
13
|
-
'route-begin': RouteBeginEvent;
|
|
14
|
-
'route-progress': RouteProgressEvent;
|
|
15
|
-
'route-done': RouteDoneEvent;
|
|
16
|
-
'route-error': RouteErrorEvent;
|
|
17
|
-
}
|
|
18
|
-
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as isExternalUrl, i as absolutePath, n as __decorate, o as parseUrl, r as __decorateMetadata, s as UOutlet, t as ULink } from "./share-
|
|
1
|
+
import { a as isExternalUrl, i as absolutePath, n as __decorate, o as parseUrl, r as __decorateMetadata, s as UOutlet, t as ULink } from "./share-BUgoWpfZ.js";
|
|
2
2
|
import { LitElement, css, html } from "lit";
|
|
3
3
|
import { customElement, property } from "lit/decorators.js";
|
|
4
4
|
//#region src/types/RouteError.ts
|
|
@@ -403,9 +403,10 @@ var Router = class {
|
|
|
403
403
|
if (anchor.target && anchor.target !== "") return;
|
|
404
404
|
const pathname = new URL(anchor.href).pathname;
|
|
405
405
|
if (this._basepath !== "/" && !pathname.startsWith(this._basepath)) return;
|
|
406
|
-
|
|
406
|
+
const routes = getRoutes(this._routes, pathname);
|
|
407
|
+
if (routes.length === 0) return;
|
|
407
408
|
e.preventDefault();
|
|
408
|
-
await this.go(anchor.href);
|
|
409
|
+
await this.go(anchor.href, void 0, routes);
|
|
409
410
|
} catch {}
|
|
410
411
|
};
|
|
411
412
|
this.destroy();
|
|
@@ -418,6 +419,8 @@ var Router = class {
|
|
|
418
419
|
if (config.useIntercept !== false) this._rootElement.addEventListener("click", this.handleRootElementClick);
|
|
419
420
|
if (config.initialLoad !== false) waitOutlet(this._rootElement).then(() => {
|
|
420
421
|
this.go(window.location.href);
|
|
422
|
+
}).catch((error) => {
|
|
423
|
+
console.error("Router initialization failed:", error instanceof Error ? error.message : error);
|
|
421
424
|
});
|
|
422
425
|
}
|
|
423
426
|
/** 객체를 정리하고 이벤트 리스너를 제거합니다. */
|
|
@@ -443,8 +446,11 @@ var Router = class {
|
|
|
443
446
|
* 지정한 경로의 클라이언트 라우팅을 수행합니다. 상대경로일 경우 basepath와 조합되어 이동합니다.
|
|
444
447
|
* @param href 이동할 경로
|
|
445
448
|
* @param options 네비게이션 옵션
|
|
449
|
+
* @param routes (internal) 호출자가 이미 계산한 라우트 매칭 결과가 있으면 재사용합니다.
|
|
450
|
+
* `handleRootElementClick`이 가로채기 여부 판단을 위해 미리 계산한 결과를 전달해
|
|
451
|
+
* 동일 pathname에 대한 getRoutes 중복 호출을 피하는 용도입니다. 외부에서 사용하지 마세요.
|
|
446
452
|
*/
|
|
447
|
-
async go(href, options) {
|
|
453
|
+
async go(href, options, routes) {
|
|
448
454
|
if (!options?.isRedirect) this._tracker.reset();
|
|
449
455
|
const requestID = getRandomID();
|
|
450
456
|
this._requestID = requestID;
|
|
@@ -461,7 +467,7 @@ var Router = class {
|
|
|
461
467
|
let title = void 0;
|
|
462
468
|
try {
|
|
463
469
|
outlet = findOutletOrThrow(this._rootElement);
|
|
464
|
-
|
|
470
|
+
routes ??= getRoutes(this._routes, context.pathname);
|
|
465
471
|
if (routes.length === 0) throw new NotFoundError(context.href);
|
|
466
472
|
const lastRoute = routes[routes.length - 1];
|
|
467
473
|
if (lastRoute.path instanceof URLPattern) context.params = lastRoute.path.exec({ pathname: context.pathname })?.pathname.groups || {};
|
package/dist/react.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ULink as ULinkElement } from './components/ULink.js';
|
|
2
2
|
import { UOutlet as UOutletElement } from './components/UOutlet.js';
|
|
3
|
+
import { ReactWebComponent } from '@lit/react';
|
|
3
4
|
/**
|
|
4
5
|
* `u-link` 웹 컴포넌트를 React에서 사용할 수 있도록 래핑한 컴포넌트입니다.
|
|
5
6
|
*/
|
|
6
|
-
export declare const ULink:
|
|
7
|
+
export declare const ULink: ReactWebComponent<ULinkElement, {}>;
|
|
7
8
|
/**
|
|
8
9
|
* `u-outlet` 웹 컴포넌트를 React에서 사용할 수 있도록 래핑한 컴포넌트입니다.
|
|
9
10
|
*/
|
|
10
|
-
export declare const UOutlet:
|
|
11
|
+
export declare const UOutlet: ReactWebComponent<UOutletElement, {}>;
|
package/dist/react.js
CHANGED
|
@@ -126,12 +126,12 @@ function catchBasepath(basepath) {
|
|
|
126
126
|
return basepath;
|
|
127
127
|
}
|
|
128
128
|
//#endregion
|
|
129
|
-
//#region \0@oxc-project+runtime@0.
|
|
129
|
+
//#region \0@oxc-project+runtime@0.139.0/helpers/esm/decorateMetadata.js
|
|
130
130
|
function __decorateMetadata(k, v) {
|
|
131
131
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
132
132
|
}
|
|
133
133
|
//#endregion
|
|
134
|
-
//#region \0@oxc-project+runtime@0.
|
|
134
|
+
//#region \0@oxc-project+runtime@0.139.0/helpers/esm/decorate.js
|
|
135
135
|
function __decorate(decorators, target, key, desc) {
|
|
136
136
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
137
137
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -40,4 +40,15 @@ export declare class RouteErrorEvent extends RouteEvent {
|
|
|
40
40
|
readonly error: RouteError;
|
|
41
41
|
constructor(context: RouteContext, error: RouteError);
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* 전역 WindowEventMap에 라우터 이벤트 타입
|
|
45
|
+
*/
|
|
46
|
+
declare global {
|
|
47
|
+
interface WindowEventMap {
|
|
48
|
+
'route-begin': RouteBeginEvent;
|
|
49
|
+
'route-progress': RouteProgressEvent;
|
|
50
|
+
'route-done': RouteDoneEvent;
|
|
51
|
+
'route-error': RouteErrorEvent;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
43
54
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/router",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "A modern client-side router for web applications with support for Lit and React components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lit",
|
|
@@ -59,13 +59,13 @@
|
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@types/node": "^
|
|
63
|
-
"@types/react": "^19.2.
|
|
62
|
+
"@types/node": "^26.1.1",
|
|
63
|
+
"@types/react": "^19.2.17",
|
|
64
64
|
"@types/react-dom": "^19.2.3",
|
|
65
|
-
"happy-dom": "^20.10.
|
|
65
|
+
"happy-dom": "^20.10.6",
|
|
66
66
|
"typescript": "^5.9.3",
|
|
67
|
-
"vite": "^8.
|
|
68
|
-
"vite-plugin-dts": "^5.0.
|
|
69
|
-
"vitest": "^4.1.
|
|
67
|
+
"vite": "^8.1.4",
|
|
68
|
+
"vite-plugin-dts": "^5.0.3",
|
|
69
|
+
"vitest": "^4.1.10"
|
|
70
70
|
}
|
|
71
71
|
}
|