@dooboostore/simple-boot-http-server-ssr 1.0.8
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 +215 -0
- package/SimpleBootHttpSSRFactory.d.ts +8 -0
- package/SimpleBootHttpSSRFactory.js +10 -0
- package/SimpleBootHttpSSRServer.d.ts +9 -0
- package/SimpleBootHttpSSRServer.js +12 -0
- package/codes/HttpHeaders.d.ts +45 -0
- package/codes/HttpHeaders.js +10 -0
- package/codes/Mimes.d.ts +31 -0
- package/codes/Mimes.js +3 -0
- package/decorators/LoadAroundBefore.d.ts +2 -0
- package/decorators/LoadAroundBefore.js +31 -0
- package/decorators/SaveAroundAfter.d.ts +3 -0
- package/decorators/SaveAroundAfter.js +26 -0
- package/filters/IntentSchemeFilter.d.ts +20 -0
- package/filters/IntentSchemeFilter.js +72 -0
- package/filters/SSRFilter.d.ts +54 -0
- package/filters/SSRFilter.js +221 -0
- package/filters/SSRWorker.d.ts +16 -0
- package/filters/SSRWorker.js +72 -0
- package/initializers/JsdomInitializer.d.ts +11 -0
- package/initializers/JsdomInitializer.js +63 -0
- package/option/HttpSSRServerOption.d.ts +4 -0
- package/option/HttpSSRServerOption.js +4 -0
- package/package.json +86 -0
- package/proxy/IntentSchemeFrontProxy.d.ts +4 -0
- package/proxy/IntentSchemeFrontProxy.js +68 -0
- package/proxy/IntentSchemeServerProxy.d.ts +4 -0
- package/proxy/IntentSchemeServerProxy.js +39 -0
- package/proxy/SymbolIntentApiServiceProxy.d.ts +15 -0
- package/proxy/SymbolIntentApiServiceProxy.js +67 -0
package/README.MD
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# SIMPLE-BOOT-HTTP-SSR
|
|
2
|
+
|
|
3
|
+
### A framework for building Server-Side Rendered (SSR) applications.
|
|
4
|
+
|
|
5
|
+
This package seamlessly integrates `@dooboostore/simple-boot-front` and `@dooboostore/simple-boot-http-server` to provide a powerful solution for building fast, SEO-friendly, and dynamic web applications.
|
|
6
|
+
|
|
7
|
+
- **Server-Side Rendering**: Renders your single-page application on the server before sending it to the client.
|
|
8
|
+
- **JSDOM Integration**: Uses `jsdom` to create a virtual DOM environment on the server, allowing front-end code to run.
|
|
9
|
+
- **Component Pooling**: Manages a pool of `SimpleBootFront` instances to handle concurrent SSR requests efficiently.
|
|
10
|
+
- **Data Hydration**: Automatically serializes data fetched on the server and hydrates it on the client, avoiding redundant API calls. The `SaveAroundAfter` and `LoadAroundBefore` decorators facilitate this by saving data to `window.server_side_data` on the server and retrieving it on the client.
|
|
11
|
+
- **Unified Codebase**: Enables sharing of routing, services, and components between the server and the client.
|
|
12
|
+
- **Intent-based Communication**: Provides a mechanism for client-server communication using custom HTTP headers and intent publishing, allowing for flexible data fetching and action triggering.
|
|
13
|
+
|
|
14
|
+
### Dependencies
|
|
15
|
+
|
|
16
|
+
- **@dooboostore/simple-boot-front**: The front-end framework for building components and managing UI state.
|
|
17
|
+
- **@dooboostore/simple-boot-http-server**: The underlying HTTP server for handling requests.
|
|
18
|
+
|
|
19
|
+
## 🚀 How It Works
|
|
20
|
+
|
|
21
|
+
The core of this package is the `SSRFilter`. When a request for an HTML page comes in, the filter does the following:
|
|
22
|
+
|
|
23
|
+
1. **Intercepts the Request**: It captures the request before it would normally serve a static `index.html` file.
|
|
24
|
+
2. **Acquires a Browser Environment**: It takes a pre-initialized `jsdom` instance from a pool. This instance acts as a virtual browser on the server.
|
|
25
|
+
3. **Initializes a Front-End App**: It uses a `SimpleBootFront` application instance (also from a pool) and sets its context to the `jsdom` window.
|
|
26
|
+
4. **Executes Routing**: It triggers the front-end router within the `jsdom` environment, using the path from the incoming request.
|
|
27
|
+
5. **Renders Components**: The front-end components render into the virtual DOM.
|
|
28
|
+
6. **Handles Data Fetching**: If components fetch data during their lifecycle, this happens on the server. The `SaveAroundAfter` and `LoadAroundBefore` decorators automatically handle the serialization of this data into `window.server_side_data`.
|
|
29
|
+
7. **Serializes the DOM**: Once rendering is complete, it captures the `outerHTML` of the `jsdom` document.
|
|
30
|
+
8. **Injects Hydration Data**: The serialized data from step 6 is injected into the HTML inside a `<script>` tag.
|
|
31
|
+
9. **Sends Response**: The fully rendered HTML is sent to the client.
|
|
32
|
+
|
|
33
|
+
The client-side application then boots up, sees the pre-rendered HTML and the hydration data, and takes over without needing to re-render the initial view or re-fetch the initial data.
|
|
34
|
+
|
|
35
|
+
Additionally, the `IntentSchemeFilter` handles specific client-server communication. When a request with `Accept: application/json-post+simple-boot-ssr-intent-scheme` and `X-Simple-Boot-Ssr-Intent-Scheme` headers is received, this filter intercepts it, publishes an intent, and returns the result, enabling a robust intent-based API.
|
|
36
|
+
|
|
37
|
+
# 😃 Example Setup
|
|
38
|
+
|
|
39
|
+
### Common Factory (`factory.ts`)
|
|
40
|
+
|
|
41
|
+
This factory is used by both the server (for SSR) and the client (for browser rendering).
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { SimpleBootHttpSSRFactory, SimFrontOption, SimpleBootFront } from '@dooboostore/simple-boot-http-server-ssr';
|
|
45
|
+
import { ConstructorType } from '@dooboostore/core';
|
|
46
|
+
import { IndexRouterComponent } from './components/index.router.component';
|
|
47
|
+
|
|
48
|
+
// Function to create a standard front-end option object
|
|
49
|
+
export const MakeSimFrontOption = (window: any): SimFrontOption => {
|
|
50
|
+
return new SimFrontOption(window).setUrlType('path');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// The factory class that creates instances of the front-end application
|
|
54
|
+
class Factory extends SimpleBootHttpSSRFactory {
|
|
55
|
+
factory(simFrontOption: SimFrontOption, using: ConstructorType<any>[] = [], domExcludes: ConstructorType<any>[] = []): Promise<SimpleBootFront> {
|
|
56
|
+
const simpleBootFront = new SimpleBootFront(IndexRouterComponent, simFrontOption);
|
|
57
|
+
// Exclude certain types from being proxied by the DOM renderer
|
|
58
|
+
simpleBootFront.domRendoerExcludeProxy.push(...domExcludes);
|
|
59
|
+
return Promise.resolve(simpleBootFront);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default new Factory();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Server Entry Point (`server.ts`)
|
|
67
|
+
|
|
68
|
+
This sets up the HTTP server with the `SSRFilter` and `IntentSchemeFilter`.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import 'reflect-metadata';
|
|
72
|
+
import { ConstructorType } from '@dooboostore/core/types';
|
|
73
|
+
import { SimpleBootHttpSSRServer } from '@dooboostore/simple-boot-http-server-ssr/SimpleBootHttpSSRServer';
|
|
74
|
+
import { HttpSSRServerOption } from '@dooboostore/simple-boot-http-server-ssr/option/HttpSSRServerOption';
|
|
75
|
+
import { environment } from './environments/environment';
|
|
76
|
+
import { NotFoundError } from '@dooboostore/simple-boot-http-server/errors/NotFoundError';
|
|
77
|
+
import { SimpleBootHttpServer } from '@dooboostore/simple-boot-http-server/SimpleBootHttpServer';
|
|
78
|
+
import Factory, { MakeSimFrontOption } from '@src/bootfactory';
|
|
79
|
+
import { FactoryAndParams, SSRFilter } from '@dooboostore/simple-boot-http-server-ssr/filters/SSRFilter';
|
|
80
|
+
import { ResourceFilter } from '@dooboostore/simple-boot-http-server/filters/ResourceFilter';
|
|
81
|
+
import { RootRouter } from '@backend/root.router';
|
|
82
|
+
import { RequestResponse } from '@dooboostore/simple-boot-http-server/models/RequestResponse';
|
|
83
|
+
import { DataSource } from 'typeorm';
|
|
84
|
+
import { DatabaseService } from '@backend/service/database/DatabaseService';
|
|
85
|
+
import { services } from '@backend/service';
|
|
86
|
+
import { IntentSchemeFilter } from '@dooboostore/simple-boot-http-server-ssr/filters/IntentSchemeFilter';
|
|
87
|
+
import { ErrorLogEndPoint } from '@backend/endpoints/ErrorLogEndPoint';
|
|
88
|
+
import { CloseLogEndPoint } from '@backend/endpoints/CloseLogEndPoint';
|
|
89
|
+
import { RequestLogEndPoint } from '@backend/endpoints/RequestLogEndPoint';
|
|
90
|
+
import { GlobalAdvice } from '@backend/advices/GlobalAdvice';
|
|
91
|
+
import { SimpleBootHttpSSRFactory } from '@dooboostore/simple-boot-http-server-ssr/SimpleBootHttpSSRFactory';
|
|
92
|
+
import { Runnable } from '@dooboostore/core/runs/Runnable';
|
|
93
|
+
import { CrossDomainHeaderEndPoint } from '@dooboostore/simple-boot-http-server/endpoints/CrossDomainHeaderEndPoint';
|
|
94
|
+
import { SyncManager } from '@backend/manager';
|
|
95
|
+
import { SecurityService } from '@backend/service/SecurityService';
|
|
96
|
+
|
|
97
|
+
type ENV_MODE = 'ONLY_SYNC' | 'NO_SYNC' | undefined;
|
|
98
|
+
type WORLD = undefined | string;
|
|
99
|
+
|
|
100
|
+
type RunParams = { mode: ENV_MODE, world: WORLD };
|
|
101
|
+
|
|
102
|
+
class Server implements Runnable<void, RunParams> {
|
|
103
|
+
async run(config?: RunParams) {
|
|
104
|
+
const securityService = new SecurityService();
|
|
105
|
+
const databaseService = new DatabaseService(securityService);
|
|
106
|
+
await databaseService.run();
|
|
107
|
+
if (mode !== 'NO_SYNC') {
|
|
108
|
+
const syncManager = new SyncManager(databaseService);
|
|
109
|
+
await syncManager.run(config?.world ? Number(config.world) : undefined);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (mode === 'ONLY_SYNC') {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
// const cacheManager = new CacheManager(databaseService);
|
|
118
|
+
// await cacheManager.run();
|
|
119
|
+
|
|
120
|
+
const otherInstanceSim = new Map<ConstructorType<any>, any>();
|
|
121
|
+
otherInstanceSim.set(SecurityService, securityService);
|
|
122
|
+
otherInstanceSim.set(DatabaseService, databaseService);
|
|
123
|
+
// otherInstanceSim.set(CacheManager, cacheManager);
|
|
124
|
+
|
|
125
|
+
const ssrOption: FactoryAndParams = {
|
|
126
|
+
frontDistPath: environment.frontDistPath,
|
|
127
|
+
frontDistIndexFileName: environment.frontDistIndexFileName,
|
|
128
|
+
factorySimFrontOption: (window: any) => MakeSimFrontOption(window),
|
|
129
|
+
factory: Factory as SimpleBootHttpSSRFactory,
|
|
130
|
+
poolOption: {
|
|
131
|
+
max: 50,
|
|
132
|
+
min: 5
|
|
133
|
+
},
|
|
134
|
+
using: [...services],
|
|
135
|
+
domExcludes: [DataSource] as ConstructorType<any>[],
|
|
136
|
+
ssrExcludeFilter: (rr: RequestResponse) => {
|
|
137
|
+
const firstExcludeFilter = [
|
|
138
|
+
/^\/signs\/confirm-email.*/,
|
|
139
|
+
/^\/assets\/.*/,
|
|
140
|
+
/^\/api\/.*/
|
|
141
|
+
];
|
|
142
|
+
for (const excludeRegExp of firstExcludeFilter) {
|
|
143
|
+
if (excludeRegExp.test(rr.reqUrl)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
},
|
|
149
|
+
simpleBootFront: {
|
|
150
|
+
notFoundError: true
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
// const ssrFilter = new SSRFilter(ssrOption, otherInstanceSim);
|
|
154
|
+
|
|
155
|
+
const resourceFilter = new ResourceFilter(environment.frontDistPath,
|
|
156
|
+
[
|
|
157
|
+
'assets/privacy.html', 'assets/.*', '\.js$', '\.map$', '\.ico$', '\.png$', '\.jpg$', '\.jpeg$', '\.gif$', 'offline\.html$', 'webmanifest$', 'manifest\.json', 'service-worker\.js$', 'googlebe4b1abe81ab7cf3\.html$',
|
|
158
|
+
{
|
|
159
|
+
request: (rr) => {
|
|
160
|
+
return RegExp('/.*').test(rr.reqUrlPathName) && rr.reqMethod()?.toUpperCase() === 'GET';
|
|
161
|
+
},
|
|
162
|
+
dist: 'index.html'
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
);
|
|
166
|
+
const uploadResourceFilter = new ResourceFilter(environment.uploadTempPath,
|
|
167
|
+
['public/.*']
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const option = new HttpSSRServerOption();
|
|
171
|
+
option.cache = {
|
|
172
|
+
enable: true
|
|
173
|
+
}
|
|
174
|
+
option.rootRouter = RootRouter;
|
|
175
|
+
option.listen = environment.httpServerConfig.listen;
|
|
176
|
+
option.globalAdvice = new GlobalAdvice();
|
|
177
|
+
option.requestEndPoints = [
|
|
178
|
+
new RequestLogEndPoint(),
|
|
179
|
+
new CrossDomainHeaderEndPoint({accessControlExposeHeaders: 'Set-Cookie', accessControlAllowHeaders: '*', accessControlAllowMethods: '*', accessControlAllowOrigin: '*'}),
|
|
180
|
+
];
|
|
181
|
+
option.closeEndPoints = [new CloseLogEndPoint()];
|
|
182
|
+
option.errorEndPoints = [new ErrorLogEndPoint()];
|
|
183
|
+
option.noSuchRouteEndPointMappingThrow = () => new NotFoundError();
|
|
184
|
+
option.fileUploadTempPath = environment.uploadTempPath;
|
|
185
|
+
option.filters = [
|
|
186
|
+
resourceFilter,
|
|
187
|
+
uploadResourceFilter,
|
|
188
|
+
// ssrFilter,
|
|
189
|
+
// SecurityFilter,
|
|
190
|
+
IntentSchemeFilter
|
|
191
|
+
];
|
|
192
|
+
// option.serverOption = {
|
|
193
|
+
// key: fs.readFileSync(path.resolve(__dirname, '../data/certificates/localhost-key.pem')),
|
|
194
|
+
// cert: fs.readFileSync(path.resolve(__dirname, '../data/certificates/localhost.pem')),
|
|
195
|
+
// }
|
|
196
|
+
option.listen.listeningListener = (server: SimpleBootHttpServer) => {
|
|
197
|
+
console.log(`http server startUP! listening on ${server.option.listen.port}`);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const ssr = new SimpleBootHttpSSRServer(option);
|
|
201
|
+
await ssr.run(otherInstanceSim);
|
|
202
|
+
return ssr;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const mode = process.env.MODE as ENV_MODE;
|
|
207
|
+
const world = process.env.WORLD as ENV_MODE;
|
|
208
|
+
new Server().run({mode, world}).then(ssr => {
|
|
209
|
+
console.log(`server started!! (mode:${mode})`);
|
|
210
|
+
});
|
|
211
|
+
console.log(`server wait... (mode:${mode})`);
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SimpleBootFront } from '@dooboostore/simple-boot-front/SimpleBootFront';
|
|
2
|
+
import { ConstructorType } from '@dooboostore/core/types';
|
|
3
|
+
import { SimFrontOption } from '@dooboostore/simple-boot-front/option/SimFrontOption';
|
|
4
|
+
export declare abstract class SimpleBootHttpSSRFactory {
|
|
5
|
+
abstract factory(simFrontOption: SimFrontOption, using: (ConstructorType<any> | Function)[], domExcludes: ConstructorType<any>[]): Promise<SimpleBootFront>;
|
|
6
|
+
create(simFrontOption: SimFrontOption, using?: (ConstructorType<any> | Function)[], domExcludes?: ConstructorType<any>[]): Promise<SimpleBootFront>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=SimpleBootHttpSSRFactory.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
export class SimpleBootHttpSSRFactory {
|
|
3
|
+
create(simFrontOption, using = [], domExcludes = []) {
|
|
4
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
5
|
+
const front = yield this.factory(simFrontOption, using, domExcludes);
|
|
6
|
+
return front;
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=SimpleBootHttpSSRFactory.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SimpleBootHttpServer } from '@dooboostore/simple-boot-http-server/SimpleBootHttpServer';
|
|
2
|
+
import { SimstanceManager } from '@dooboostore/simple-boot/simstance/SimstanceManager';
|
|
3
|
+
import { HttpSSRServerOption } from './option/HttpSSRServerOption';
|
|
4
|
+
import { ConstructorType } from '@dooboostore/core/types';
|
|
5
|
+
export declare class SimpleBootHttpSSRServer extends SimpleBootHttpServer {
|
|
6
|
+
constructor(option?: HttpSSRServerOption);
|
|
7
|
+
run(otherInstanceSim?: Map<ConstructorType<any>, any>): SimstanceManager;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=SimpleBootHttpSSRServer.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SimpleBootHttpServer } from '@dooboostore/simple-boot-http-server/SimpleBootHttpServer';
|
|
2
|
+
export class SimpleBootHttpSSRServer extends SimpleBootHttpServer {
|
|
3
|
+
constructor(option) {
|
|
4
|
+
super(option);
|
|
5
|
+
}
|
|
6
|
+
run(otherInstanceSim) {
|
|
7
|
+
const oi = new Map();
|
|
8
|
+
otherInstanceSim === null || otherInstanceSim === void 0 ? void 0 : otherInstanceSim.forEach((value, key) => oi.set(key, value));
|
|
9
|
+
return super.run(oi);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=SimpleBootHttpSSRServer.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { HttpHeaders as AHttpHeaders } from '@dooboostore/simple-boot-http-server/codes/HttpHeaders';
|
|
2
|
+
export declare const HttpHeaders: {
|
|
3
|
+
XSimpleBootSsrIntentScheme: string;
|
|
4
|
+
ContentLength: AHttpHeaders.ContentLength;
|
|
5
|
+
ContentType: AHttpHeaders.ContentType;
|
|
6
|
+
ContentEncoding: AHttpHeaders.ContentEncoding;
|
|
7
|
+
Accept: AHttpHeaders.Accept;
|
|
8
|
+
Authorization: AHttpHeaders.Authorization;
|
|
9
|
+
CacheControl: AHttpHeaders.CacheControl;
|
|
10
|
+
Connection: AHttpHeaders.Connection;
|
|
11
|
+
Date: AHttpHeaders.Date;
|
|
12
|
+
Host: AHttpHeaders.Host;
|
|
13
|
+
Pragma: AHttpHeaders.Pragma;
|
|
14
|
+
Trailer: AHttpHeaders.Trailer;
|
|
15
|
+
TransferEncoding: AHttpHeaders.TransferEncoding;
|
|
16
|
+
Upgrade: AHttpHeaders.Upgrade;
|
|
17
|
+
Via: AHttpHeaders.Via;
|
|
18
|
+
Warning: AHttpHeaders.Warning;
|
|
19
|
+
AcceptCharset: AHttpHeaders.AcceptCharset;
|
|
20
|
+
AcceptEncoding: AHttpHeaders.AcceptEncoding;
|
|
21
|
+
AcceptLanguage: AHttpHeaders.AcceptLanguage;
|
|
22
|
+
AccessControlAllowOrigin: AHttpHeaders.AccessControlAllowOrigin;
|
|
23
|
+
AccessControlAllowMethods: AHttpHeaders.AccessControlAllowMethods;
|
|
24
|
+
AccessControlAllowHeaders: AHttpHeaders.AccessControlAllowHeaders;
|
|
25
|
+
AccessControlExposeHeaders: AHttpHeaders.AccessControlExposeHeaders;
|
|
26
|
+
Expect: AHttpHeaders.Expect;
|
|
27
|
+
From: AHttpHeaders.From;
|
|
28
|
+
MaxForwards: AHttpHeaders.MaxForwards;
|
|
29
|
+
Referer: AHttpHeaders.Referer;
|
|
30
|
+
UserAgent: AHttpHeaders.UserAgent;
|
|
31
|
+
Cookie: AHttpHeaders.Cookie;
|
|
32
|
+
SetCookie: AHttpHeaders.SetCookie;
|
|
33
|
+
Cookie2: AHttpHeaders.Cookie2;
|
|
34
|
+
SetCookie2: AHttpHeaders.SetCookie2;
|
|
35
|
+
Location: AHttpHeaders.Location;
|
|
36
|
+
IfModifiedSince: AHttpHeaders.IfModifiedSince;
|
|
37
|
+
IfUnmodifiedSince: AHttpHeaders.IfUnmodifiedSince;
|
|
38
|
+
IfMatch: AHttpHeaders.IfMatch;
|
|
39
|
+
IfNoneMatch: AHttpHeaders.IfNoneMatch;
|
|
40
|
+
IfRange: AHttpHeaders.IfRange;
|
|
41
|
+
Allow: AHttpHeaders.Allow;
|
|
42
|
+
Server: AHttpHeaders.Server;
|
|
43
|
+
};
|
|
44
|
+
export declare const makeIntentHeaderBySymbol: (symbol: Symbol) => HeadersInit;
|
|
45
|
+
//# sourceMappingURL=HttpHeaders.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HttpHeaders as AHttpHeaders } from '@dooboostore/simple-boot-http-server/codes/HttpHeaders';
|
|
2
|
+
import { Mimes } from './Mimes';
|
|
3
|
+
export const HttpHeaders = Object.assign(Object.assign({}, AHttpHeaders), { XSimpleBootSsrIntentScheme: 'x-simple-boot-ssr-intent-scheme' });
|
|
4
|
+
export const makeIntentHeaderBySymbol = (symbol) => {
|
|
5
|
+
return {
|
|
6
|
+
[HttpHeaders.Accept]: Mimes.ApplicationJsonPostSimpleBootSsrIntentScheme,
|
|
7
|
+
[HttpHeaders.XSimpleBootSsrIntentScheme]: `Symbol.for(${symbol.description})`
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=HttpHeaders.js.map
|
package/codes/Mimes.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Mimes as AMimes } from '@dooboostore/simple-boot-http-server/codes/Mimes';
|
|
2
|
+
export declare const Mimes: {
|
|
3
|
+
ApplicationJsonPostSimpleBootSsrIntentScheme: string;
|
|
4
|
+
Intent: string;
|
|
5
|
+
ApplicationJson: AMimes.ApplicationJson;
|
|
6
|
+
ApplicationOctetStream: AMimes.ApplicationOctetStream;
|
|
7
|
+
ApplicationXml: AMimes.ApplicationXml;
|
|
8
|
+
ApplicationJsonPatch: AMimes.ApplicationJsonPatch;
|
|
9
|
+
ApplicationXWwwFormUrlencoded: AMimes.ApplicationXWwwFormUrlencoded;
|
|
10
|
+
TextPlain: AMimes.TextPlain;
|
|
11
|
+
TextHtml: AMimes.TextHtml;
|
|
12
|
+
All: AMimes.All;
|
|
13
|
+
TextCss: AMimes.TextCss;
|
|
14
|
+
TextJavascript: AMimes.TextJavascript;
|
|
15
|
+
TextXml: AMimes.TextXml;
|
|
16
|
+
TextXslt: AMimes.TextXslt;
|
|
17
|
+
TextXmlDtd: AMimes.TextXmlDtd;
|
|
18
|
+
TextPlainUtf8: AMimes.TextPlainUtf8;
|
|
19
|
+
ImagePng: AMimes.ImagePng;
|
|
20
|
+
ImageGif: AMimes.ImageGif;
|
|
21
|
+
ImageJpeg: AMimes.ImageJpeg;
|
|
22
|
+
ImageSvg: AMimes.ImageSvg;
|
|
23
|
+
ImageBmp: AMimes.ImageBmp;
|
|
24
|
+
ImageTiff: AMimes.ImageTiff;
|
|
25
|
+
ImagePdf: AMimes.ImagePdf;
|
|
26
|
+
ImageXBmp: AMimes.ImageXBmp;
|
|
27
|
+
ImageXpixmap: AMimes.ImageXpixmap;
|
|
28
|
+
ImageXxbm: AMimes.ImageXxbm;
|
|
29
|
+
MultipartFormData: AMimes.MultipartFormData;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=Mimes.d.ts.map
|
package/codes/Mimes.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Mimes as AMimes } from '@dooboostore/simple-boot-http-server/codes/Mimes';
|
|
2
|
+
export const Mimes = Object.assign(Object.assign({}, AMimes), { ApplicationJsonPostSimpleBootSsrIntentScheme: 'application/json-post+simple-boot-ssr-intent-scheme', Intent: 'intent' });
|
|
3
|
+
//# sourceMappingURL=Mimes.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { getSim } from '@dooboostore/simple-boot/decorators/SimDecorator';
|
|
2
|
+
import { AroundForceReturn } from '@dooboostore/simple-boot/decorators/aop/AOPDecorator';
|
|
3
|
+
import { ReflectUtils } from '@dooboostore/simple-boot/utils/reflect/ReflectUtils';
|
|
4
|
+
export const LoadAroundBefore = (obj, propertyKey, args) => {
|
|
5
|
+
var _a, _b, _c;
|
|
6
|
+
const simstanceManager = obj._SimpleBoot_simstanceManager;
|
|
7
|
+
const simOption = obj._SimpleBoot_simOption;
|
|
8
|
+
const config = getSim(obj);
|
|
9
|
+
if (simstanceManager && simOption && (config === null || config === void 0 ? void 0 : config.scheme)) {
|
|
10
|
+
const key = config.scheme + '_' + propertyKey;
|
|
11
|
+
const type = ReflectUtils.getReturnType(obj, propertyKey);
|
|
12
|
+
const isHas = (key in ((_a = simOption.window.server_side_data) !== null && _a !== void 0 ? _a : {}));
|
|
13
|
+
if (isHas) {
|
|
14
|
+
const data = (_b = simOption.window.server_side_data) === null || _b === void 0 ? void 0 : _b[key];
|
|
15
|
+
(_c = simOption.window.server_side_data) === null || _c === void 0 ? true : delete _c[key];
|
|
16
|
+
let rdata;
|
|
17
|
+
if (type === Promise) {
|
|
18
|
+
rdata = Promise.resolve(data);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
rdata = data;
|
|
22
|
+
}
|
|
23
|
+
throw new AroundForceReturn(rdata);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return args;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return args;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=LoadAroundBefore.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getSim } from '@dooboostore/simple-boot/decorators/SimDecorator';
|
|
2
|
+
export const SaveAroundAfter = (obj, propertyKey, args, beforeReturn) => {
|
|
3
|
+
const simstanceManager = obj._SimpleBoot_simstanceManager;
|
|
4
|
+
const simOption = obj._SimpleBoot_simOption;
|
|
5
|
+
const config = getSim(obj);
|
|
6
|
+
if (simstanceManager && simOption && (config === null || config === void 0 ? void 0 : config.scheme)) {
|
|
7
|
+
if (!simOption.window.server_side_data) {
|
|
8
|
+
simOption.window.server_side_data = {};
|
|
9
|
+
}
|
|
10
|
+
const key = config.scheme + '_' + propertyKey;
|
|
11
|
+
if (beforeReturn instanceof Promise) {
|
|
12
|
+
beforeReturn.then((it) => {
|
|
13
|
+
simOption.window.server_side_data[key] = JSON.stringify(it);
|
|
14
|
+
return it;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
simOption.window.server_side_data[key] = JSON.stringify(beforeReturn);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return beforeReturn;
|
|
22
|
+
};
|
|
23
|
+
export const getStorage = (window) => {
|
|
24
|
+
return window.aroundStorage;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=SaveAroundAfter.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Filter } from '@dooboostore/simple-boot-http-server/filters/Filter';
|
|
2
|
+
import { IntentManager } from '@dooboostore/simple-boot/intent/IntentManager';
|
|
3
|
+
import { RequestResponse } from '@dooboostore/simple-boot-http-server/models/RequestResponse';
|
|
4
|
+
import { SimpleBootHttpServer } from '@dooboostore/simple-boot-http-server/SimpleBootHttpServer';
|
|
5
|
+
export declare class IntentSchemeFilter implements Filter {
|
|
6
|
+
private intentManager;
|
|
7
|
+
constructor(intentManager: IntentManager);
|
|
8
|
+
onInit(app: SimpleBootHttpServer): Promise<void>;
|
|
9
|
+
proceedBefore({ rr, app }: {
|
|
10
|
+
rr: RequestResponse;
|
|
11
|
+
app: SimpleBootHttpServer;
|
|
12
|
+
carrier: Map<string, any>;
|
|
13
|
+
}): Promise<boolean>;
|
|
14
|
+
proceedAfter({ rr, app }: {
|
|
15
|
+
rr: RequestResponse;
|
|
16
|
+
app: SimpleBootHttpServer;
|
|
17
|
+
carrier: Map<string, any>;
|
|
18
|
+
}): Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=IntentSchemeFilter.d.ts.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { __awaiter, __decorate, __metadata } from "tslib";
|
|
2
|
+
import { HttpHeaders } from '../codes/HttpHeaders';
|
|
3
|
+
import { Intent, PublishType } from '@dooboostore/simple-boot/intent/Intent';
|
|
4
|
+
import { IntentManager } from '@dooboostore/simple-boot/intent/IntentManager';
|
|
5
|
+
import { Sim } from '@dooboostore/simple-boot/decorators/SimDecorator';
|
|
6
|
+
import { HttpStatus } from '@dooboostore/simple-boot-http-server/codes/HttpStatus';
|
|
7
|
+
import { Mimes } from '../codes/Mimes';
|
|
8
|
+
let IntentSchemeFilter = class IntentSchemeFilter {
|
|
9
|
+
constructor(intentManager) {
|
|
10
|
+
this.intentManager = intentManager;
|
|
11
|
+
}
|
|
12
|
+
onInit(app) {
|
|
13
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
proceedBefore({ rr, app }) {
|
|
17
|
+
var _a;
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
// const rr = rrr;
|
|
20
|
+
const url = rr.reqUrl;
|
|
21
|
+
const contentLength = Number(rr.reqHeader((_a = HttpHeaders.ContentLength.toLowerCase()) !== null && _a !== void 0 ? _a : '0'));
|
|
22
|
+
const acceptType = rr.reqHeader(HttpHeaders.Accept);
|
|
23
|
+
const contentType = rr.reqHeader(HttpHeaders.ContentType);
|
|
24
|
+
const intentScheme = rr.reqHeader(HttpHeaders.XSimpleBootSsrIntentScheme);
|
|
25
|
+
if (acceptType === Mimes.ApplicationJsonPostSimpleBootSsrIntentScheme && intentScheme) {
|
|
26
|
+
let intent = new Intent(`${intentScheme}:/${url}`);
|
|
27
|
+
intent.publishType = PublishType.INLINE_DATA_PARAMETERS;
|
|
28
|
+
// const responseHeader = {} as any;
|
|
29
|
+
// responseHeader[HttpHeaders.ContentType] = Mimes.ApplicationJson;
|
|
30
|
+
if (contentLength > 0) {
|
|
31
|
+
if (contentType.includes(Mimes.ApplicationJson)) {
|
|
32
|
+
intent.data = [yield rr.reqBodyJsonData(), rr];
|
|
33
|
+
}
|
|
34
|
+
else if (contentType.includes(Mimes.MultipartFormData)) {
|
|
35
|
+
intent.data = [yield rr.reqBodyMultipartFormDataObject(), rr];
|
|
36
|
+
}
|
|
37
|
+
const rdatas = this.intentManager.publish(intent);
|
|
38
|
+
const rdata = rdatas[0];
|
|
39
|
+
const wdata = rdata instanceof Promise ? yield rdata : rdata;
|
|
40
|
+
rr.resStatusCode(HttpStatus.Ok);
|
|
41
|
+
rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
|
|
42
|
+
yield rr.resEnd(wdata ? JSON.stringify(wdata) : undefined);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
intent.data = rr.reqUrlSearchParamTuples.length > 0 ? [rr.reqUrlSearchParamsObj, rr] : [rr];
|
|
46
|
+
const rdatas = this.intentManager.publish(intent);
|
|
47
|
+
const rdata = rdatas[0];
|
|
48
|
+
const wdata = rdata instanceof Promise ? yield rdata : rdata;
|
|
49
|
+
rr.resStatusCode(HttpStatus.Ok);
|
|
50
|
+
rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
|
|
51
|
+
yield rr.resEnd(wdata ? JSON.stringify(wdata) : undefined);
|
|
52
|
+
}
|
|
53
|
+
// console.log('---------3--intent request', rr.req.readable, rr.req.readableLength);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
proceedAfter({ rr, app }) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
IntentSchemeFilter = __decorate([
|
|
68
|
+
Sim,
|
|
69
|
+
__metadata("design:paramtypes", [IntentManager])
|
|
70
|
+
], IntentSchemeFilter);
|
|
71
|
+
export { IntentSchemeFilter };
|
|
72
|
+
//# sourceMappingURL=IntentSchemeFilter.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { RequestResponse } from '@dooboostore/simple-boot-http-server/models/RequestResponse';
|
|
2
|
+
import { SimpleBootHttpSSRFactory } from '../SimpleBootHttpSSRFactory';
|
|
3
|
+
import { ConstructorType } from '@dooboostore/core/types';
|
|
4
|
+
import { Filter } from '@dooboostore/simple-boot-http-server/filters/Filter';
|
|
5
|
+
import { HttpStatus } from '@dooboostore/simple-boot-http-server/codes/HttpStatus';
|
|
6
|
+
import { SimpleBootHttpServer } from '@dooboostore/simple-boot-http-server/SimpleBootHttpServer';
|
|
7
|
+
import { SimFrontOption } from '@dooboostore/simple-boot-front/option/SimFrontOption';
|
|
8
|
+
import { SimpleBootFront } from '@dooboostore/simple-boot-front/SimpleBootFront';
|
|
9
|
+
import * as JSDOM from 'jsdom';
|
|
10
|
+
export type FactoryAndParams = {
|
|
11
|
+
frontDistPath: string;
|
|
12
|
+
frontDistIndexFileName?: string;
|
|
13
|
+
factorySimFrontOption: (window: any) => SimFrontOption;
|
|
14
|
+
factory: SimpleBootHttpSSRFactory;
|
|
15
|
+
poolOption: {
|
|
16
|
+
max: number;
|
|
17
|
+
min: number;
|
|
18
|
+
};
|
|
19
|
+
using: ConstructorType<any>[];
|
|
20
|
+
domExcludes: ConstructorType<any>[];
|
|
21
|
+
ssrExcludeFilter?: (rr: RequestResponse) => boolean;
|
|
22
|
+
simpleBootFront?: {
|
|
23
|
+
notFoundError?: boolean;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export declare class SSRFilter implements Filter {
|
|
27
|
+
config: FactoryAndParams;
|
|
28
|
+
otherInstanceSim?: Map<ConstructorType<any>, any>;
|
|
29
|
+
private simpleBootFrontPool;
|
|
30
|
+
private simpleBootFrontQueue;
|
|
31
|
+
private indexHTML;
|
|
32
|
+
private welcomUrl;
|
|
33
|
+
constructor(config: FactoryAndParams, otherInstanceSim?: Map<ConstructorType<any>, any>);
|
|
34
|
+
onInit(app: SimpleBootHttpServer): Promise<void>;
|
|
35
|
+
makeJsdom(): Promise<JSDOM.JSDOM>;
|
|
36
|
+
makeFront(jsdom: JSDOM.JSDOM): Promise<SimpleBootFront>;
|
|
37
|
+
enqueueFrontApp(simpleBootFront: SimpleBootFront): void;
|
|
38
|
+
pushQueue(): Promise<void>;
|
|
39
|
+
proceedBefore({ rr, app }: {
|
|
40
|
+
rr: RequestResponse;
|
|
41
|
+
app: SimpleBootHttpServer;
|
|
42
|
+
carrier: Map<string, any>;
|
|
43
|
+
}): Promise<boolean>;
|
|
44
|
+
writeOkHtmlAndEnd({ rr, status }: {
|
|
45
|
+
rr: RequestResponse;
|
|
46
|
+
status?: HttpStatus;
|
|
47
|
+
}, html: string): Promise<void>;
|
|
48
|
+
proceedAfter({ rr, app }: {
|
|
49
|
+
rr: RequestResponse;
|
|
50
|
+
app: SimpleBootHttpServer;
|
|
51
|
+
carrier: Map<string, any>;
|
|
52
|
+
}): Promise<boolean>;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=SSRFilter.d.ts.map
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { HttpHeaders } from '@dooboostore/simple-boot-http-server/codes/HttpHeaders';
|
|
3
|
+
import { JsdomInitializer } from '../initializers/JsdomInitializer';
|
|
4
|
+
import { Mimes } from '@dooboostore/simple-boot-http-server/codes/Mimes';
|
|
5
|
+
import { HttpStatus } from '@dooboostore/simple-boot-http-server/codes/HttpStatus';
|
|
6
|
+
import { AsyncBlockingQueue } from '@dooboostore/core/queues/AsyncBlockingQueue';
|
|
7
|
+
import { RandomUtils } from '@dooboostore/core/random/RandomUtils';
|
|
8
|
+
import { NotFoundError } from '@dooboostore/simple-boot-http-server/errors/NotFoundError';
|
|
9
|
+
export class SSRFilter {
|
|
10
|
+
constructor(config, otherInstanceSim) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.otherInstanceSim = otherInstanceSim;
|
|
13
|
+
this.simpleBootFrontPool = [];
|
|
14
|
+
this.simpleBootFrontQueue = new AsyncBlockingQueue();
|
|
15
|
+
this.welcomUrl = 'http://localhost';
|
|
16
|
+
config.frontDistIndexFileName = config.frontDistIndexFileName || 'index.html';
|
|
17
|
+
this.indexHTML = JsdomInitializer.loadFile(this.config.frontDistPath, config.frontDistIndexFileName);
|
|
18
|
+
}
|
|
19
|
+
onInit(app) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
for (let i = 0; i < this.config.poolOption.min; i++) {
|
|
22
|
+
yield this.pushQueue();
|
|
23
|
+
}
|
|
24
|
+
// console.log('SimpleBootHttpSSRFactory init success ', + this.simpleBootFrontPool.length)
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// workerTs(workerOptions: WorkerOptions) {
|
|
28
|
+
// workerOptions.eval = true;
|
|
29
|
+
// if (!workerOptions.workerData) {
|
|
30
|
+
// workerOptions.workerData = {};
|
|
31
|
+
// }
|
|
32
|
+
// workerOptions.workerData.__filename = '/Users/hyunhakim/source/visualkhh/pet-space/libs/simple-boot-http-ssr/dist/filters/SSRCreatorWorker.js';
|
|
33
|
+
// return new Worker(` const wk = require('worker_threads'); require('ts-node').register(); let file = wk.workerData.__filename; require(file); `, workerOptions,);
|
|
34
|
+
// }
|
|
35
|
+
makeJsdom() {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
const jsdom = yield new JsdomInitializer(this.config.frontDistPath, this.config.frontDistIndexFileName || 'index.html', { url: this.welcomUrl }).run();
|
|
38
|
+
return jsdom;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
makeFront(jsdom) {
|
|
42
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
const name = RandomUtils.uuid();
|
|
44
|
+
// const jsdom = await this.makeJsdom();
|
|
45
|
+
const window = jsdom.window;
|
|
46
|
+
window.ssrUse = false;
|
|
47
|
+
const option = this.config.factorySimFrontOption(window);
|
|
48
|
+
const simpleBootFront = yield this.config.factory.create(option, this.config.using, this.config.domExcludes);
|
|
49
|
+
simpleBootFront.run(this.otherInstanceSim);
|
|
50
|
+
simpleBootFront.jsdom = jsdom;
|
|
51
|
+
return simpleBootFront;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
enqueueFrontApp(simpleBootFront) {
|
|
55
|
+
// this.simpleBootFrontPool.set(simpleBootFront.option.name!, simpleBootFront);
|
|
56
|
+
this.simpleBootFrontPool.push(simpleBootFront);
|
|
57
|
+
this.simpleBootFrontQueue.enqueue(simpleBootFront);
|
|
58
|
+
}
|
|
59
|
+
// async pushQueue(destorFront?: SimpleBootFront) {
|
|
60
|
+
// if (destorFront) {
|
|
61
|
+
// this.simpleBootFrontPool.delete(destorFront.option.name!);
|
|
62
|
+
// }
|
|
63
|
+
pushQueue() {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
if (this.simpleBootFrontPool.length < this.config.poolOption.max) {
|
|
66
|
+
this.enqueueFrontApp(yield this.makeFront(yield this.makeJsdom()));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
proceedBefore({ rr, app }) {
|
|
71
|
+
var _a, _b, _c;
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
if ((_b = (_a = this.config).ssrExcludeFilter) === null || _b === void 0 ? void 0 : _b.call(_a, rr)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
if ((rr.reqHasAcceptHeader(Mimes.TextHtml) || rr.reqHasAcceptHeader(Mimes.All))) {
|
|
77
|
+
if (this.simpleBootFrontQueue.isEmpty()) {
|
|
78
|
+
yield this.pushQueue();
|
|
79
|
+
}
|
|
80
|
+
const simpleBootFront = yield this.simpleBootFrontQueue.dequeue();
|
|
81
|
+
try {
|
|
82
|
+
// console.log('SSRFilter before-->' , simpleBootFront.option.name, 'poolLength:',this.simpleBootFrontPool.size);
|
|
83
|
+
simpleBootFront.option.window.ssrUse = true;
|
|
84
|
+
delete simpleBootFront.option.window.server_side_data;
|
|
85
|
+
const url = rr.reqUrlObj({ host: 'localhost' });
|
|
86
|
+
if ((_c = this.config.simpleBootFront) === null || _c === void 0 ? void 0 : _c.notFoundError) {
|
|
87
|
+
// intent router check first
|
|
88
|
+
const intent = yield simpleBootFront.getIntent(url.pathname);
|
|
89
|
+
// route를 못찾은상태에서 router path까지 안맞으면 404 처리한다. route랑 router랑 다르니깐 헛갈리지말도록
|
|
90
|
+
if (intent.module === undefined && (!intent.getRouterPathData(rr.reqUrlPathName))) {
|
|
91
|
+
throw new NotFoundError({ message: `Not Found: ${rr.reqUrlPathName}` });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// runRouting!!
|
|
95
|
+
simpleBootFront.goRouting(url.toString());
|
|
96
|
+
// console.log('------intent', intent)
|
|
97
|
+
yield new Promise((r) => setTimeout(r, 0)); // <--중요: 이거 넣어야지 두번불러지는게 없어지는듯? 뭐지 event loop 변경된건가?
|
|
98
|
+
// const e = Expression.Path.pathNameData(rr.reqUrlPathName, intent.getRouterPath())
|
|
99
|
+
// console.log('------intent', rr.reqUrl, rr.reqUrlPathName, intent.module, intent.getRouterPath(), e)
|
|
100
|
+
let html = simpleBootFront.option.window.document.documentElement.outerHTML;
|
|
101
|
+
const serverSideData = simpleBootFront.option.window.server_side_data;
|
|
102
|
+
if (serverSideData) {
|
|
103
|
+
const data = Object.entries(serverSideData).map(([k, v]) => {
|
|
104
|
+
if (typeof v === 'string') {
|
|
105
|
+
return `window.server_side_data.${k} = ${v}`;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
return `window.server_side_data.${k} = ${JSON.stringify(v)}`;
|
|
109
|
+
}
|
|
110
|
+
}).join(';');
|
|
111
|
+
if (data) {
|
|
112
|
+
html = html.replace('</head>', `<script> window.server_side_data={}; ${data}; </script></head>`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
yield this.writeOkHtmlAndEnd({ rr }, html);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
simpleBootFront.option.window.ssrUse = false;
|
|
119
|
+
delete simpleBootFront.option.window.server_side_data;
|
|
120
|
+
// console.log('--------->', simpleBootFront.option.window)
|
|
121
|
+
// simpleBootFront.ninitWriteRootRouter();
|
|
122
|
+
// ((simpleBootFront as any).jsdom as JSDOM.JSDOM)?.reconfigure({url: '/' });
|
|
123
|
+
// simpleBootFront.option.window.location.href = 'about:blank';
|
|
124
|
+
this.simpleBootFrontQueue.enqueue(simpleBootFront);
|
|
125
|
+
// simpleBootFront.option.window.document.body.innerHTML = this.rootJSDOM.window.document.body.innerHTML;
|
|
126
|
+
// simpleBootFront.writeRootRouter()
|
|
127
|
+
// await simpleBootFront.goRouting('/');
|
|
128
|
+
// ((simpleBootFront as any).jsdom as JSDOM.JSDOM)?.reconfigure({url: this.welcomUrl });
|
|
129
|
+
// simpleBootFront.option.window.location.href = this.welcomUrl;
|
|
130
|
+
// simpleBootFront.option.window.document.documentElement.outerHTML = this.indexHTML;
|
|
131
|
+
// this.simpleBootFrontQueue.enqueue(simpleBootFront);
|
|
132
|
+
// await new Promise((re, r) => setTimeout(() => re(true), 10000));
|
|
133
|
+
// new Promise((re, r) => setTimeout(() => re(true), 10000)).then(it => {
|
|
134
|
+
// console.log('ddddddddddd')
|
|
135
|
+
// });
|
|
136
|
+
// this.simpleBootFrontPool.delete(simpleBootFront.option.name!);
|
|
137
|
+
// if (isMainThread) { // 메인 스레드
|
|
138
|
+
// console.log('file-->', __filename)
|
|
139
|
+
// const worker = new Worker(__filename);
|
|
140
|
+
// worker.on('message', (value: any) => {
|
|
141
|
+
// console.log('워커로부터', value)
|
|
142
|
+
// })
|
|
143
|
+
// worker.on('exit', (value: any) => { // parentPort.close()가 일어나면 이벤트 발생
|
|
144
|
+
// console.log('워커 끝~');
|
|
145
|
+
// })
|
|
146
|
+
// worker.postMessage('ping'); // 워커스레드에게 메세지를 보낸다.
|
|
147
|
+
// } else { // 워커스레드
|
|
148
|
+
// parentPort.on('message', (value: any) => {
|
|
149
|
+
// console.log("부모로부터", value);
|
|
150
|
+
// parentPort.postMessage('pong');
|
|
151
|
+
// parentPort.close(); // 워커스레드 종료라고 메인스레드에 알려줘야 exit이벤트 발생
|
|
152
|
+
// })
|
|
153
|
+
// }
|
|
154
|
+
//worker thrad
|
|
155
|
+
// const workerPath = path.join(__dirname, 'SSRWorker.js');
|
|
156
|
+
// const worker = new Worker(workerPath);
|
|
157
|
+
// worker.once('message', (value: any) => {
|
|
158
|
+
// console.log('워커로부터', value)
|
|
159
|
+
// });
|
|
160
|
+
// const receiveWorker = new Worker('/Users/hyunhakim/source/visualkhh/pet-space/libs/simple-boot-http-ssr/dist/filters/SSRCreatorWorker.js');
|
|
161
|
+
// receiveWorker.on('message', (msg: JSDOM.JSDOM)=>{
|
|
162
|
+
// console.log('워커로부터', msg, msg.window.document.body.innerHTML)
|
|
163
|
+
// console.log('a message is sent! : ', msg)
|
|
164
|
+
//
|
|
165
|
+
// });
|
|
166
|
+
//
|
|
167
|
+
// receiveWorker.on('error', err=>{
|
|
168
|
+
// console.error(err);
|
|
169
|
+
// })
|
|
170
|
+
//
|
|
171
|
+
// receiveWorker.on('exit', ()=>console.log('exited!'));
|
|
172
|
+
// receiveWorker.postMessage(
|
|
173
|
+
// {
|
|
174
|
+
// frontDistPath: this.factory.frontDistPath,
|
|
175
|
+
// frontDistIndexFileName: this.factory.frontDistIndexFileName,
|
|
176
|
+
// }
|
|
177
|
+
// );
|
|
178
|
+
// const myWorkers = this.workerTs({});
|
|
179
|
+
// myWorkers.postMessage(this);
|
|
180
|
+
// myWorkers.on('message', (value: SimpleBootFront) => {
|
|
181
|
+
// this.pushQueue(value);
|
|
182
|
+
// })
|
|
183
|
+
// this
|
|
184
|
+
// this.pushQueue(simpleBootFront).then(it => {
|
|
185
|
+
// console.log('deee')
|
|
186
|
+
// });
|
|
187
|
+
// console.log('-1->', simpleBootFront.option.window.location.href);
|
|
188
|
+
// simpleBootFront.option.window.location.href = this.welcomUrl;
|
|
189
|
+
// simpleBootFront.option.window.location.reload();
|
|
190
|
+
// console.log('-2->', simpleBootFront.option.window.location.href);
|
|
191
|
+
// simpleBootFront.option.window.location.reload();
|
|
192
|
+
// console.log('-3->', simpleBootFront.option.window.location.href);
|
|
193
|
+
// this.simpleBootFrontQueue.enqueue(simpleBootFront);
|
|
194
|
+
// await this.makeJsdom();
|
|
195
|
+
// simpleBootFront.option.window.location.href = this.welcomUrl;
|
|
196
|
+
}
|
|
197
|
+
// console.log('----doen')
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
// console.log('----doen2')
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
writeOkHtmlAndEnd({ rr, status = HttpStatus.Ok }, html) {
|
|
207
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
208
|
+
// rr.res.writeHead(status, {[HttpHeaders.ContentType]: Mimes.TextHtml});
|
|
209
|
+
rr.resStatusCode(status);
|
|
210
|
+
rr.resSetHeader(HttpHeaders.ContentType, Mimes.TextHtml);
|
|
211
|
+
yield rr.resEnd(html);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
proceedAfter({ rr, app }) {
|
|
215
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
216
|
+
// console.log('done--------', sw)
|
|
217
|
+
return true;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=SSRFilter.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ConstructorType } from '@dooboostore/core/types';
|
|
2
|
+
import { FactoryAndParams } from './SSRFilter';
|
|
3
|
+
import JSDOM from 'jsdom';
|
|
4
|
+
import { SimpleBootFront } from '@dooboostore/simple-boot-front/SimpleBootFront';
|
|
5
|
+
export declare class SSRWorker {
|
|
6
|
+
factory: FactoryAndParams;
|
|
7
|
+
otherInstanceSim?: Map<ConstructorType<any>, any>;
|
|
8
|
+
welcomUrl: string;
|
|
9
|
+
private simpleBootFront?;
|
|
10
|
+
constructor(factory: FactoryAndParams, otherInstanceSim?: Map<ConstructorType<any>, any>);
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
makeJsdom(): Promise<JSDOM.JSDOM>;
|
|
13
|
+
makeFront(jsdom?: JSDOM.JSDOM): Promise<SimpleBootFront>;
|
|
14
|
+
getHtml(url: string): Promise<string>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=SSRWorker.d.ts.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { JsdomInitializer } from '../initializers/JsdomInitializer';
|
|
3
|
+
import { RandomUtils } from '@dooboostore/core/random/RandomUtils';
|
|
4
|
+
export class SSRWorker {
|
|
5
|
+
constructor(factory, otherInstanceSim) {
|
|
6
|
+
this.factory = factory;
|
|
7
|
+
this.otherInstanceSim = otherInstanceSim;
|
|
8
|
+
this.welcomUrl = 'http://localhost';
|
|
9
|
+
}
|
|
10
|
+
run() {
|
|
11
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12
|
+
this.simpleBootFront = yield this.makeFront();
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
makeJsdom() {
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
const jsdom = yield new JsdomInitializer(this.factory.frontDistPath, this.factory.frontDistIndexFileName || 'index.html', { url: this.welcomUrl }).run();
|
|
18
|
+
return jsdom;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
makeFront(jsdom) {
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
if (!jsdom) {
|
|
24
|
+
jsdom = yield this.makeJsdom();
|
|
25
|
+
}
|
|
26
|
+
const name = RandomUtils.uuid();
|
|
27
|
+
// const jsdom = await this.makeJsdom();
|
|
28
|
+
const window = jsdom.window;
|
|
29
|
+
window.ssrUse = false;
|
|
30
|
+
const option = this.factory.factorySimFrontOption(window);
|
|
31
|
+
// option.name = name;
|
|
32
|
+
const simpleBootFront = yield this.factory.factory.create(option, this.factory.using, this.factory.domExcludes);
|
|
33
|
+
simpleBootFront.run(this.otherInstanceSim);
|
|
34
|
+
simpleBootFront.jsdom = jsdom;
|
|
35
|
+
return simpleBootFront;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
getHtml(url) {
|
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
if (this.simpleBootFront && this.simpleBootFront.option.window.ssrUse) {
|
|
41
|
+
}
|
|
42
|
+
else if (this.simpleBootFront) {
|
|
43
|
+
this.simpleBootFront.option.window.ssrUse = true;
|
|
44
|
+
delete this.simpleBootFront.option.window.server_side_data;
|
|
45
|
+
// run
|
|
46
|
+
yield this.simpleBootFront.goRouting(url);
|
|
47
|
+
let html = this.simpleBootFront.option.window.document.documentElement.outerHTML;
|
|
48
|
+
const serverSideData = this.simpleBootFront.option.window.server_side_data;
|
|
49
|
+
if (serverSideData) {
|
|
50
|
+
const data = Object.entries(serverSideData).map(([k, v]) => {
|
|
51
|
+
if (typeof v === 'string') {
|
|
52
|
+
return `window.server_side_data.${k} = ${v}`;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
return `window.server_side_data.${k} = ${JSON.stringify(v)}`;
|
|
56
|
+
}
|
|
57
|
+
}).join(';');
|
|
58
|
+
if (data) {
|
|
59
|
+
html = html.replace('</head>', `<script> window.server_side_data={}; ${data}; </script></head>`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
this.makeFront().then(it => {
|
|
63
|
+
this.simpleBootFront = it;
|
|
64
|
+
});
|
|
65
|
+
return html;
|
|
66
|
+
}
|
|
67
|
+
{
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=SSRWorker.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as JSDOM from 'jsdom';
|
|
2
|
+
import { ReconfigureSettings } from 'jsdom';
|
|
3
|
+
export declare class JsdomInitializer {
|
|
4
|
+
private frontDistPath;
|
|
5
|
+
private frontDistIndexFileName;
|
|
6
|
+
private reconfigureSettings?;
|
|
7
|
+
constructor(frontDistPath: string, frontDistIndexFileName: string, reconfigureSettings?: ReconfigureSettings);
|
|
8
|
+
static loadFile(distPath: string, filePath: string): string;
|
|
9
|
+
run(): Promise<JSDOM.JSDOM>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=JsdomInitializer.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import * as JSDOM from 'jsdom';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
export class JsdomInitializer {
|
|
6
|
+
constructor(frontDistPath, frontDistIndexFileName, reconfigureSettings) {
|
|
7
|
+
this.frontDistPath = frontDistPath;
|
|
8
|
+
this.frontDistIndexFileName = frontDistIndexFileName;
|
|
9
|
+
this.reconfigureSettings = reconfigureSettings;
|
|
10
|
+
}
|
|
11
|
+
static loadFile(distPath, filePath) {
|
|
12
|
+
return fs.readFileSync(path.join(distPath, filePath), 'utf8');
|
|
13
|
+
}
|
|
14
|
+
run() {
|
|
15
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
// const indexHTML = fs.readFileSync(path.join(this.frontDistPath, 'index.html'), 'utf8');
|
|
17
|
+
// const indexHTML = JsdomInitializer.loadFile(this.frontDistPath, this.frontDistIndexFileName);
|
|
18
|
+
const pathStr = path.join(this.frontDistPath, this.frontDistIndexFileName);
|
|
19
|
+
const jsdom = yield JSDOM.JSDOM.fromFile(pathStr, {});
|
|
20
|
+
if (this.reconfigureSettings) {
|
|
21
|
+
jsdom.reconfigure(this.reconfigureSettings);
|
|
22
|
+
}
|
|
23
|
+
// devDependencies
|
|
24
|
+
// "@types/jsdom": "^21.1.2",
|
|
25
|
+
// "canvas": "^3.1.0",
|
|
26
|
+
// global setting
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
global.document = jsdom.window.document;
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
global.window = jsdom.window;
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
global.window.requestAnimationFrame = () => { };
|
|
33
|
+
const dummyResponse = { ok: false, json: () => Promise.resolve({}) }; // as Response;
|
|
34
|
+
global.fetch = (...data) => Promise.resolve(dummyResponse);
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
global.history = jsdom.window.history;
|
|
37
|
+
global.Event = jsdom.window.Event;
|
|
38
|
+
global.IntersectionObserver = jsdom.window.IntersectionObserver;
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
// global.Error = ErrorBase;
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
// global.navigator = jsdom.window.navigator;
|
|
43
|
+
global.NodeFilter = jsdom.window.NodeFilter;
|
|
44
|
+
global.Node = jsdom.window.Node;
|
|
45
|
+
global.HTMLElement = jsdom.window.HTMLElement;
|
|
46
|
+
global.HTMLMetaElement = jsdom.window.HTMLMetaElement;
|
|
47
|
+
global.Element = jsdom.window.Element;
|
|
48
|
+
global.HTMLCanvasElement = jsdom.window.HTMLCanvasElement;
|
|
49
|
+
global.HTMLCanvasElement.prototype.getContext = () => {
|
|
50
|
+
return null;
|
|
51
|
+
};
|
|
52
|
+
global.CanvasRenderingContext2D = jsdom.window.CanvasRenderingContext2D;
|
|
53
|
+
global.CanvasPattern = jsdom.window.CanvasPattern;
|
|
54
|
+
global.CanvasGradient = jsdom.window.CanvasGradient;
|
|
55
|
+
global.Path2D = jsdom.window.Path2D;
|
|
56
|
+
global.ImageData = jsdom.window.ImageData;
|
|
57
|
+
return jsdom;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//
|
|
62
|
+
// export default new JsdomInitializer();
|
|
63
|
+
//# sourceMappingURL=JsdomInitializer.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dooboostore/simple-boot-http-server-ssr",
|
|
3
|
+
"version": "1.0.8",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"description": "front end SPA frameworks SSR",
|
|
8
|
+
"files": [
|
|
9
|
+
"**/*.js",
|
|
10
|
+
"**/*.d.ts"
|
|
11
|
+
],
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"front",
|
|
17
|
+
"spa",
|
|
18
|
+
"SPA",
|
|
19
|
+
"module",
|
|
20
|
+
"front-end",
|
|
21
|
+
"framwork",
|
|
22
|
+
"node"
|
|
23
|
+
],
|
|
24
|
+
"author": "dooboostore <dooboostore@gmail.com> (https://github.com/dooboostore)",
|
|
25
|
+
"contributors": [
|
|
26
|
+
"sewoo <sewooimda@nate.com> (https://github.com/sewoo)",
|
|
27
|
+
"SeoDH <adonis_84@naver.com> (https://github.com/SeoDH)",
|
|
28
|
+
"tkyung (https://github.com/tkyungDev)",
|
|
29
|
+
"Hoil-Gang (https://github.com/khl1154)",
|
|
30
|
+
"hwangsero (https://github.com/hwangsero)"
|
|
31
|
+
],
|
|
32
|
+
"homepage": "https://github.com/dooboostore-develop/packages",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/dooboostore-develop/packages",
|
|
35
|
+
"email": "dooboostore@gmail.com"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/dooboostore-develop/packages"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/css": "^0.0.33",
|
|
43
|
+
"@types/jest": "^26.0.22",
|
|
44
|
+
"@types/jsdom": "^21.1.2",
|
|
45
|
+
"@types/mime-types": "^2.1.1",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^4.16.1",
|
|
47
|
+
"@typescript-eslint/parser": "^4.16.1",
|
|
48
|
+
"eslint": "^7.21.0",
|
|
49
|
+
"eslint-config-standard": "^16.0.2",
|
|
50
|
+
"eslint-plugin-import": "^2.22.1",
|
|
51
|
+
"eslint-plugin-node": "^11.1.0",
|
|
52
|
+
"eslint-plugin-promise": "^4.3.1",
|
|
53
|
+
"jest": "^26.6.3",
|
|
54
|
+
"supertest": "^6.1.3",
|
|
55
|
+
"ts-jest": "^26.5.4",
|
|
56
|
+
"@types/node": "^20",
|
|
57
|
+
"tslib": "^2.8.1",
|
|
58
|
+
"typescript": "^4.4.3"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"jsdom": "^26.0.0",
|
|
62
|
+
"reflect-metadata": "^0.2.2",
|
|
63
|
+
"@dooboostore/core-web": "1.0.1",
|
|
64
|
+
"@dooboostore/simple-boot": "1.0.43",
|
|
65
|
+
"@dooboostore/dom-render": "1.0.99",
|
|
66
|
+
"@dooboostore/simple-boot-front": "1.0.120",
|
|
67
|
+
"@dooboostore/core-node": "1.0.1",
|
|
68
|
+
"@dooboostore/core": "1.0.7",
|
|
69
|
+
"@dooboostore/simple-boot-http-server": "1.0.15"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
73
|
+
"clean": "rm -rf dist",
|
|
74
|
+
"npm:build": "pnpm run build && cp README.MD dist/ && pnpm pack && TARBALL_NAME=$(ls dooboostore-simple-boot-http-server-ssr-*.tgz | head -n 1) && tar -xzf \"$TARBALL_NAME\" -C dist --strip-components=1 package/package.json && rm \"$TARBALL_NAME\"",
|
|
75
|
+
"npm:clean": "rm -rf dist",
|
|
76
|
+
"npm:publish": "pnpm run npm:build && cd dist && pnpm publish --no-git-checks",
|
|
77
|
+
"npm:publish:clean": "pnpm run npm:publish && rm -rf dist",
|
|
78
|
+
"ts:clean": "find . -name '*.js' -o -name '*.map' -o -name '*.d.ts' | xargs rm -f",
|
|
79
|
+
"tsc": "tsc",
|
|
80
|
+
"tsc:watch": "rm -rf ./dist && mkdir dist && cp package.json dist && tsc --watch --sourceMap true",
|
|
81
|
+
"tsc:watch:dev": "rm -rf ./dist && mkdir dist && cp package-dev.json dist && tsc --watch --sourceMap true",
|
|
82
|
+
"tsc:watch:prod": "rm -rf dist && mkdir dist && cp package-prod.json dist/package.json && cp README.MD dist && tsc --watch --sourceMap true --outDir dist --declarationDir dist",
|
|
83
|
+
"test": "jest --detectOpenHandles --forceExit",
|
|
84
|
+
"typecheck": "tsc --noEmit"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { __awaiter, __decorate } from "tslib";
|
|
2
|
+
import { getSim, Sim } from '@dooboostore/simple-boot/decorators/SimDecorator';
|
|
3
|
+
import { HttpHeaders } from '@dooboostore/simple-boot-http-server/codes/HttpHeaders';
|
|
4
|
+
import { HttpHeaders as SSRHttpHeaders } from '../codes/HttpHeaders';
|
|
5
|
+
import { Mimes as SSRMimes } from '../codes/Mimes';
|
|
6
|
+
import { ReflectUtils } from '@dooboostore/simple-boot/utils/reflect/ReflectUtils';
|
|
7
|
+
import { ConvertUtils } from '@dooboostore/core/convert/ConvertUtils';
|
|
8
|
+
let IntentSchemeFrontProxy = class IntentSchemeFrontProxy {
|
|
9
|
+
get(target, prop) {
|
|
10
|
+
const t = target[prop];
|
|
11
|
+
// TODO: 여기에 추가적인 프로퍼티 작성으 추가적으로 해야된다..
|
|
12
|
+
// if (typeof t === 'function') {
|
|
13
|
+
if (!['constructor', 'onProxyDomRender', 'toString'].includes(prop)) {
|
|
14
|
+
return (...args) => {
|
|
15
|
+
var _a, _b, _c;
|
|
16
|
+
// const simstanceManager = target._SimpleBoot_simstanceManager;
|
|
17
|
+
const simOption = target._SimpleBoot_simOption;
|
|
18
|
+
const config = getSim(target);
|
|
19
|
+
// const scheme = getSim(target)?.scheme;
|
|
20
|
+
const firstScheme = ConvertUtils.flatArray(config === null || config === void 0 ? void 0 : config.scheme)[0];
|
|
21
|
+
const key = firstScheme + '_' + prop;
|
|
22
|
+
const type = ReflectUtils.getReturnType(target, prop);
|
|
23
|
+
const isHas = (key in ((_a = simOption.window.server_side_data) !== null && _a !== void 0 ? _a : {}));
|
|
24
|
+
if (isHas) {
|
|
25
|
+
const data = (_b = simOption.window.server_side_data) === null || _b === void 0 ? void 0 : _b[key];
|
|
26
|
+
(_c = simOption.window.server_side_data) === null || _c === void 0 ? true : delete _c[key];
|
|
27
|
+
let rdata;
|
|
28
|
+
if (type instanceof Promise) {
|
|
29
|
+
rdata = Promise.resolve(data);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
rdata = data;
|
|
33
|
+
}
|
|
34
|
+
return rdata;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
return fetch(`/${prop.toString()}`, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { [HttpHeaders.ContentType]: SSRMimes.ApplicationJsonPostSimpleBootSsrIntentScheme, [SSRHttpHeaders.XSimpleBootSsrIntentScheme]: firstScheme !== null && firstScheme !== void 0 ? firstScheme : '' },
|
|
40
|
+
body: JSON.stringify(args[0])
|
|
41
|
+
}).then((res) => __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
try {
|
|
43
|
+
const data = yield res.json();
|
|
44
|
+
return data;
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
try {
|
|
48
|
+
return yield res.text();
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
// return t.apply(target, args);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
return t;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
IntentSchemeFrontProxy = __decorate([
|
|
65
|
+
Sim
|
|
66
|
+
], IntentSchemeFrontProxy);
|
|
67
|
+
export { IntentSchemeFrontProxy };
|
|
68
|
+
//# sourceMappingURL=IntentSchemeFrontProxy.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { getSim, Sim } from '@dooboostore/simple-boot/decorators/SimDecorator';
|
|
3
|
+
let IntentSchemeServerProxy = class IntentSchemeServerProxy {
|
|
4
|
+
get(target, prop) {
|
|
5
|
+
const t = target[prop];
|
|
6
|
+
if (typeof t === 'function') {
|
|
7
|
+
return (...args) => {
|
|
8
|
+
const simstanceManager = target._SimpleBoot_simstanceManager;
|
|
9
|
+
const simOption = target._SimpleBoot_simOption;
|
|
10
|
+
const config = getSim(target);
|
|
11
|
+
const data = t.apply(target, args);
|
|
12
|
+
if (simstanceManager && simOption && (config === null || config === void 0 ? void 0 : config.scheme) && simOption.window) {
|
|
13
|
+
if (!simOption.window.server_side_data) {
|
|
14
|
+
simOption.window.server_side_data = {};
|
|
15
|
+
}
|
|
16
|
+
const key = config.scheme + '_' + prop;
|
|
17
|
+
if (data instanceof Promise) {
|
|
18
|
+
data.then((it) => {
|
|
19
|
+
simOption.window.server_side_data[key] = JSON.stringify(it);
|
|
20
|
+
return it;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
simOption.window.server_side_data[key] = JSON.stringify(data);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return data;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
return t;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
IntentSchemeServerProxy = __decorate([
|
|
36
|
+
Sim
|
|
37
|
+
], IntentSchemeServerProxy);
|
|
38
|
+
export { IntentSchemeServerProxy };
|
|
39
|
+
//# sourceMappingURL=IntentSchemeServerProxy.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ApiService } from '@dooboostore/simple-boot/fetch/ApiService';
|
|
2
|
+
export type Config<T = any> = {
|
|
3
|
+
multipartFormData?: boolean;
|
|
4
|
+
bypassTransform?: boolean;
|
|
5
|
+
transformText?: boolean;
|
|
6
|
+
headers?: HeadersInit;
|
|
7
|
+
body?: T;
|
|
8
|
+
};
|
|
9
|
+
export declare class SymbolIntentApiServiceProxy<T extends object> implements ProxyHandler<T> {
|
|
10
|
+
private apiService;
|
|
11
|
+
constructor(apiService: ApiService);
|
|
12
|
+
get(target: T, prop: string | symbol, receiver: any): any;
|
|
13
|
+
apply(target: T, thisArg: any, argArray: any[]): any;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=SymbolIntentApiServiceProxy.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { getSim, Sim } from '@dooboostore/simple-boot/decorators/SimDecorator';
|
|
3
|
+
import { makeIntentHeaderBySymbol } from '../codes/HttpHeaders';
|
|
4
|
+
import { ConvertUtils } from '@dooboostore/core/convert/ConvertUtils';
|
|
5
|
+
import { ApiService } from '@dooboostore/simple-boot/fetch/ApiService';
|
|
6
|
+
let SymbolIntentApiServiceProxy = class SymbolIntentApiServiceProxy {
|
|
7
|
+
constructor(apiService) {
|
|
8
|
+
this.apiService = apiService;
|
|
9
|
+
}
|
|
10
|
+
get(target, prop, receiver) {
|
|
11
|
+
const simConfig = getSim(target);
|
|
12
|
+
const apiService = this.apiService;
|
|
13
|
+
const value = Reflect.get(target, prop, receiver);
|
|
14
|
+
if (typeof value === 'function' && (simConfig === null || simConfig === void 0 ? void 0 : simConfig.symbol)) {
|
|
15
|
+
return function (...args) {
|
|
16
|
+
const f = value;
|
|
17
|
+
const p = (userConfig) => {
|
|
18
|
+
var _a;
|
|
19
|
+
const headers = Object.assign(Object.assign({}, ((_a = userConfig === null || userConfig === void 0 ? void 0 : userConfig.headers) !== null && _a !== void 0 ? _a : {})), makeIntentHeaderBySymbol(simConfig.symbol));
|
|
20
|
+
if (userConfig === null || userConfig === void 0 ? void 0 : userConfig.multipartFormData) {
|
|
21
|
+
return apiService.post({
|
|
22
|
+
target: `/${String(prop)}`,
|
|
23
|
+
config: {
|
|
24
|
+
bypassTransform: userConfig === null || userConfig === void 0 ? void 0 : userConfig.bypassTransform,
|
|
25
|
+
transformText: userConfig === null || userConfig === void 0 ? void 0 : userConfig.transformText,
|
|
26
|
+
fetch: {
|
|
27
|
+
credentials: 'include',
|
|
28
|
+
headers: headers,
|
|
29
|
+
body: ConvertUtils.toFormData(userConfig === null || userConfig === void 0 ? void 0 : userConfig.body)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return apiService.postJson({
|
|
36
|
+
target: `/${String(prop)}`,
|
|
37
|
+
config: {
|
|
38
|
+
bypassTransform: userConfig === null || userConfig === void 0 ? void 0 : userConfig.bypassTransform,
|
|
39
|
+
transformText: userConfig === null || userConfig === void 0 ? void 0 : userConfig.transformText,
|
|
40
|
+
fetch: {
|
|
41
|
+
credentials: 'include',
|
|
42
|
+
headers: headers,
|
|
43
|
+
body: userConfig === null || userConfig === void 0 ? void 0 : userConfig.body
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
args.push(p);
|
|
50
|
+
return Reflect.apply(f, target, args);
|
|
51
|
+
// return f.apply(target, args);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return Reflect.get(target, prop, receiver);
|
|
55
|
+
}
|
|
56
|
+
apply(target, thisArg, argArray) {
|
|
57
|
+
console.log('SymbolIntentApiServiceProxy apply');
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
return Reflect.apply(target, thisArg, argArray);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
SymbolIntentApiServiceProxy = __decorate([
|
|
63
|
+
Sim,
|
|
64
|
+
__metadata("design:paramtypes", [ApiService])
|
|
65
|
+
], SymbolIntentApiServiceProxy);
|
|
66
|
+
export { SymbolIntentApiServiceProxy };
|
|
67
|
+
//# sourceMappingURL=SymbolIntentApiServiceProxy.js.map
|