@modern-js/prod-server 2.0.0-beta.0 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/dist/js/modern/constants.js +0 -2
- package/dist/js/modern/index.js +0 -1
- package/dist/js/modern/libs/context/context.js +10 -56
- package/dist/js/modern/libs/hook-api/index.js +0 -31
- package/dist/js/modern/libs/hook-api/route.js +0 -8
- package/dist/js/modern/libs/hook-api/template.js +0 -16
- package/dist/js/modern/libs/loadConfig.js +3 -10
- package/dist/js/modern/libs/metrics.js +6 -6
- package/dist/js/modern/libs/proxy.js +7 -12
- package/dist/js/modern/libs/render/cache/__tests__/cache.fun.test.js +0 -1
- package/dist/js/modern/libs/render/cache/__tests__/cache.test.js +0 -9
- package/dist/js/modern/libs/render/cache/index.js +8 -16
- package/dist/js/modern/libs/render/cache/page-caches/lru.js +0 -10
- package/dist/js/modern/libs/render/cache/spr.js +12 -62
- package/dist/js/modern/libs/render/cache/util.js +0 -6
- package/dist/js/modern/libs/render/index.js +6 -11
- package/dist/js/modern/libs/render/measure.js +1 -11
- package/dist/js/modern/libs/render/modern/index.js +2 -13
- package/dist/js/modern/libs/render/reader.js +13 -24
- package/dist/js/modern/libs/render/ssr.js +5 -6
- package/dist/js/modern/libs/render/static.js +6 -9
- package/dist/js/modern/libs/render/type.js +0 -1
- package/dist/js/modern/libs/route/index.js +8 -19
- package/dist/js/modern/libs/route/matcher.js +21 -29
- package/dist/js/modern/libs/route/route.js +0 -13
- package/dist/js/modern/libs/serve-file.js +5 -6
- package/dist/js/modern/server/index.js +19 -41
- package/dist/js/modern/server/modern-server-split.js +0 -11
- package/dist/js/modern/server/modern-server.js +83 -164
- package/dist/js/modern/utils.js +2 -21
- package/dist/js/modern/worker-server.js +34 -0
- package/dist/js/node/constants.js +0 -2
- package/dist/js/node/index.js +0 -10
- package/dist/js/node/libs/context/context.js +10 -65
- package/dist/js/node/libs/context/index.js +0 -3
- package/dist/js/node/libs/hook-api/index.js +0 -42
- package/dist/js/node/libs/hook-api/route.js +0 -10
- package/dist/js/node/libs/hook-api/template.js +0 -22
- package/dist/js/node/libs/loadConfig.js +3 -22
- package/dist/js/node/libs/metrics.js +6 -6
- package/dist/js/node/libs/proxy.js +7 -17
- package/dist/js/node/libs/render/cache/__tests__/cache.fun.test.js +0 -5
- package/dist/js/node/libs/render/cache/__tests__/cache.test.js +0 -12
- package/dist/js/node/libs/render/cache/index.js +8 -22
- package/dist/js/node/libs/render/cache/page-caches/index.js +0 -2
- package/dist/js/node/libs/render/cache/page-caches/lru.js +0 -14
- package/dist/js/node/libs/render/cache/spr.js +12 -71
- package/dist/js/node/libs/render/cache/util.js +0 -18
- package/dist/js/node/libs/render/index.js +6 -26
- package/dist/js/node/libs/render/measure.js +0 -17
- package/dist/js/node/libs/render/modern/index.js +2 -20
- package/dist/js/node/libs/render/reader.js +12 -39
- package/dist/js/node/libs/render/ssr.js +4 -16
- package/dist/js/node/libs/render/static.js +6 -18
- package/dist/js/node/libs/render/type.js +0 -1
- package/dist/js/node/libs/route/index.js +8 -22
- package/dist/js/node/libs/route/matcher.js +18 -34
- package/dist/js/node/libs/route/route.js +0 -15
- package/dist/js/node/libs/serve-file.js +5 -13
- package/dist/js/node/server/index.js +19 -61
- package/dist/js/node/server/modern-server-split.js +0 -13
- package/dist/js/node/server/modern-server.js +83 -193
- package/dist/js/node/utils.js +3 -46
- package/dist/js/node/worker-server.js +41 -0
- package/dist/js/treeshaking/constants.js +28 -0
- package/dist/js/treeshaking/index.js +13 -0
- package/dist/js/treeshaking/libs/context/context.js +243 -0
- package/dist/js/treeshaking/libs/context/index.js +5 -0
- package/dist/js/treeshaking/libs/hook-api/index.js +157 -0
- package/dist/js/treeshaking/libs/hook-api/route.js +33 -0
- package/dist/js/treeshaking/libs/hook-api/template.js +91 -0
- package/dist/js/treeshaking/libs/loadConfig.js +39 -0
- package/dist/js/treeshaking/libs/metrics.js +12 -0
- package/dist/js/treeshaking/libs/proxy.js +80 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/cache.fun.test.js +124 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/cache.test.js +464 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/cacheable.js +53 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/error-configuration.js +35 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/matched-cache.js +121 -0
- package/dist/js/treeshaking/libs/render/cache/index.js +184 -0
- package/dist/js/treeshaking/libs/render/cache/page-caches/index.js +30 -0
- package/dist/js/treeshaking/libs/render/cache/page-caches/lru.js +46 -0
- package/dist/js/treeshaking/libs/render/cache/spr.js +362 -0
- package/dist/js/treeshaking/libs/render/cache/type.js +1 -0
- package/dist/js/treeshaking/libs/render/cache/util.js +101 -0
- package/dist/js/treeshaking/libs/render/index.js +100 -0
- package/dist/js/treeshaking/libs/render/measure.js +61 -0
- package/dist/js/treeshaking/libs/render/modern/browser-list.js +7 -0
- package/dist/js/treeshaking/libs/render/modern/index.js +39 -0
- package/dist/js/treeshaking/libs/render/reader.js +191 -0
- package/dist/js/treeshaking/libs/render/ssr.js +98 -0
- package/dist/js/treeshaking/libs/render/static.js +84 -0
- package/dist/js/treeshaking/libs/render/type.js +6 -0
- package/dist/js/treeshaking/libs/route/index.js +94 -0
- package/dist/js/treeshaking/libs/route/matcher.js +113 -0
- package/dist/js/treeshaking/libs/route/route.js +26 -0
- package/dist/js/treeshaking/libs/serve-file.js +75 -0
- package/dist/js/treeshaking/server/index.js +343 -0
- package/dist/js/treeshaking/server/modern-server-split.js +152 -0
- package/dist/js/treeshaking/server/modern-server.js +945 -0
- package/dist/js/treeshaking/type.js +1 -0
- package/dist/js/treeshaking/utils.js +87 -0
- package/dist/js/treeshaking/worker-server.js +56 -0
- package/dist/types/index.d.ts +0 -2
- package/dist/types/libs/context/context.d.ts +0 -3
- package/dist/types/libs/loadConfig.d.ts +0 -1
- package/dist/types/libs/render/cache/index.d.ts +0 -2
- package/dist/types/libs/render/cache/spr.d.ts +0 -2
- package/dist/types/server/index.d.ts +0 -3
- package/dist/types/utils.d.ts +0 -1
- package/dist/types/worker-server.d.ts +16 -0
- package/package.json +28 -12
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
const _excluded = ["getMiddlewares"];
|
|
2
|
-
|
|
3
2
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
4
|
-
|
|
5
3
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
6
|
-
|
|
7
4
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
8
|
-
|
|
9
5
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
10
|
-
|
|
11
6
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
12
|
-
|
|
13
7
|
/* eslint-disable max-lines */
|
|
14
8
|
import { createServer } from 'http';
|
|
15
9
|
import util from 'util';
|
|
@@ -29,8 +23,11 @@ const API_DIR = './api';
|
|
|
29
23
|
const SERVER_DIR = './server';
|
|
30
24
|
export class ModernServer {
|
|
31
25
|
// appDirectory
|
|
26
|
+
|
|
32
27
|
// product dist dir
|
|
28
|
+
|
|
33
29
|
// work on src or dist
|
|
30
|
+
|
|
34
31
|
constructor({
|
|
35
32
|
pwd,
|
|
36
33
|
config,
|
|
@@ -42,51 +39,28 @@ export class ModernServer {
|
|
|
42
39
|
proxyTarget
|
|
43
40
|
}) {
|
|
44
41
|
var _config$output;
|
|
45
|
-
|
|
46
42
|
_defineProperty(this, "pwd", void 0);
|
|
47
|
-
|
|
48
43
|
_defineProperty(this, "distDir", void 0);
|
|
49
|
-
|
|
50
44
|
_defineProperty(this, "workDir", void 0);
|
|
51
|
-
|
|
52
45
|
_defineProperty(this, "router", void 0);
|
|
53
|
-
|
|
54
46
|
_defineProperty(this, "conf", void 0);
|
|
55
|
-
|
|
56
47
|
_defineProperty(this, "handlers", []);
|
|
57
|
-
|
|
58
48
|
_defineProperty(this, "presetRoutes", void 0);
|
|
59
|
-
|
|
60
49
|
_defineProperty(this, "runner", void 0);
|
|
61
|
-
|
|
62
50
|
_defineProperty(this, "logger", void 0);
|
|
63
|
-
|
|
64
51
|
_defineProperty(this, "metrics", void 0);
|
|
65
|
-
|
|
66
52
|
_defineProperty(this, "runMode", void 0);
|
|
67
|
-
|
|
68
53
|
_defineProperty(this, "reader", reader);
|
|
69
|
-
|
|
70
54
|
_defineProperty(this, "proxyTarget", void 0);
|
|
71
|
-
|
|
72
55
|
_defineProperty(this, "staticFileHandler", void 0);
|
|
73
|
-
|
|
74
56
|
_defineProperty(this, "routeRenderHandler", void 0);
|
|
75
|
-
|
|
76
57
|
_defineProperty(this, "beforeRouteHandler", null);
|
|
77
|
-
|
|
78
58
|
_defineProperty(this, "frameWebHandler", null);
|
|
79
|
-
|
|
80
59
|
_defineProperty(this, "frameAPIHandler", null);
|
|
81
|
-
|
|
82
60
|
_defineProperty(this, "proxyHandler", null);
|
|
83
|
-
|
|
84
61
|
_defineProperty(this, "_handler", void 0);
|
|
85
|
-
|
|
86
62
|
_defineProperty(this, "staticGenerate", void 0);
|
|
87
|
-
|
|
88
63
|
require('ignore-styles');
|
|
89
|
-
|
|
90
64
|
this.pwd = pwd;
|
|
91
65
|
this.distDir = path.join(pwd, ((_config$output = config.output) === null || _config$output === void 0 ? void 0 : _config$output.path) || 'dist');
|
|
92
66
|
this.workDir = this.distDir;
|
|
@@ -98,43 +72,45 @@ export class ModernServer {
|
|
|
98
72
|
this.presetRoutes = routes;
|
|
99
73
|
this.proxyTarget = proxyTarget;
|
|
100
74
|
this.staticGenerate = staticGenerate || false;
|
|
101
|
-
this.runMode = runMode || RUN_MODE.FULL;
|
|
102
|
-
|
|
103
|
-
|
|
75
|
+
this.runMode = runMode || RUN_MODE.FULL;
|
|
76
|
+
// process.env.BUILD_TYPE = `${this.staticGenerate ? 'ssg' : 'ssr'}`;
|
|
77
|
+
}
|
|
104
78
|
|
|
79
|
+
// server prepare
|
|
105
80
|
async onInit(runner, app) {
|
|
106
81
|
var _conf$bff;
|
|
107
|
-
|
|
108
82
|
this.runner = runner;
|
|
109
83
|
const {
|
|
110
84
|
distDir,
|
|
111
85
|
staticGenerate,
|
|
112
86
|
conf
|
|
113
87
|
} = this;
|
|
114
|
-
debug('final server conf', this.conf);
|
|
115
|
-
|
|
88
|
+
debug('final server conf', this.conf);
|
|
89
|
+
// proxy handler, each proxy has own handler
|
|
116
90
|
this.proxyHandler = createProxyHandler((_conf$bff = conf.bff) === null || _conf$bff === void 0 ? void 0 : _conf$bff.proxy);
|
|
117
|
-
|
|
118
91
|
if (this.proxyHandler) {
|
|
119
92
|
this.proxyHandler.forEach(handler => {
|
|
120
93
|
this.addHandler(handler);
|
|
121
94
|
});
|
|
122
|
-
}
|
|
123
|
-
|
|
95
|
+
}
|
|
124
96
|
|
|
97
|
+
// start file reader
|
|
125
98
|
this.reader.init();
|
|
126
99
|
app.on('close', () => {
|
|
127
100
|
this.reader.close();
|
|
128
|
-
});
|
|
101
|
+
});
|
|
129
102
|
|
|
103
|
+
// use preset routes priority
|
|
130
104
|
const usageRoutes = this.filterRoutes(this.getRoutes());
|
|
131
|
-
this.router.reset(usageRoutes);
|
|
105
|
+
this.router.reset(usageRoutes);
|
|
132
106
|
|
|
107
|
+
// warmup ssr bundle in production env
|
|
133
108
|
this.warmupSSRBundle();
|
|
134
109
|
await this.prepareFrameHandler();
|
|
135
|
-
await this.prepareBeforeRouteHandler(usageRoutes, distDir);
|
|
136
|
-
// Setting `assetPrefix` means these resources should be uploaded to CDN.
|
|
110
|
+
await this.prepareBeforeRouteHandler(usageRoutes, distDir);
|
|
137
111
|
|
|
112
|
+
// Only work when without setting `assetPrefix`.
|
|
113
|
+
// Setting `assetPrefix` means these resources should be uploaded to CDN.
|
|
138
114
|
const staticPathRegExp = getStaticReg(this.conf.output || {});
|
|
139
115
|
this.staticFileHandler = createStaticFileHandler([{
|
|
140
116
|
path: staticPathRegExp,
|
|
@@ -145,34 +121,33 @@ export class ModernServer {
|
|
|
145
121
|
staticGenerate
|
|
146
122
|
});
|
|
147
123
|
await this.setupBeforeProdMiddleware();
|
|
148
|
-
this.addHandler(this.staticFileHandler);
|
|
124
|
+
this.addHandler(this.staticFileHandler);
|
|
149
125
|
|
|
126
|
+
// execute after staticFileHandler, can rename to staticFallbackHandler if needed.
|
|
150
127
|
this.addHandler(faviconFallbackHandler);
|
|
151
128
|
this.addBeforeRouteHandler();
|
|
152
|
-
this.addHandler(this.routeHandler.bind(this));
|
|
129
|
+
this.addHandler(this.routeHandler.bind(this));
|
|
153
130
|
|
|
131
|
+
// compose middlewares to http handler
|
|
154
132
|
this.compose();
|
|
155
|
-
} // server ready
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
onRepack(_) {// empty
|
|
159
133
|
}
|
|
160
134
|
|
|
135
|
+
// server ready
|
|
136
|
+
onRepack(_) {
|
|
137
|
+
// empty
|
|
138
|
+
}
|
|
161
139
|
addBeforeRouteHandler() {
|
|
162
140
|
this.addHandler(async (context, next) => {
|
|
163
141
|
if (this.beforeRouteHandler) {
|
|
164
142
|
await this.beforeRouteHandler(context);
|
|
165
|
-
|
|
166
143
|
if (this.isSend(context.res)) {
|
|
167
144
|
return;
|
|
168
145
|
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
146
|
+
}
|
|
147
|
+
// eslint-disable-next-line consistent-return
|
|
172
148
|
return next();
|
|
173
149
|
});
|
|
174
150
|
}
|
|
175
|
-
|
|
176
151
|
onServerChange({
|
|
177
152
|
filepath
|
|
178
153
|
}) {
|
|
@@ -191,73 +166,63 @@ export class ModernServer {
|
|
|
191
166
|
onlyWeb,
|
|
192
167
|
onlyApi
|
|
193
168
|
});
|
|
194
|
-
}
|
|
195
|
-
|
|
169
|
+
}
|
|
196
170
|
|
|
171
|
+
// exposed requestHandler
|
|
197
172
|
getRequestHandler() {
|
|
198
173
|
return this.requestHandler.bind(this);
|
|
199
174
|
}
|
|
200
|
-
|
|
201
175
|
async render(req, res, url) {
|
|
202
176
|
req.logger = this.logger;
|
|
203
177
|
req.metrics = this.metrics;
|
|
204
178
|
const context = createContext(req, res);
|
|
205
179
|
const matched = this.router.match(url || context.path);
|
|
206
|
-
|
|
207
180
|
if (!matched) {
|
|
208
181
|
return null;
|
|
209
182
|
}
|
|
210
|
-
|
|
211
183
|
const route = matched.generate(context.url);
|
|
212
184
|
const result = await this.handleWeb(context, route);
|
|
213
|
-
|
|
214
185
|
if (!result) {
|
|
215
186
|
return null;
|
|
216
187
|
}
|
|
217
|
-
|
|
218
188
|
return result.content.toString();
|
|
219
189
|
}
|
|
220
|
-
|
|
221
190
|
async createHTTPServer(handler) {
|
|
222
191
|
return createServer(handler);
|
|
223
192
|
}
|
|
193
|
+
|
|
224
194
|
/* —————————————————————— function will be overwrite —————————————————————— */
|
|
225
195
|
// get routes info
|
|
226
|
-
|
|
227
|
-
|
|
228
196
|
getRoutes() {
|
|
229
197
|
// Preferred to use preset routes
|
|
230
198
|
if (this.presetRoutes) {
|
|
231
199
|
return this.presetRoutes;
|
|
232
|
-
}
|
|
233
|
-
|
|
200
|
+
}
|
|
234
201
|
|
|
202
|
+
// read routes from spec file
|
|
235
203
|
const file = path.join(this.distDir, ROUTE_SPEC_FILE);
|
|
236
|
-
|
|
237
204
|
if (fs.existsSync(file)) {
|
|
238
205
|
const content = fs.readJSONSync(file);
|
|
239
206
|
return content.routes;
|
|
240
207
|
}
|
|
241
|
-
|
|
242
208
|
return [];
|
|
243
|
-
}
|
|
244
|
-
// handler should do not do more things after invoke next
|
|
245
|
-
|
|
209
|
+
}
|
|
246
210
|
|
|
211
|
+
// add promisify request handler to server
|
|
212
|
+
// handler should do not do more things after invoke next
|
|
247
213
|
addHandler(handler) {
|
|
248
214
|
if (handler[Symbol.toStringTag] === 'AsyncFunction') {
|
|
249
215
|
this.handlers.push(handler);
|
|
250
216
|
} else {
|
|
251
217
|
this.handlers.push(util.promisify(handler));
|
|
252
218
|
}
|
|
253
|
-
}
|
|
254
|
-
|
|
219
|
+
}
|
|
255
220
|
|
|
221
|
+
// return 404 page
|
|
256
222
|
render404(context) {
|
|
257
223
|
context.error(ERROR_DIGEST.ENOTF, '404 Not Found');
|
|
258
224
|
this.renderErrorPage(context, 404);
|
|
259
225
|
}
|
|
260
|
-
|
|
261
226
|
async prepareBeforeRouteHandler(specs, distDir) {
|
|
262
227
|
const {
|
|
263
228
|
runner
|
|
@@ -269,9 +234,9 @@ export class ModernServer {
|
|
|
269
234
|
onLast: () => null
|
|
270
235
|
});
|
|
271
236
|
this.beforeRouteHandler = handler;
|
|
272
|
-
}
|
|
273
|
-
|
|
237
|
+
}
|
|
274
238
|
|
|
239
|
+
// gather frame extension and get framework handler
|
|
275
240
|
async prepareFrameHandler(options) {
|
|
276
241
|
const {
|
|
277
242
|
workDir,
|
|
@@ -280,33 +245,32 @@ export class ModernServer {
|
|
|
280
245
|
const {
|
|
281
246
|
onlyApi,
|
|
282
247
|
onlyWeb
|
|
283
|
-
} = options || {};
|
|
248
|
+
} = options || {};
|
|
284
249
|
|
|
250
|
+
// server hook, gather plugin inject
|
|
285
251
|
const _createMiddlewareColl = createMiddlewareCollecter(),
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
252
|
+
{
|
|
253
|
+
getMiddlewares
|
|
254
|
+
} = _createMiddlewareColl,
|
|
255
|
+
collector = _objectWithoutProperties(_createMiddlewareColl, _excluded);
|
|
291
256
|
await runner.gather(collector);
|
|
292
257
|
const {
|
|
293
258
|
api: pluginAPIExt,
|
|
294
259
|
web: pluginWebExt
|
|
295
260
|
} = getMiddlewares();
|
|
296
261
|
const apiDir = path.join(workDir, API_DIR);
|
|
297
|
-
const serverDir = path.join(workDir, SERVER_DIR);
|
|
262
|
+
const serverDir = path.join(workDir, SERVER_DIR);
|
|
298
263
|
|
|
264
|
+
// get api or web server handler from server-framework plugin
|
|
299
265
|
if ((await fs.pathExists(path.join(serverDir))) && !onlyApi) {
|
|
300
266
|
const webExtension = mergeExtension(pluginWebExt);
|
|
301
267
|
this.frameWebHandler = await this.prepareWebHandler(webExtension);
|
|
302
268
|
}
|
|
303
|
-
|
|
304
269
|
if (fs.existsSync(apiDir) && !onlyWeb) {
|
|
305
270
|
const apiExtension = mergeExtension(pluginAPIExt);
|
|
306
271
|
this.frameAPIHandler = await this.prepareAPIHandler(apiExtension);
|
|
307
272
|
}
|
|
308
273
|
}
|
|
309
|
-
|
|
310
274
|
async prepareWebHandler(extension) {
|
|
311
275
|
const {
|
|
312
276
|
workDir,
|
|
@@ -320,7 +284,6 @@ export class ModernServer {
|
|
|
320
284
|
});
|
|
321
285
|
return handler;
|
|
322
286
|
}
|
|
323
|
-
|
|
324
287
|
async prepareAPIHandler(extension) {
|
|
325
288
|
const {
|
|
326
289
|
workDir,
|
|
@@ -339,11 +302,9 @@ export class ModernServer {
|
|
|
339
302
|
onLast: () => null
|
|
340
303
|
});
|
|
341
304
|
}
|
|
342
|
-
|
|
343
305
|
filterRoutes(routes) {
|
|
344
306
|
return routes;
|
|
345
307
|
}
|
|
346
|
-
|
|
347
308
|
async setupBeforeProdMiddleware() {
|
|
348
309
|
const {
|
|
349
310
|
conf,
|
|
@@ -354,20 +315,16 @@ export class ModernServer {
|
|
|
354
315
|
this.addHandler(mid);
|
|
355
316
|
});
|
|
356
317
|
}
|
|
357
|
-
|
|
358
318
|
async handleAPI(context) {
|
|
359
319
|
const {
|
|
360
320
|
req,
|
|
361
321
|
res
|
|
362
322
|
} = context;
|
|
363
|
-
|
|
364
323
|
if (!this.frameAPIHandler) {
|
|
365
324
|
throw new Error('can not found api handler');
|
|
366
325
|
}
|
|
367
|
-
|
|
368
326
|
await this.frameAPIHandler(req, res);
|
|
369
327
|
}
|
|
370
|
-
|
|
371
328
|
async handleWeb(context, route) {
|
|
372
329
|
return this.routeRenderHandler({
|
|
373
330
|
ctx: context,
|
|
@@ -375,231 +332,198 @@ export class ModernServer {
|
|
|
375
332
|
runner: this.runner
|
|
376
333
|
});
|
|
377
334
|
}
|
|
378
|
-
|
|
379
335
|
async proxy() {
|
|
380
336
|
return null;
|
|
381
|
-
}
|
|
382
|
-
|
|
337
|
+
}
|
|
383
338
|
|
|
339
|
+
// warmup ssr function
|
|
384
340
|
warmupSSRBundle() {
|
|
385
341
|
const {
|
|
386
342
|
distDir
|
|
387
343
|
} = this;
|
|
388
344
|
const bundles = this.router.getBundles();
|
|
389
345
|
bundles.forEach(bundle => {
|
|
390
|
-
const filepath = path.join(distDir, bundle);
|
|
391
|
-
|
|
346
|
+
const filepath = path.join(distDir, bundle);
|
|
347
|
+
// if error, just throw and let process die
|
|
392
348
|
require(filepath);
|
|
393
349
|
});
|
|
394
350
|
}
|
|
395
|
-
|
|
396
351
|
createContext(req, res, options = {}) {
|
|
397
352
|
return createContext(req, res, options);
|
|
398
353
|
}
|
|
354
|
+
|
|
399
355
|
/* —————————————————————— private function —————————————————————— */
|
|
400
356
|
// handler route.json, include api / csr / ssr
|
|
401
|
-
|
|
402
|
-
|
|
403
357
|
async routeHandler(context) {
|
|
404
358
|
const {
|
|
405
359
|
res
|
|
406
|
-
} = context;
|
|
360
|
+
} = context;
|
|
407
361
|
|
|
362
|
+
// match routes in the route spec
|
|
408
363
|
const matched = this.router.match(context.path);
|
|
409
|
-
|
|
410
364
|
if (!matched) {
|
|
411
365
|
this.render404(context);
|
|
412
366
|
return;
|
|
413
|
-
}
|
|
414
|
-
|
|
367
|
+
}
|
|
415
368
|
|
|
369
|
+
// route is api service
|
|
416
370
|
let route = matched.generate(context.url);
|
|
417
|
-
|
|
418
371
|
if (route.isApi) {
|
|
419
372
|
await this.handleAPI(context);
|
|
420
373
|
return;
|
|
421
374
|
}
|
|
375
|
+
const afterMatchContext = createAfterMatchContext(context, route.entryName);
|
|
422
376
|
|
|
423
|
-
|
|
424
|
-
|
|
377
|
+
// only full mode run server hook
|
|
425
378
|
if (this.runMode === RUN_MODE.FULL) {
|
|
426
379
|
await this.runner.afterMatch(afterMatchContext, {
|
|
427
380
|
onLast: noop
|
|
428
381
|
});
|
|
429
382
|
}
|
|
430
|
-
|
|
431
383
|
if (this.isSend(res)) {
|
|
432
384
|
return;
|
|
433
385
|
}
|
|
434
|
-
|
|
435
386
|
const {
|
|
436
387
|
current,
|
|
437
388
|
url,
|
|
438
389
|
status
|
|
439
|
-
} = afterMatchContext.router;
|
|
440
|
-
|
|
390
|
+
} = afterMatchContext.router;
|
|
391
|
+
// redirect to another url
|
|
441
392
|
if (url) {
|
|
442
393
|
this.redirect(res, url, status);
|
|
443
394
|
return;
|
|
444
|
-
}
|
|
445
|
-
|
|
395
|
+
}
|
|
446
396
|
|
|
397
|
+
// rewrite to another entry
|
|
447
398
|
if (route.entryName !== current) {
|
|
448
399
|
const matched = this.router.matchEntry(current);
|
|
449
|
-
|
|
450
400
|
if (!matched) {
|
|
451
401
|
this.render404(context);
|
|
452
402
|
return;
|
|
453
403
|
}
|
|
454
|
-
|
|
455
404
|
route = matched.generate(context.url);
|
|
456
405
|
}
|
|
457
|
-
|
|
458
406
|
context.setParams(route.params);
|
|
459
407
|
context.setServerData('router', {
|
|
460
408
|
baseUrl: route.urlPath,
|
|
461
409
|
params: route.params
|
|
462
410
|
});
|
|
463
|
-
|
|
464
411
|
if (this.frameWebHandler) {
|
|
465
412
|
res.locals = res.locals || {};
|
|
466
413
|
const middlewareContext = createMiddlewareContext(context);
|
|
467
414
|
await this.frameWebHandler(middlewareContext);
|
|
468
415
|
res.locals = _objectSpread(_objectSpread({}, res.locals), middlewareContext.response.locals);
|
|
469
|
-
}
|
|
470
|
-
|
|
416
|
+
}
|
|
471
417
|
|
|
418
|
+
// frameWebHandler has process request
|
|
472
419
|
if (this.isSend(res)) {
|
|
473
420
|
return;
|
|
474
421
|
}
|
|
475
|
-
|
|
476
422
|
if (route.responseHeaders) {
|
|
477
423
|
Object.keys(route.responseHeaders).forEach(key => {
|
|
478
424
|
const value = route.responseHeaders[key];
|
|
479
|
-
|
|
480
425
|
if (value) {
|
|
481
426
|
context.res.setHeader(key, value);
|
|
482
427
|
}
|
|
483
428
|
});
|
|
484
429
|
}
|
|
485
|
-
|
|
486
430
|
const renderResult = await this.handleWeb(context, route);
|
|
487
|
-
|
|
488
431
|
if (!renderResult) {
|
|
489
432
|
this.render404(context);
|
|
490
433
|
return;
|
|
491
|
-
}
|
|
492
|
-
|
|
434
|
+
}
|
|
493
435
|
|
|
436
|
+
// React Router navigation
|
|
494
437
|
if (renderResult.redirect) {
|
|
495
438
|
this.redirect(res, renderResult.content, renderResult.statusCode);
|
|
496
439
|
return;
|
|
497
440
|
}
|
|
498
|
-
|
|
499
441
|
if (this.isSend(res)) {
|
|
500
442
|
return;
|
|
501
443
|
}
|
|
502
|
-
|
|
503
444
|
res.setHeader('content-type', renderResult.contentType);
|
|
504
445
|
const {
|
|
505
446
|
contentStream
|
|
506
447
|
} = renderResult;
|
|
507
|
-
|
|
508
448
|
if (contentStream) {
|
|
509
449
|
contentStream.pipe(templateInjectableStream({
|
|
510
450
|
prependHead: route.entryName ? `<script>window._SERVER_DATA=${JSON.stringify(context.serverData)}</script>` : undefined
|
|
511
451
|
})).pipe(res);
|
|
512
452
|
return;
|
|
513
453
|
}
|
|
514
|
-
|
|
515
454
|
let response = renderResult.content;
|
|
516
|
-
|
|
517
455
|
if (route.entryName) {
|
|
518
|
-
const afterRenderContext = createAfterRenderContext(context, response.toString());
|
|
519
|
-
// FIXME: how to run server hook in streaming
|
|
456
|
+
const afterRenderContext = createAfterRenderContext(context, response.toString());
|
|
520
457
|
|
|
458
|
+
// only full mode run server hook
|
|
459
|
+
// FIXME: how to run server hook in streaming
|
|
521
460
|
if (this.runMode === RUN_MODE.FULL) {
|
|
522
461
|
await this.runner.afterRender(afterRenderContext, {
|
|
523
462
|
onLast: noop
|
|
524
463
|
});
|
|
525
464
|
}
|
|
526
|
-
|
|
527
465
|
if (this.isSend(res)) {
|
|
528
466
|
return;
|
|
529
|
-
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// It will inject _SERVER_DATA twice, when SSG mode.
|
|
530
470
|
// The first time was in ssg html created, the seoncd time was in prod-server start.
|
|
531
471
|
// but the second wound causes route error.
|
|
532
472
|
// To ensure that the second injection fails, the _SERVER_DATA inject at the front of head,
|
|
533
|
-
|
|
534
|
-
|
|
535
473
|
afterRenderContext.template.prependHead(`<script>window._SERVER_DATA=${JSON.stringify(context.serverData)}</script>`);
|
|
536
474
|
response = afterRenderContext.template.get();
|
|
537
475
|
}
|
|
538
|
-
|
|
539
476
|
res.end(response);
|
|
540
477
|
}
|
|
541
|
-
|
|
542
478
|
isSend(res) {
|
|
543
479
|
if (res.headersSent) {
|
|
544
480
|
return true;
|
|
545
481
|
}
|
|
546
|
-
|
|
547
482
|
if (res.getHeader('Location') && isRedirect(res.statusCode)) {
|
|
548
483
|
res.end();
|
|
549
484
|
return true;
|
|
550
485
|
}
|
|
551
|
-
|
|
552
486
|
return false;
|
|
553
|
-
}
|
|
554
|
-
|
|
487
|
+
}
|
|
555
488
|
|
|
489
|
+
// compose handlers and create the final handler
|
|
556
490
|
compose() {
|
|
557
491
|
const {
|
|
558
492
|
handlers
|
|
559
493
|
} = this;
|
|
560
|
-
|
|
561
494
|
if (!Array.isArray(handlers)) {
|
|
562
495
|
throw new TypeError('Middleware stack must be an array!');
|
|
563
496
|
}
|
|
564
|
-
|
|
565
497
|
for (const fn of handlers) {
|
|
566
498
|
if (typeof fn !== 'function') {
|
|
567
499
|
throw new TypeError('Middleware must be composed of functions!');
|
|
568
500
|
}
|
|
569
501
|
}
|
|
570
|
-
|
|
571
502
|
this._handler = (context, next) => {
|
|
572
503
|
let i = 0;
|
|
573
|
-
|
|
574
504
|
const dispatch = error => {
|
|
575
505
|
if (error) {
|
|
576
506
|
return this.onError(context, error);
|
|
577
507
|
}
|
|
578
|
-
|
|
579
508
|
const handler = handlers[i++];
|
|
580
|
-
|
|
581
509
|
if (!handler) {
|
|
582
510
|
return next();
|
|
583
511
|
}
|
|
584
|
-
|
|
585
512
|
return handler(context, dispatch).catch(onError);
|
|
586
513
|
};
|
|
587
|
-
|
|
588
514
|
const onError = err => {
|
|
589
515
|
this.onError(context, err);
|
|
590
516
|
};
|
|
591
|
-
|
|
592
517
|
return dispatch();
|
|
593
518
|
};
|
|
594
519
|
}
|
|
595
|
-
|
|
596
|
-
|
|
520
|
+
requestHandler(req, res, next = () => {
|
|
521
|
+
// empty
|
|
597
522
|
}) {
|
|
598
523
|
res.statusCode = 200;
|
|
599
524
|
req.logger = this.logger;
|
|
600
525
|
req.metrics = this.metrics;
|
|
601
526
|
let context;
|
|
602
|
-
|
|
603
527
|
try {
|
|
604
528
|
context = this.createContext(req, res);
|
|
605
529
|
} catch (e) {
|
|
@@ -608,25 +532,21 @@ export class ModernServer {
|
|
|
608
532
|
res.setHeader('content-type', mime.contentType('html'));
|
|
609
533
|
return res.end(createErrorDocument(500, ERROR_PAGE_TEXT[500]));
|
|
610
534
|
}
|
|
611
|
-
|
|
612
535
|
try {
|
|
613
536
|
return this._handler(context, next);
|
|
614
537
|
} catch (err) {
|
|
615
538
|
return this.onError(context, err);
|
|
616
539
|
}
|
|
617
540
|
}
|
|
618
|
-
|
|
619
541
|
redirect(res, url, status = 302) {
|
|
620
542
|
res.setHeader('Location', url);
|
|
621
543
|
res.statusCode = status;
|
|
622
544
|
res.end();
|
|
623
545
|
}
|
|
624
|
-
|
|
625
546
|
onError(context, err) {
|
|
626
547
|
context.error(ERROR_DIGEST.EINTER, err);
|
|
627
548
|
this.renderErrorPage(context, 500);
|
|
628
549
|
}
|
|
629
|
-
|
|
630
550
|
async renderErrorPage(context, status) {
|
|
631
551
|
const {
|
|
632
552
|
res
|
|
@@ -635,14 +555,15 @@ export class ModernServer {
|
|
|
635
555
|
res.setHeader('content-type', mime.contentType('html'));
|
|
636
556
|
const statusPage = `/${status}`;
|
|
637
557
|
const customErrorPage = `/_error`;
|
|
638
|
-
const matched = this.router.match(statusPage) || this.router.match(customErrorPage);
|
|
558
|
+
const matched = this.router.match(statusPage) || this.router.match(customErrorPage);
|
|
559
|
+
// if no custom status page find
|
|
639
560
|
|
|
640
561
|
if (matched) {
|
|
641
562
|
const route = matched.generate(context.url);
|
|
642
563
|
const {
|
|
643
564
|
entryName
|
|
644
|
-
} = route;
|
|
645
|
-
|
|
565
|
+
} = route;
|
|
566
|
+
// check entryName, avoid matched '/' route
|
|
646
567
|
if (entryName === status.toString() || entryName === '_error') {
|
|
647
568
|
try {
|
|
648
569
|
const file = await this.routeRenderHandler({
|
|
@@ -650,19 +571,17 @@ export class ModernServer {
|
|
|
650
571
|
ctx: context,
|
|
651
572
|
runner: this.runner
|
|
652
573
|
});
|
|
653
|
-
|
|
654
574
|
if (file) {
|
|
655
575
|
context.res.end(file.content);
|
|
656
576
|
return;
|
|
657
577
|
}
|
|
658
|
-
} catch (e) {
|
|
578
|
+
} catch (e) {
|
|
579
|
+
// just catch error when the rendering error occurred in the custom error page.
|
|
659
580
|
}
|
|
660
581
|
}
|
|
661
582
|
}
|
|
662
|
-
|
|
663
583
|
const text = ERROR_PAGE_TEXT[status] || ERROR_PAGE_TEXT[500];
|
|
664
584
|
context.res.end(createErrorDocument(status, text));
|
|
665
585
|
}
|
|
666
|
-
|
|
667
586
|
}
|
|
668
587
|
/* eslint-enable max-lines */
|