@dooboostore/simple-web-component 1.0.51 → 1.0.53
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/README.md +7 -8
- package/dist/cjs/decorators/addEventListener.js +8 -3
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/requestAnimationFrame.js +10 -2
- package/dist/cjs/decorators/requestAnimationFrame.js.map +2 -2
- package/dist/cjs/decorators/setInterval.js +4 -2
- package/dist/cjs/decorators/setInterval.js.map +2 -2
- package/dist/cjs/decorators/setTimeout.js +4 -2
- package/dist/cjs/decorators/setTimeout.js.map +2 -2
- package/dist/cjs/decorators/subscribeSwcAppMessage.js +14 -1
- package/dist/cjs/decorators/subscribeSwcAppMessage.js.map +2 -2
- package/dist/cjs/elements/SwcAppMixin.js +7 -1
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js +8 -3
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/requestAnimationFrame.js +10 -2
- package/dist/esm/decorators/requestAnimationFrame.js.map +2 -2
- package/dist/esm/decorators/setInterval.js +4 -2
- package/dist/esm/decorators/setInterval.js.map +2 -2
- package/dist/esm/decorators/setTimeout.js +4 -2
- package/dist/esm/decorators/setTimeout.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppMessage.js +14 -1
- package/dist/esm/decorators/subscribeSwcAppMessage.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +7 -1
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +44 -8
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +3 -3
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/requestAnimationFrame.d.ts +7 -4
- package/dist/types/decorators/requestAnimationFrame.d.ts.map +1 -1
- package/dist/types/decorators/setInterval.d.ts +6 -4
- package/dist/types/decorators/setInterval.d.ts.map +1 -1
- package/dist/types/decorators/setTimeout.d.ts +6 -4
- package/dist/types/decorators/setTimeout.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppMessage.d.ts +12 -0
- package/dist/types/decorators/subscribeSwcAppMessage.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +44 -8
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +3 -3
- package/package.json +2 -2
- package/src/decorators/addEventListener.ts +10 -3
- package/src/decorators/requestAnimationFrame.ts +17 -5
- package/src/decorators/setInterval.ts +9 -5
- package/src/decorators/setTimeout.ts +9 -5
- package/src/decorators/subscribeSwcAppMessage.ts +27 -0
- package/src/elements/SwcAppMixin.ts +11 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dooboostore/simple-web-component",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.53",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"dependencies": {
|
|
98
98
|
"@dooboostore/core": "1.0.33",
|
|
99
99
|
"@dooboostore/core-web": "1.0.14",
|
|
100
|
-
"@dooboostore/simple-boot": "1.0.
|
|
100
|
+
"@dooboostore/simple-boot": "1.0.59"
|
|
101
101
|
},
|
|
102
102
|
"scripts": {
|
|
103
103
|
"clean": "rm -rf dist",
|
|
@@ -1228,7 +1228,11 @@ export class EventListenerLifeCycler implements ElementDefineLifeCycler {
|
|
|
1228
1228
|
const { type, options } = meta;
|
|
1229
1229
|
const opts = { capture: options.capture, once: options.once, passive: options.passive };
|
|
1230
1230
|
|
|
1231
|
+
// event.currentTarget 은 dispatch 가 끝나면 null 이 된다 (표준). debounce/throttle 이나 async filter 뒤에 읽으면 이미 null 이라
|
|
1232
|
+
// 리스너가 불리는 순간에 잡아 둔다 → @matchedElement 가 항상 채워진다.
|
|
1233
|
+
const matchedTargets = new WeakMap<Event, EventTarget | null>();
|
|
1231
1234
|
const handler = async (event: Event) => {
|
|
1235
|
+
const matchedElement = matchedTargets.get(event) ?? event.currentTarget;
|
|
1232
1236
|
const helper = (options.filter || options.before || options.finally) ? SwcUtils.getHelperAndHostSet(target as HTMLElement, currentWin) : undefined;
|
|
1233
1237
|
if (options.filter) {
|
|
1234
1238
|
if (!(await options.filter(event, { currentThis: inst, helper }))) return;
|
|
@@ -1237,12 +1241,12 @@ export class EventListenerLifeCycler implements ElementDefineLifeCycler {
|
|
|
1237
1241
|
if (options.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
1238
1242
|
if (options.preventDefault) event.preventDefault();
|
|
1239
1243
|
const currentHostSet = SwcUtils.getHostSet(inst);
|
|
1240
|
-
const legacyArgs = [event, { currentHostSet, $matchedElement:
|
|
1244
|
+
const legacyArgs = [event, { currentHostSet, $matchedElement: matchedElement }, { event, ...currentHostSet, $el: target, $root: target }];
|
|
1241
1245
|
const currentHelperSet = SwcUtils.getHelperSet(currentWin);
|
|
1242
1246
|
const currentHelperHostSet = { ...currentHelperSet, ...currentHostSet, $this: inst };
|
|
1243
1247
|
const buildArgs = (beforeReturn: any) => buildSwcParameterArgs(inst, meta.propertyKey, {
|
|
1244
1248
|
eventObject: event,
|
|
1245
|
-
matchedElement
|
|
1249
|
+
matchedElement,
|
|
1246
1250
|
hostSet: currentHostSet,
|
|
1247
1251
|
helperHostSet: currentHelperHostSet,
|
|
1248
1252
|
helperSet: currentHelperSet,
|
|
@@ -1283,7 +1287,10 @@ export class EventListenerLifeCycler implements ElementDefineLifeCycler {
|
|
|
1283
1287
|
error: (err: any) => console.error('Event stream error:', err),
|
|
1284
1288
|
});
|
|
1285
1289
|
|
|
1286
|
-
const wrappedHandler = (event: Event) =>
|
|
1290
|
+
const wrappedHandler = (event: Event) => {
|
|
1291
|
+
matchedTargets.set(event, event.currentTarget);
|
|
1292
|
+
eventSubject.next(event);
|
|
1293
|
+
};
|
|
1287
1294
|
target.addEventListener(type, wrappedHandler, opts);
|
|
1288
1295
|
|
|
1289
1296
|
const onRemoves: Array<{ fn: any; opts: any }> =
|
|
@@ -9,8 +9,8 @@ export type RequestAnimationFrameType = 'onConnected' | 'returnValue';
|
|
|
9
9
|
|
|
10
10
|
export interface RequestAnimationFrameOptions {
|
|
11
11
|
/**
|
|
12
|
-
* 'onConnected' - connect 시 자동으로 루프 시작 (매 프레임 데코레이트된 메서드를 직접 호출), disconnect 시 자동 정리.
|
|
13
|
-
* 'returnValue'
|
|
12
|
+
* 'onConnected'(기본값) - connect 시 자동으로 루프 시작 (매 프레임 데코레이트된 메서드를 직접 호출), disconnect 시 자동 정리.
|
|
13
|
+
* 'returnValue' - 자동 시작 없음. 개발자가 이 메서드를 직접 호출해야 시작되고,
|
|
14
14
|
* 그 호출의 리턴값(또는 valueKey로 뽑은 값)이 실제로 매 프레임 호출될 함수가 된다.
|
|
15
15
|
*/
|
|
16
16
|
type?: RequestAnimationFrameType;
|
|
@@ -63,7 +63,7 @@ const startFrameLoop = (win: Window, entries: number[], frameFn: FrameCallback):
|
|
|
63
63
|
|
|
64
64
|
const applyRequestAnimationFrame = (options: RequestAnimationFrameOptions, target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor): PropertyDescriptor | void => {
|
|
65
65
|
const constructor = target.constructor;
|
|
66
|
-
const normalizedOptions: RequestAnimationFrameOptions = { ...options, type: options.type ?? '
|
|
66
|
+
const normalizedOptions: RequestAnimationFrameOptions = { ...options, type: options.type ?? 'onConnected' };
|
|
67
67
|
|
|
68
68
|
let metaList = ReflectUtils.getOwnMetadata(REQUEST_ANIMATION_FRAME_METADATA_KEY, constructor) as RequestAnimationFrameMetadata[];
|
|
69
69
|
if (!metaList) {
|
|
@@ -96,8 +96,8 @@ const applyRequestAnimationFrame = (options: RequestAnimationFrameOptions, targe
|
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
* type:'onConnected' - connect 시 자동으로 매 프레임 루프를 시작하고, disconnect 시 자동으로 cancelAnimationFrame 한다.
|
|
100
|
-
* type:'returnValue'(
|
|
99
|
+
* type:'onConnected'(기본값) - connect 시 자동으로 매 프레임 루프를 시작하고, disconnect 시 자동으로 cancelAnimationFrame 한다.
|
|
100
|
+
* type:'returnValue' (@requestAnimationFrameReturnValue) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
|
|
101
101
|
* 그대로 실행하고 리턴값(또는 valueKey로 뽑은 값)이 함수면 그 함수를 매 프레임 호출되는 루프로 등록한다.
|
|
102
102
|
* 원본 리턴값은 그대로 통과시키므로 다른 데코레이터와 같은 메서드에 스택해도 순서에 상관없이 안전하다.
|
|
103
103
|
*
|
|
@@ -147,3 +147,15 @@ export class RequestAnimationFrameLifeCycler implements ElementDefineLifeCycler
|
|
|
147
147
|
inst.__swc_requestAnimationFrameIds = [];
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
+
|
|
151
|
+
/** 수동 시작: 메서드를 직접 호출해야 시작되고, 그 리턴 함수가 매 프레임 돈다. = @requestAnimationFrame({ type: 'returnValue' }) */
|
|
152
|
+
export function requestAnimationFrameReturnValue(options: Omit<RequestAnimationFrameOptions, 'type'>): MethodDecorator;
|
|
153
|
+
export function requestAnimationFrameReturnValue(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
154
|
+
export function requestAnimationFrameReturnValue(optionsOrTarget?: Omit<RequestAnimationFrameOptions, 'type'> | Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): MethodDecorator | void {
|
|
155
|
+
if (propertyKey !== undefined) {
|
|
156
|
+
applyRequestAnimationFrame({ type: 'returnValue' }, optionsOrTarget as Object, propertyKey, descriptor);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) =>
|
|
160
|
+
applyRequestAnimationFrame({ ...((optionsOrTarget as RequestAnimationFrameOptions) ?? {}), type: 'returnValue' }, target, propertyKey, descriptor);
|
|
161
|
+
}
|
|
@@ -10,8 +10,8 @@ export type SetIntervalType = 'onConnected' | 'returnValue';
|
|
|
10
10
|
|
|
11
11
|
export interface SetIntervalOptions {
|
|
12
12
|
/**
|
|
13
|
-
* 'onConnected' (connect 시 자동으로 시작, disconnect 시 자동 정리) |
|
|
14
|
-
* 'returnValue' (
|
|
13
|
+
* 'onConnected' (기본값 - connect 시 자동으로 시작, disconnect 시 자동 정리) |
|
|
14
|
+
* 'returnValue' (자동 시작 없음. 개발자가 이 메서드를 직접 호출해야 시작되고,
|
|
15
15
|
* 그 호출의 리턴값이 실제로 반복 실행될 함수가 된다 - 아래 설명 참고).
|
|
16
16
|
*/
|
|
17
17
|
type?: SetIntervalType;
|
|
@@ -43,8 +43,8 @@ export interface SetIntervalMetadata {
|
|
|
43
43
|
const getActiveEntries = (inst: any): number[] => (inst.__swc_intervalIds ??= []);
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* type:'onConnected' - connect 시 자동으로 setInterval을 걸고, disconnect 시 자동으로 clearInterval 한다.
|
|
47
|
-
* type:'returnValue'(
|
|
46
|
+
* type:'onConnected'(기본값) - connect 시 자동으로 setInterval을 걸고, disconnect 시 자동으로 clearInterval 한다.
|
|
47
|
+
* type:'returnValue' (@setIntervalReturnValue) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
|
|
48
48
|
* 그대로 실행하고 리턴값(또는 valueKey로 뽑은 값)이 함수면 그 함수를 새 setInterval의 반복 콜백으로 등록한다.
|
|
49
49
|
* 호출할 때마다 별도의 새 타이머가 생기며, disconnect 시 전부 정리된다. 원본 리턴값은 그대로 통과시키므로
|
|
50
50
|
* 다른 데코레이터와 같은 메서드에 스택해도 순서에 상관없이 안전하다.
|
|
@@ -52,7 +52,7 @@ const getActiveEntries = (inst: any): number[] => (inst.__swc_intervalIds ??= []
|
|
|
52
52
|
export function setInterval(interval: number, options: SetIntervalOptions = {}): MethodDecorator {
|
|
53
53
|
return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
|
|
54
54
|
const constructor = target.constructor;
|
|
55
|
-
const normalizedOptions: SetIntervalOptions = { ...options, type: options.type ?? '
|
|
55
|
+
const normalizedOptions: SetIntervalOptions = { ...options, type: options.type ?? 'onConnected' };
|
|
56
56
|
|
|
57
57
|
let metaList = ReflectUtils.getOwnMetadata(SET_INTERVAL_METADATA_KEY, constructor) as SetIntervalMetadata[];
|
|
58
58
|
if (!metaList) {
|
|
@@ -145,3 +145,7 @@ export class SetIntervalLifeCycler implements ElementDefineLifeCycler {
|
|
|
145
145
|
inst.__swc_intervalIds = [];
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
|
|
149
|
+
/** 수동 시작: 메서드를 직접 호출해야 시작된다. = @setInterval(interval, { type: 'returnValue' }) */
|
|
150
|
+
export const setIntervalReturnValue = (interval: number, options: Omit<SetIntervalOptions, 'type'> = {}): MethodDecorator =>
|
|
151
|
+
setInterval(interval, { ...options, type: 'returnValue' });
|
|
@@ -10,8 +10,8 @@ export type SetTimeoutType = 'onConnected' | 'returnValue';
|
|
|
10
10
|
|
|
11
11
|
export interface SetTimeoutOptions {
|
|
12
12
|
/**
|
|
13
|
-
* 'onConnected' (connect 시 자동으로 예약, disconnect 시 자동 정리) |
|
|
14
|
-
* 'returnValue' (
|
|
13
|
+
* 'onConnected' (기본값 - connect 시 자동으로 예약, disconnect 시 자동 정리) |
|
|
14
|
+
* 'returnValue' (자동 예약 없음. 개발자가 이 메서드를 직접 호출해야 예약되고,
|
|
15
15
|
* 그 호출의 리턴값이 실제로 실행될 함수가 된다 - 아래 설명 참고).
|
|
16
16
|
*/
|
|
17
17
|
type?: SetTimeoutType;
|
|
@@ -43,8 +43,8 @@ export interface SetTimeoutMetadata {
|
|
|
43
43
|
const getActiveEntries = (inst: any): number[] => (inst.__swc_timeoutIds ??= []);
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* type:'onConnected' - connect 시 자동으로 setTimeout을 걸고, disconnect 시 (아직 실행 전이라면) 자동으로 clearTimeout 한다.
|
|
47
|
-
* type:'returnValue'(
|
|
46
|
+
* type:'onConnected'(기본값) - connect 시 자동으로 setTimeout을 걸고, disconnect 시 (아직 실행 전이라면) 자동으로 clearTimeout 한다.
|
|
47
|
+
* type:'returnValue' (@setTimeoutReturnValue) - 메서드를 감싸지 않는 대신, 호출될 때마다(개발자가 직접 호출) 원본 로직을
|
|
48
48
|
* 그대로 실행하고 리턴값(또는 valueKey로 뽑은 값)이 함수면 그 함수를 새 setTimeout으로 예약한다.
|
|
49
49
|
* 호출할 때마다 별도의 새 타이머가 생기며, disconnect 시 (아직 실행 전인 것들은) 전부 정리된다.
|
|
50
50
|
* 원본 리턴값은 그대로 통과시키므로 다른 데코레이터와 같은 메서드에 스택해도 순서에 상관없이 안전하다.
|
|
@@ -52,7 +52,7 @@ const getActiveEntries = (inst: any): number[] => (inst.__swc_timeoutIds ??= [])
|
|
|
52
52
|
export function setTimeout(delay: number, options: SetTimeoutOptions = {}): MethodDecorator {
|
|
53
53
|
return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
|
|
54
54
|
const constructor = target.constructor;
|
|
55
|
-
const normalizedOptions: SetTimeoutOptions = { ...options, type: options.type ?? '
|
|
55
|
+
const normalizedOptions: SetTimeoutOptions = { ...options, type: options.type ?? 'onConnected' };
|
|
56
56
|
|
|
57
57
|
let metaList = ReflectUtils.getOwnMetadata(SET_TIMEOUT_METADATA_KEY, constructor) as SetTimeoutMetadata[];
|
|
58
58
|
if (!metaList) {
|
|
@@ -148,3 +148,7 @@ export class SetTimeoutLifeCycler implements ElementDefineLifeCycler {
|
|
|
148
148
|
inst.__swc_timeoutIds = [];
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
+
|
|
152
|
+
/** 수동 예약: 메서드를 직접 호출해야 예약된다. = @setTimeout(delay, { type: 'returnValue' }) */
|
|
153
|
+
export const setTimeoutReturnValue = (delay: number, options: Omit<SetTimeoutOptions, 'type'> = {}): MethodDecorator =>
|
|
154
|
+
setTimeout(delay, { ...options, type: 'returnValue' });
|
|
@@ -82,6 +82,33 @@ export function subscribeSwcAppMessage(targetOrMessageTypeOrOptions?: any, optio
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
export const receiveMessage = subscribeSwcAppMessage;
|
|
85
|
+
|
|
86
|
+
// ── subject 를 이름에 박은 별칭: @subscribeSwcAppMessageBehavior('auth') = @subscribeSwcAppMessage('auth', { subject: 'behavior' }) ──
|
|
87
|
+
type SubjectlessOptions<Data, BeforeReturn, Result> = Omit<SwcAppMessageOptions<Data, BeforeReturn, Result>, 'subject'>;
|
|
88
|
+
|
|
89
|
+
const withSubject = (subject: SwcAppMessageSubject, a?: any, b?: any, descriptor?: PropertyDescriptor): any => {
|
|
90
|
+
if (descriptor) return createSubscribeSwcAppMessage({ subject })(a, b, descriptor); // 괄호 없이
|
|
91
|
+
if (typeof a === 'string') return createSubscribeSwcAppMessage({ ...(b ?? {}), subject }, a);
|
|
92
|
+
return createSubscribeSwcAppMessage({ ...(a ?? {}), subject });
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/** 늦게 붙어도 마지막 메시지 1개를 받는다 (subject: 'behavior') */
|
|
96
|
+
export function subscribeSwcAppMessageBehavior(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
97
|
+
export function subscribeSwcAppMessageBehavior(messageType: string): MethodDecorator;
|
|
98
|
+
export function subscribeSwcAppMessageBehavior<Data = any, BeforeReturn = any, Result = any>(options: SubjectlessOptions<NoInfer<Data>, NoInfer<BeforeReturn>, NoInfer<Result>>): MethodDecorator;
|
|
99
|
+
export function subscribeSwcAppMessageBehavior<Data = any, BeforeReturn = any, Result = any>(messageType: string, options: SubjectlessOptions<NoInfer<Data>, NoInfer<BeforeReturn>, NoInfer<Result>>): MethodDecorator;
|
|
100
|
+
export function subscribeSwcAppMessageBehavior(a?: any, b?: any, descriptor?: PropertyDescriptor): any {
|
|
101
|
+
return withSubject('behavior', a, b, descriptor);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** 늦게 붙어도 지나간 메시지를 전부 시간순으로 받는다 (subject: 'replay') */
|
|
105
|
+
export function subscribeSwcAppMessageReplay(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
106
|
+
export function subscribeSwcAppMessageReplay(messageType: string): MethodDecorator;
|
|
107
|
+
export function subscribeSwcAppMessageReplay<Data = any, BeforeReturn = any, Result = any>(options: SubjectlessOptions<NoInfer<Data>, NoInfer<BeforeReturn>, NoInfer<Result>>): MethodDecorator;
|
|
108
|
+
export function subscribeSwcAppMessageReplay<Data = any, BeforeReturn = any, Result = any>(messageType: string, options: SubjectlessOptions<NoInfer<Data>, NoInfer<BeforeReturn>, NoInfer<Result>>): MethodDecorator;
|
|
109
|
+
export function subscribeSwcAppMessageReplay(a?: any, b?: any, descriptor?: PropertyDescriptor): any {
|
|
110
|
+
return withSubject('replay', a, b, descriptor);
|
|
111
|
+
}
|
|
85
112
|
// Helper function to retrieve message subscribers metadata
|
|
86
113
|
export const getSubscribeSwcAppMessageMetadata = (target: any): SwcAppMessageSubscriberMetadata[] | undefined => {
|
|
87
114
|
const constructor = typeof target === 'function' ? target : target.constructor;
|
|
@@ -56,6 +56,8 @@ export const setSSRAttribute = (i: HTMLElement) => {
|
|
|
56
56
|
i.setAttribute('swc-use-ssr', (i as any)._swcId ?? '');
|
|
57
57
|
};
|
|
58
58
|
export const removeSSRAttribute = (i: HTMLElement) => {
|
|
59
|
+
// 표식은 지워도 "서버가 그린 엘리먼트"였다는 건 기억한다 → 첫 라우트(같은 경로)를 다시 그리지 않게 (_invokeRouteChangeSubscribers)
|
|
60
|
+
if (isSSR(i)) (i as any).__swc_ssrRoute ??= true;
|
|
59
61
|
i.removeAttribute('swc-use-ssr');
|
|
60
62
|
};
|
|
61
63
|
|
|
@@ -142,6 +144,14 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
|
|
|
142
144
|
// live는 전부 실행, replay는 해당 trigger 구독자만 실행.
|
|
143
145
|
// on(enter/update/leave) 판정을 위해 구독자별 직전 매칭 상태를 기억한다 (멈춘 뒤에도 상태는 계속 갱신).
|
|
144
146
|
const state = routeStateOf(instance);
|
|
147
|
+
// 서버가 이미 이 경로로 그려 보낸 엘리먼트는 같은 경로에 대해 다시 그리지 않는다 (@onConnected 렌더를 건너뛰는 것과 같은 규칙).
|
|
148
|
+
// 연결 때(connected)와 라우터 시작 때(live) 두 번 오므로 경로를 기억해 둘 다 건너뛰고, 다른 경로로 가면 잊는다.
|
|
149
|
+
// 매칭 상태는 아래에서 그대로 기록해 이후 enter/update/leave 판정은 정상으로 돈다.
|
|
150
|
+
const routeSig = JSON.stringify([re.path ?? '', re.search ?? '']);
|
|
151
|
+
if (ValidUtils.isBrowser() && isSSR(instance)) (instance as any).__swc_ssrRoute ??= true;
|
|
152
|
+
if ((instance as any).__swc_ssrRoute === true) (instance as any).__swc_ssrRoute = routeSig;
|
|
153
|
+
const ssrPainted = (instance as any).__swc_ssrRoute === routeSig;
|
|
154
|
+
if (!ssrPainted) delete (instance as any).__swc_ssrRoute;
|
|
145
155
|
let stopped = false;
|
|
146
156
|
for (const metadata of routeChangeSubscribers) {
|
|
147
157
|
if (phase !== 'live' && (metadata.options?.trigger ?? 'connected') !== phase) continue;
|
|
@@ -168,7 +178,7 @@ export function SwcAppMixin<T extends { new (...args: any[]): HTMLElement }>(Bas
|
|
|
168
178
|
: on === 'update' ? !!match && !!prev?.matched && prev.signature !== signature
|
|
169
179
|
: on === 'leave' ? !match && !!prev?.matched
|
|
170
180
|
: false;
|
|
171
|
-
if (stopped || !shouldRun || !instance[methodName]) continue;
|
|
181
|
+
if (stopped || ssrPainted || !shouldRun || !instance[methodName]) continue;
|
|
172
182
|
|
|
173
183
|
// leave 는 지금 경로가 안 맞으므로 직전 매칭의 pathData 로 준다
|
|
174
184
|
const pathData = match ? match.pathData : prev?.pathData ?? {};
|