@dooboostore/simple-boot-http-server-ssr 1.0.16 → 1.0.18
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 +87 -38
- package/dist/cjs/bundle-entry.js +46 -12
- package/dist/cjs/bundle-entry.js.map +2 -2
- package/dist/cjs/filters/SSRDomParserFilter.js +4 -3
- package/dist/cjs/filters/SSRDomParserFilter.js.map +2 -2
- package/dist/cjs/filters/SSRFilter.js +4 -3
- package/dist/cjs/filters/SSRFilter.js.map +2 -2
- package/dist/cjs/filters/SSRLinkDomFilter.js +4 -3
- package/dist/cjs/filters/SSRLinkDomFilter.js.map +2 -2
- package/dist/cjs/filters/SSRSimpleWebComponentDomParserFilter.js +50 -2
- package/dist/cjs/filters/SSRSimpleWebComponentDomParserFilter.js.map +2 -2
- package/dist/cjs/filters/SSRSimpleWebComponentFilter.js.map +1 -1
- package/dist/esm/bundle-entry.js +22 -6
- package/dist/esm/bundle-entry.js.map +2 -2
- package/dist/esm/filters/SSRDomParserFilter.js +5 -4
- package/dist/esm/filters/SSRDomParserFilter.js.map +2 -2
- package/dist/esm/filters/SSRFilter.js +4 -3
- package/dist/esm/filters/SSRFilter.js.map +2 -2
- package/dist/esm/filters/SSRLinkDomFilter.js +4 -3
- package/dist/esm/filters/SSRLinkDomFilter.js.map +2 -2
- package/dist/esm/filters/SSRSimpleWebComponentDomParserFilter.js +50 -2
- package/dist/esm/filters/SSRSimpleWebComponentDomParserFilter.js.map +2 -2
- package/dist/esm/filters/SSRSimpleWebComponentFilter.js.map +1 -1
- package/dist/esm-bundle/dooboostore-simple-boot-http-server-ssr.esm.js +33495 -24465
- package/dist/esm-bundle/dooboostore-simple-boot-http-server-ssr.esm.js.map +4 -4
- package/dist/types/bundle-entry.d.ts +11 -6
- package/dist/types/bundle-entry.d.ts.map +1 -1
- package/dist/types/filters/SSRDomParserFilter.d.ts.map +1 -1
- package/dist/types/filters/SSRFilter.d.ts.map +1 -1
- package/dist/types/filters/SSRLinkDomFilter.d.ts.map +1 -1
- package/dist/types/filters/SSRSimpleWebComponentDomParserFilter.d.ts +14 -2
- package/dist/types/filters/SSRSimpleWebComponentDomParserFilter.d.ts.map +1 -1
- package/dist/types/filters/SSRSimpleWebComponentFilter.d.ts +1 -1
- package/dist/types/filters/SSRSimpleWebComponentFilter.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-boot-http-server-ssr.umd.js +32485 -23456
- package/dist/umd-bundle/dooboostore-simple-boot-http-server-ssr.umd.js.map +4 -4
- package/package.json +12 -12
- package/src/bundle-entry.ts +16 -6
- package/src/filters/SSRDomParserFilter.ts +5 -4
- package/src/filters/SSRFilter.ts +4 -3
- package/src/filters/SSRLinkDomFilter.ts +4 -3
- package/src/filters/SSRSimpleWebComponentDomParserFilter.ts +81 -5
- package/src/filters/SSRSimpleWebComponentFilter.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dooboostore/simple-boot-http-server-ssr",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -86,21 +86,21 @@
|
|
|
86
86
|
"esbuild-plugin-tsc": "^0.5.0",
|
|
87
87
|
"raw-loader": "^4.0.2",
|
|
88
88
|
"tslib": "^2.8.1",
|
|
89
|
-
"typescript": "^5.9.2"
|
|
90
|
-
"@dooboostore/core": "1.0.32",
|
|
91
|
-
"@dooboostore/core-web": "1.0.12",
|
|
92
|
-
"@dooboostore/simple-boot": "1.0.56",
|
|
93
|
-
"@dooboostore/dom-render": "1.0.113",
|
|
94
|
-
"@dooboostore/dom-parser": "1.0.7",
|
|
95
|
-
"@dooboostore/simple-boot-front": "1.0.131",
|
|
96
|
-
"@dooboostore/simple-boot-http-server": "1.0.25",
|
|
97
|
-
"@dooboostore/simple-web-component": "1.0.37",
|
|
98
|
-
"@dooboostore/core-node": "1.0.12"
|
|
89
|
+
"typescript": "^5.9.2"
|
|
99
90
|
},
|
|
100
91
|
"dependencies": {
|
|
101
92
|
"jsdom": "^26.0.0",
|
|
102
93
|
"linkedom": "0.18.12",
|
|
103
|
-
"playwright": "^1.59.1"
|
|
94
|
+
"playwright": "^1.59.1",
|
|
95
|
+
"@dooboostore/core-web": "1.0.14",
|
|
96
|
+
"@dooboostore/core-node": "1.0.14",
|
|
97
|
+
"@dooboostore/core": "1.0.33",
|
|
98
|
+
"@dooboostore/dom-render": "1.0.115",
|
|
99
|
+
"@dooboostore/dom-parser": "1.0.8",
|
|
100
|
+
"@dooboostore/simple-boot": "1.0.58",
|
|
101
|
+
"@dooboostore/simple-boot-front": "1.0.133",
|
|
102
|
+
"@dooboostore/simple-boot-http-server": "1.0.28",
|
|
103
|
+
"@dooboostore/simple-web-component": "1.0.51"
|
|
104
104
|
},
|
|
105
105
|
"scripts": {
|
|
106
106
|
"clean": "rm -rf dist",
|
package/src/bundle-entry.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export * from './
|
|
5
|
-
|
|
6
|
-
export
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
|
|
3
|
+
// simple-boot-http-server-ssr itself
|
|
4
|
+
export * from './index';
|
|
5
|
+
|
|
6
|
+
// Re-export peer dependencies so bundle consumers can access them
|
|
7
|
+
// without separately importing each package
|
|
8
|
+
export * as Core from '@dooboostore/core';
|
|
9
|
+
export * as CoreNode from '@dooboostore/core-node';
|
|
10
|
+
export * as CoreWeb from '@dooboostore/core-web';
|
|
11
|
+
export * as DomParser from '@dooboostore/dom-parser';
|
|
12
|
+
export * as DomRender from '@dooboostore/dom-render';
|
|
13
|
+
export * as SimpleBoot from '@dooboostore/simple-boot';
|
|
14
|
+
export * as SimpleBootFront from '@dooboostore/simple-boot-front';
|
|
15
|
+
export * as SimpleBootHttpServer from '@dooboostore/simple-boot-http-server';
|
|
16
|
+
export * as SimpleWebComponent from '@dooboostore/simple-web-component';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { RequestResponse } from '@dooboostore/simple-boot-http-server/models/RequestResponse';
|
|
2
2
|
import { HttpHeaders } from '@dooboostore/simple-boot-http-server/codes/HttpHeaders';
|
|
3
3
|
import { SimpleBootHttpSSRFactory } from '../SimpleBootHttpSSRFactory';
|
|
4
|
-
import { ConstructorType, AsyncBlockingQueue, RandomUtils,
|
|
4
|
+
import { ConstructorType, AsyncBlockingQueue, RandomUtils, firstValueFrom } from '@dooboostore/core';
|
|
5
|
+
import { filter, first } from '@dooboostore/core/message/operators';
|
|
5
6
|
import { Filter } from '@dooboostore/simple-boot-http-server/filters/Filter';
|
|
6
7
|
import { Mimes } from '@dooboostore/simple-boot-http-server/codes/Mimes';
|
|
7
8
|
import { HttpStatus } from '@dooboostore/simple-boot-http-server/codes/HttpStatus';
|
|
@@ -144,15 +145,15 @@ export class SSRDomParserFilter implements Filter {
|
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
const data = await
|
|
148
|
+
const data = await firstValueFrom(
|
|
148
149
|
simpleBootFront.routingObservable.pipe(
|
|
149
|
-
|
|
150
|
+
filter(it => {
|
|
150
151
|
|
|
151
152
|
const sw = it.triggerPoint === 'end' && typeof it.routerModule.intent.uri === 'string' && targetUrl.endsWith(it.routerModule.intent.uri);
|
|
152
153
|
return sw;
|
|
153
154
|
}),
|
|
154
155
|
// delay(1000),
|
|
155
|
-
|
|
156
|
+
first()
|
|
156
157
|
)
|
|
157
158
|
);
|
|
158
159
|
|
package/src/filters/SSRFilter.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { RequestResponse } from '@dooboostore/simple-boot-http-server/models/RequestResponse';
|
|
2
2
|
import { HttpHeaders } from '@dooboostore/simple-boot-http-server/codes/HttpHeaders';
|
|
3
3
|
import { SimpleBootHttpSSRFactory } from '../SimpleBootHttpSSRFactory';
|
|
4
|
-
import { ConstructorType, AsyncBlockingQueue, RandomUtils,
|
|
4
|
+
import { ConstructorType, AsyncBlockingQueue, RandomUtils, firstValueFrom } from '@dooboostore/core';
|
|
5
|
+
import { first } from '@dooboostore/core/message/operators';
|
|
5
6
|
import { JsdomInitializer } from '../initializers/JsdomInitializer';
|
|
6
7
|
import { Filter } from '@dooboostore/simple-boot-http-server/filters/Filter';
|
|
7
8
|
import { Mimes } from '@dooboostore/simple-boot-http-server/codes/Mimes';
|
|
@@ -162,7 +163,7 @@ export class SSRFilter implements Filter {
|
|
|
162
163
|
// // delay(1000),
|
|
163
164
|
// first()
|
|
164
165
|
// );
|
|
165
|
-
const data = await
|
|
166
|
+
const data = await firstValueFrom(
|
|
166
167
|
// @ts-ignore
|
|
167
168
|
simpleBootFront.routingObservable.pipe(
|
|
168
169
|
// @ts-ignore
|
|
@@ -173,7 +174,7 @@ export class SSRFilter implements Filter {
|
|
|
173
174
|
targetUrl.endsWith(it.routerModule.intent.uri)
|
|
174
175
|
),
|
|
175
176
|
// delay(1000),
|
|
176
|
-
|
|
177
|
+
first()
|
|
177
178
|
)
|
|
178
179
|
);
|
|
179
180
|
// console.log('rrrrrssss');
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { RequestResponse } from '@dooboostore/simple-boot-http-server/models/RequestResponse';
|
|
2
2
|
import { HttpHeaders } from '@dooboostore/simple-boot-http-server/codes/HttpHeaders';
|
|
3
3
|
import { SimpleBootHttpSSRFactory } from '../SimpleBootHttpSSRFactory';
|
|
4
|
-
import { ConstructorType, AsyncBlockingQueue, RandomUtils,
|
|
4
|
+
import { ConstructorType, AsyncBlockingQueue, RandomUtils, firstValueFrom } from '@dooboostore/core';
|
|
5
|
+
import { first } from '@dooboostore/core/message/operators';
|
|
5
6
|
import { JsdomInitializer } from '../initializers/JsdomInitializer';
|
|
6
7
|
import { Filter } from '@dooboostore/simple-boot-http-server/filters/Filter';
|
|
7
8
|
import { Mimes } from '@dooboostore/simple-boot-http-server/codes/Mimes';
|
|
@@ -142,7 +143,7 @@ export class SSRLinkDomFilter implements Filter {
|
|
|
142
143
|
// }
|
|
143
144
|
// })
|
|
144
145
|
|
|
145
|
-
const data = await
|
|
146
|
+
const data = await firstValueFrom(
|
|
146
147
|
// @ts-ignore
|
|
147
148
|
simpleBootFront.routingObservable.pipe(
|
|
148
149
|
// @ts-ignore
|
|
@@ -153,7 +154,7 @@ export class SSRLinkDomFilter implements Filter {
|
|
|
153
154
|
targetUrl.endsWith(it.routerModule.intent.uri)
|
|
154
155
|
),
|
|
155
156
|
// delay(1000),
|
|
156
|
-
|
|
157
|
+
first()
|
|
157
158
|
)
|
|
158
159
|
);
|
|
159
160
|
// console.log('???????done');
|
|
@@ -4,7 +4,11 @@ import {Filter} from '@dooboostore/simple-boot-http-server/filters/Filter';
|
|
|
4
4
|
import {Mimes} from '@dooboostore/simple-boot-http-server/codes/Mimes';
|
|
5
5
|
import {HttpStatus} from '@dooboostore/simple-boot-http-server/codes/HttpStatus';
|
|
6
6
|
import {SimpleBootHttpServer} from '@dooboostore/simple-boot-http-server/SimpleBootHttpServer';
|
|
7
|
+
import {injectRequestResponse} from '@dooboostore/simple-boot-http-server/proxy/RequestResponseInjectProxy';
|
|
8
|
+
import {SimConfig} from '@dooboostore/simple-boot';
|
|
7
9
|
import {DomParserInitializer} from '../initializers/DomParserInitializer';
|
|
10
|
+
import type { SwcAppInterface } from '@dooboostore/simple-web-component';
|
|
11
|
+
import { findAllPropertyMetadata } from '@dooboostore/simple-web-component';
|
|
8
12
|
|
|
9
13
|
export type SWCSSRDomParserConfig = {
|
|
10
14
|
frontDistPath: string;
|
|
@@ -12,9 +16,18 @@ export type SWCSSRDomParserConfig = {
|
|
|
12
16
|
welcomUrl?: string;
|
|
13
17
|
ssrExcludeFilter?: (rr: RequestResponse) => boolean;
|
|
14
18
|
/**
|
|
15
|
-
*
|
|
19
|
+
* SSR 에 노출할 백엔드 서비스 목록(각 항목은 symbol 을 가진다, 예: pairServices).
|
|
20
|
+
* 프레임워크가 요청마다 각 서비스를 꺼내 이 요청의 rr 을 주입한 뒤 Map 으로 묶어
|
|
21
|
+
* registerComponents 의 3번째 인자(sim)로 넘긴다. → 앱은 그 Map 을 bootfactory 에 그대로 전달만 하면 되고
|
|
22
|
+
* 직접 Proxy 로 감싸거나 rr 을 넣을 필요가 없다(쿠키 등 요청 컨텍스트 자동 전달).
|
|
16
23
|
*/
|
|
17
|
-
|
|
24
|
+
intentServices?: SimConfig[];
|
|
25
|
+
/**
|
|
26
|
+
* 요청마다 컴포넌트를 등록한다. 앱 bootfactory를 그대로 넘기면 된다.
|
|
27
|
+
* @param sim intentServices 를 rr 주입해 묶은 Map<symbol, service>. bootfactory 에 그대로 넘기면 된다.
|
|
28
|
+
* @returns 초기화된 SwcApp (하이드레이션 데이터 박제 등에 사용)
|
|
29
|
+
*/
|
|
30
|
+
registerComponents?: (window: any, rr: RequestResponse, sim: Map<symbol, any>) => Promise<SwcAppInterface | void> | SwcAppInterface | void;
|
|
18
31
|
};
|
|
19
32
|
|
|
20
33
|
/**
|
|
@@ -23,12 +36,15 @@ export type SWCSSRDomParserConfig = {
|
|
|
23
36
|
*/
|
|
24
37
|
export class SSRSimpleWebComponentDomParserFilter implements Filter {
|
|
25
38
|
private welcomUrl = 'http://localhost';
|
|
39
|
+
private app?: SimpleBootHttpServer;
|
|
26
40
|
|
|
27
41
|
constructor(public config: SWCSSRDomParserConfig) {
|
|
28
42
|
this.welcomUrl = config.welcomUrl || this.welcomUrl;
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
async onInit(app: SimpleBootHttpServer) {
|
|
45
|
+
async onInit(app: SimpleBootHttpServer) {
|
|
46
|
+
this.app = app;
|
|
47
|
+
}
|
|
32
48
|
|
|
33
49
|
async onDestroy() {}
|
|
34
50
|
|
|
@@ -40,12 +56,12 @@ export class SSRSimpleWebComponentDomParserFilter implements Filter {
|
|
|
40
56
|
if (rr.reqHasAcceptHeader(Mimes.TextHtml) || rr.reqHasAcceptHeader(Mimes.All)) {
|
|
41
57
|
const url = rr.reqUrlObj({ host: 'localhost' });
|
|
42
58
|
const targetUrl = url.toString() ?? this.welcomUrl;
|
|
59
|
+
console.log('SSRSimpleWebComponentDomParserFilter start');
|
|
43
60
|
|
|
44
61
|
// 1. Initialize Virtual DOM Environment
|
|
45
62
|
const domParserInitializer = new DomParserInitializer(this.config.frontDistPath, this.config.frontDistIndexFileName || 'index.html', { url: targetUrl });
|
|
46
63
|
const window = await domParserInitializer.run();
|
|
47
64
|
|
|
48
|
-
console.log('vvvv22aa');
|
|
49
65
|
// web component 경우 자기 tagName을 생성자 에게 HTMLElementBase에넘겨줘야되기떄문에
|
|
50
66
|
// const getTagName = (type: ConstructorType<any>) => {
|
|
51
67
|
// const zz = getElementConfig(type);
|
|
@@ -63,8 +79,68 @@ export class SSRSimpleWebComponentDomParserFilter implements Filter {
|
|
|
63
79
|
try {
|
|
64
80
|
// 2. Register Components if provided
|
|
65
81
|
// We use SwcApplication inside the callback or directly here.
|
|
82
|
+
let app: SwcAppInterface | void;
|
|
66
83
|
if (this.config.registerComponents) {
|
|
67
|
-
|
|
84
|
+
// intentServices 를 rr 주입해 Map 으로 묶어 넘긴다 (앱은 bootfactory 에 그대로 전달만).
|
|
85
|
+
const sim = new Map<symbol, any>();
|
|
86
|
+
for (const service of (this.config.intentServices ?? []).filter(Boolean)) {
|
|
87
|
+
if (!service.symbol) continue;
|
|
88
|
+
for (const sym of (Array.isArray(service.symbol) ? service.symbol : [service.symbol])) {
|
|
89
|
+
const raw = this.app?.sim<any>(sym as any);
|
|
90
|
+
if (raw) sim.set(sym, injectRequestResponse(raw, rr));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
app = await this.config.registerComponents(window, rr, sim);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// [하이드레이션] swcApp 본체 + 연결 엘리먼트의 @property 값을 script로 박제.
|
|
97
|
+
// 클라에서 번들보다 먼저 실행 → querySelector로 찾아 .prop = 값 세팅 (네이티브
|
|
98
|
+
// 업그레이드는 own property 유지라 upgrade 후에도 값 살아있음).
|
|
99
|
+
if (app) {
|
|
100
|
+
const items: Array<{ sel: string; prop: string; value: unknown }> = [];
|
|
101
|
+
const targets: any[] = [app, ...(app.connectedElements?.() ?? []).filter((el: any) => el !== app)];
|
|
102
|
+
for (const el of targets) {
|
|
103
|
+
const swcId = (el as any)._swcId;
|
|
104
|
+
if (!swcId) continue;
|
|
105
|
+
const sel = `[swc-use-ssr="${swcId}"]`;
|
|
106
|
+
for (const m of findAllPropertyMetadata(el)) {
|
|
107
|
+
let value: unknown;
|
|
108
|
+
try {
|
|
109
|
+
value = el[m.propertyKey];
|
|
110
|
+
} catch {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (value === undefined || typeof value === 'function') continue;
|
|
114
|
+
try {
|
|
115
|
+
JSON.stringify(value);
|
|
116
|
+
} catch {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
items.push({ sel, prop: String(m.propertyKey), value });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (items.length > 0) {
|
|
123
|
+
// 업그레이드 때 노드가 갈아엎어지면 JS 프로퍼티는 날아감. attribute는 복사되니
|
|
124
|
+
// data-hyd-* 로 박고, 같은 노드면 프로퍼티도 바로 세팅.
|
|
125
|
+
const script = window.document.createElement('script');
|
|
126
|
+
// <script> 내용은 이스케이프 없이 직렬화된다 → 값에 '</script>'가 있으면 HTML 파서가 거기서 태그를 닫아 XSS.
|
|
127
|
+
// JSON.stringify는 '<'를 이스케이프하지 않으므로 '\u003c'로 바꾼다 (JS에선 같은 문자열).
|
|
128
|
+
// U+2028/2029는 구형 JS 엔진에서 문자열 리터럴 안의 줄바꿈으로 해석돼 문법 오류가 나므로 함께 이스케이프.
|
|
129
|
+
const hydrationJson = JSON.stringify(items)
|
|
130
|
+
.replace(/</g, '\\u003c')
|
|
131
|
+
.replace(/\u2028/g, '\\u2028')
|
|
132
|
+
.replace(/\u2029/g, '\\u2029');
|
|
133
|
+
script.textContent =
|
|
134
|
+
` window.__swc_hydration=${hydrationJson};` +
|
|
135
|
+
`for(const h of window.__swc_hydration){
|
|
136
|
+
const el=document.querySelector(h.sel);
|
|
137
|
+
if(el){
|
|
138
|
+
el[h.prop]=h.value;
|
|
139
|
+
}
|
|
140
|
+
}`;
|
|
141
|
+
window.document.body.appendChild(script);
|
|
142
|
+
console.log(`[ssr-hydration] ${items.length} props embedded`);
|
|
143
|
+
}
|
|
68
144
|
}
|
|
69
145
|
|
|
70
146
|
// window.document.querySelector('.sidebar-space').innerHTML = '씨발놈아.';
|
|
@@ -19,7 +19,7 @@ export type SWCSSRConfig = {
|
|
|
19
19
|
* Playwright evaluates real JS files loaded from your index.html,
|
|
20
20
|
* so component registration happens automatically in the browser context.
|
|
21
21
|
*/
|
|
22
|
-
registerComponents?: (window: any) => Promise<void> | void;
|
|
22
|
+
registerComponents?: (window: any, rr?: RequestResponse) => Promise<void> | void;
|
|
23
23
|
playwright?: {
|
|
24
24
|
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
|
|
25
25
|
waitForSelector?: string;
|