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