@modern-js/prod-server 1.21.3 → 2.0.0-beta.0
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 +43 -3
- package/dist/js/modern/libs/hook-api/index.js +156 -0
- package/dist/js/modern/libs/hook-api/route.js +14 -29
- package/dist/js/modern/libs/hook-api/template.js +43 -4
- package/dist/js/modern/libs/render/cache/index.js +33 -16
- package/dist/js/modern/libs/render/measure.js +8 -1
- package/dist/js/modern/libs/render/ssr.js +20 -7
- package/dist/js/modern/libs/serve-file.js +8 -0
- package/dist/js/modern/server/index.js +9 -3
- package/dist/js/modern/server/modern-server-split.js +5 -44
- package/dist/js/modern/server/modern-server.js +140 -130
- package/dist/js/node/libs/hook-api/index.js +178 -0
- package/dist/js/node/libs/hook-api/route.js +14 -29
- package/dist/js/node/libs/hook-api/template.js +48 -4
- package/dist/js/node/libs/render/cache/index.js +34 -16
- package/dist/js/node/libs/render/measure.js +7 -0
- package/dist/js/node/libs/render/ssr.js +20 -7
- package/dist/js/node/libs/serve-file.js +12 -1
- package/dist/js/node/server/index.js +8 -2
- package/dist/js/node/server/modern-server-split.js +5 -45
- package/dist/js/node/server/modern-server.js +140 -132
- 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/render/cache/index.d.ts +4 -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 -0
- package/dist/types/server/modern-server.d.ts +11 -11
- package/dist/types/type.d.ts +8 -10
- package/package.json +9 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,51 @@
|
|
|
1
1
|
# @modern-js/prod-server
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 2.0.0-beta.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- dda38c9: chore: v2
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- c9e800d39: feat: support React18 streaming SSR
|
|
12
|
+
feat: 支持 React18 流式 SSR
|
|
13
|
+
- 543be95: feat: compile server loader and support handle loader request
|
|
14
|
+
feat: 编译 server loader 并支持处理 loader 的请求
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
|
6
17
|
|
|
7
|
-
-
|
|
8
|
-
|
|
18
|
+
- 15bf09d9c: feat: support completely custom server, export render() api for render single page
|
|
19
|
+
feat: 支持完全自定义 Server,导出 render() 方法用来渲染单个页面
|
|
20
|
+
- cc971eabf: refactor: move server plugin load logic in `@modern-js/core`
|
|
21
|
+
refactor:移除在 `@modern-js/core` 中的 server 插件加载逻辑
|
|
22
|
+
- 102d32e4b: feat(server): add `req` and `res` to SSR context
|
|
23
|
+
|
|
24
|
+
feat(server): 添加 `req` 和 `res` 到 SSR context 中
|
|
25
|
+
|
|
26
|
+
- 3bbea92b2: feat: support Hook、Middleware new API
|
|
27
|
+
feat: 支持 Hook、Middleware 的新 API
|
|
28
|
+
- 73cd29dd9: fix(server): add favicon fallback handler
|
|
29
|
+
|
|
30
|
+
fix(server): 添加 favicon 兜底处理逻辑
|
|
31
|
+
|
|
32
|
+
- 14b712d: fix: use consistent alias type and default value across packages
|
|
33
|
+
|
|
34
|
+
fix: 在各个包中使用一致的 alias 类型定义和默认值
|
|
35
|
+
|
|
36
|
+
- Updated dependencies [15bf09d9c]
|
|
37
|
+
- Updated dependencies [edd1cfb1a]
|
|
38
|
+
- Updated dependencies [cc971eabf]
|
|
39
|
+
- Updated dependencies [5b9049f]
|
|
40
|
+
- Updated dependencies [b8bbe036c]
|
|
41
|
+
- Updated dependencies [d5a31df78]
|
|
42
|
+
- Updated dependencies [dda38c9]
|
|
43
|
+
- Updated dependencies [3bbea92b2]
|
|
44
|
+
- Updated dependencies [abf3421]
|
|
45
|
+
- Updated dependencies [543be95]
|
|
46
|
+
- Updated dependencies [14b712d]
|
|
47
|
+
- @modern-js/server-core@2.0.0-beta.0
|
|
48
|
+
- @modern-js/utils@2.0.0-beta.0
|
|
9
49
|
|
|
10
50
|
## 1.21.2
|
|
11
51
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
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; }
|
|
2
|
+
|
|
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; }
|
|
4
|
+
|
|
5
|
+
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; }
|
|
6
|
+
|
|
7
|
+
import cookie from 'cookie';
|
|
8
|
+
import { RouteAPI } from "./route";
|
|
9
|
+
import { TemplateAPI } from "./template";
|
|
10
|
+
|
|
11
|
+
class Response {
|
|
12
|
+
constructor(res) {
|
|
13
|
+
_defineProperty(this, "cookies", void 0);
|
|
14
|
+
|
|
15
|
+
_defineProperty(this, "res", void 0);
|
|
16
|
+
|
|
17
|
+
_defineProperty(this, "_cookie", void 0);
|
|
18
|
+
|
|
19
|
+
this.res = res;
|
|
20
|
+
this._cookie = cookie.parse(res.getHeader('set-cookie') || '');
|
|
21
|
+
this.cookies = {
|
|
22
|
+
get: this.getCookie.bind(this),
|
|
23
|
+
set: this.setCookie.bind(this),
|
|
24
|
+
delete: this.deleteCookie.bind(this),
|
|
25
|
+
clear: this.clearCookie.bind(this),
|
|
26
|
+
apply: this.applyCookie.bind(this)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get(key) {
|
|
31
|
+
return this.res.getHeader(key);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
set(key, value) {
|
|
35
|
+
return this.res.setHeader(key, value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
status(code) {
|
|
39
|
+
this.res.statusCode = code;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getCookie(key) {
|
|
43
|
+
return this._cookie[key];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setCookie(key, value) {
|
|
47
|
+
this._cookie[key] = value;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
deleteCookie(key) {
|
|
51
|
+
if (this._cookie[key]) {
|
|
52
|
+
delete this._cookie[key];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
clearCookie() {
|
|
57
|
+
this._cookie = {};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
applyCookie() {
|
|
61
|
+
const str = Object.entries(this._cookie).map(([key, value]) => {
|
|
62
|
+
return cookie.serialize(key, value);
|
|
63
|
+
}).join('; ');
|
|
64
|
+
|
|
65
|
+
if (str) {
|
|
66
|
+
this.res.setHeader('set-cookie', str);
|
|
67
|
+
} else {
|
|
68
|
+
this.res.removeHeader('set-cookie');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
raw(body, {
|
|
73
|
+
status,
|
|
74
|
+
headers
|
|
75
|
+
}) {
|
|
76
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
77
|
+
this.res.setHeader(key, value);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (status) {
|
|
81
|
+
this.res.statusCode = status;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.res.end(body);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
class Request {
|
|
90
|
+
constructor(ctx) {
|
|
91
|
+
_defineProperty(this, "host", void 0);
|
|
92
|
+
|
|
93
|
+
_defineProperty(this, "pathname", void 0);
|
|
94
|
+
|
|
95
|
+
_defineProperty(this, "query", void 0);
|
|
96
|
+
|
|
97
|
+
_defineProperty(this, "headers", void 0);
|
|
98
|
+
|
|
99
|
+
_defineProperty(this, "cookie", void 0);
|
|
100
|
+
|
|
101
|
+
_defineProperty(this, "cookies", void 0);
|
|
102
|
+
|
|
103
|
+
_defineProperty(this, "_cookie", void 0);
|
|
104
|
+
|
|
105
|
+
this.host = ctx.host;
|
|
106
|
+
this.pathname = ctx.path;
|
|
107
|
+
this.query = ctx.query;
|
|
108
|
+
this.headers = ctx.headers;
|
|
109
|
+
this.cookie = ctx.headers.cookie || '';
|
|
110
|
+
this._cookie = cookie.parse(this.cookie);
|
|
111
|
+
this.cookies = {
|
|
112
|
+
get: this.getCookie.bind(this)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
getCookie(key) {
|
|
117
|
+
return this._cookie[key];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const base = context => {
|
|
123
|
+
const {
|
|
124
|
+
res
|
|
125
|
+
} = context;
|
|
126
|
+
return {
|
|
127
|
+
response: new Response(res),
|
|
128
|
+
request: new Request(context),
|
|
129
|
+
logger: context.logger,
|
|
130
|
+
metrics: context.metrics
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
export const createAfterMatchContext = (context, entryName) => {
|
|
134
|
+
const baseContext = base(context);
|
|
135
|
+
return _objectSpread(_objectSpread({}, baseContext), {}, {
|
|
136
|
+
router: new RouteAPI(entryName)
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
export const createAfterRenderContext = (context, content) => {
|
|
140
|
+
const baseContext = base(context);
|
|
141
|
+
return _objectSpread(_objectSpread({}, baseContext), {}, {
|
|
142
|
+
template: new TemplateAPI(content)
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
export const createMiddlewareContext = context => {
|
|
146
|
+
const baseContext = base(context);
|
|
147
|
+
return _objectSpread(_objectSpread({}, baseContext), {}, {
|
|
148
|
+
response: _objectSpread(_objectSpread({}, baseContext.response), {}, {
|
|
149
|
+
locals: context.res.locals || {}
|
|
150
|
+
}),
|
|
151
|
+
source: {
|
|
152
|
+
req: context.req,
|
|
153
|
+
res: context.res
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
};
|
|
@@ -1,44 +1,29 @@
|
|
|
1
1
|
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; }
|
|
2
2
|
|
|
3
|
-
class RouteAPI {
|
|
4
|
-
constructor(
|
|
5
|
-
_defineProperty(this, "router", void 0);
|
|
6
|
-
|
|
3
|
+
export class RouteAPI {
|
|
4
|
+
constructor(entryName) {
|
|
7
5
|
_defineProperty(this, "current", void 0);
|
|
8
6
|
|
|
7
|
+
_defineProperty(this, "status", void 0);
|
|
8
|
+
|
|
9
9
|
_defineProperty(this, "url", void 0);
|
|
10
10
|
|
|
11
|
-
this.current =
|
|
12
|
-
this.
|
|
13
|
-
this.url =
|
|
11
|
+
this.current = entryName;
|
|
12
|
+
this.status = 200;
|
|
13
|
+
this.url = '';
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
redirect(url, status = 302) {
|
|
17
|
+
this.url = url;
|
|
18
|
+
this.status = status;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
router
|
|
23
|
-
} = this;
|
|
24
|
-
const matched = router.matchEntry(entryName);
|
|
25
|
-
return matched ? matched.generate(this.url) : null;
|
|
21
|
+
rewrite(entryName) {
|
|
22
|
+
this.current = entryName;
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
use(entryName) {
|
|
29
|
-
|
|
30
|
-
router
|
|
31
|
-
} = this;
|
|
32
|
-
const matched = router.matchEntry(entryName);
|
|
33
|
-
|
|
34
|
-
if (matched) {
|
|
35
|
-
this.current = matched;
|
|
36
|
-
return true;
|
|
37
|
-
} else {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
26
|
+
this.rewrite(entryName);
|
|
40
27
|
}
|
|
41
28
|
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const createRouteAPI = (matched, router, url) => new RouteAPI(matched, router, url);
|
|
29
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
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; }
|
|
2
2
|
|
|
3
|
+
import { Transform } from 'stream';
|
|
3
4
|
const RegList = {
|
|
4
5
|
before: {
|
|
5
6
|
head: '<head>',
|
|
@@ -10,8 +11,7 @@ const RegList = {
|
|
|
10
11
|
body: '</body>'
|
|
11
12
|
}
|
|
12
13
|
};
|
|
13
|
-
|
|
14
|
-
class TemplateAPI {
|
|
14
|
+
export class TemplateAPI {
|
|
15
15
|
constructor(content) {
|
|
16
16
|
_defineProperty(this, "content", void 0);
|
|
17
17
|
|
|
@@ -56,9 +56,48 @@ class TemplateAPI {
|
|
|
56
56
|
|
|
57
57
|
replace(reg, text) {
|
|
58
58
|
this.content = this.content.replace(reg, text);
|
|
59
|
-
return this;
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
}
|
|
62
|
+
export const templateInjectableStream = ({
|
|
63
|
+
prependHead,
|
|
64
|
+
appendHead,
|
|
65
|
+
prependBody,
|
|
66
|
+
appendBody
|
|
67
|
+
}) => new Transform({
|
|
68
|
+
write(chunk, _, callback) {
|
|
69
|
+
let chunk_str = chunk.toString();
|
|
70
|
+
|
|
71
|
+
if (prependHead) {
|
|
72
|
+
const {
|
|
73
|
+
head
|
|
74
|
+
} = RegList.before;
|
|
75
|
+
chunk_str = chunk_str.replace(head, `${head}${prependHead}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (appendHead) {
|
|
79
|
+
const {
|
|
80
|
+
head
|
|
81
|
+
} = RegList.after;
|
|
82
|
+
chunk_str = chunk_str.replace(head, `${appendHead}${head}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (prependBody) {
|
|
86
|
+
const {
|
|
87
|
+
body
|
|
88
|
+
} = RegList.before;
|
|
89
|
+
chunk_str = chunk_str.replace(body, `${body}${prependBody}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (appendBody) {
|
|
93
|
+
const {
|
|
94
|
+
body
|
|
95
|
+
} = RegList.after;
|
|
96
|
+
chunk_str = chunk_str.replace(body, `${appendBody}${body}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.push(chunk_str);
|
|
100
|
+
callback();
|
|
101
|
+
}
|
|
63
102
|
|
|
64
|
-
|
|
103
|
+
});
|
|
@@ -4,6 +4,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
4
4
|
|
|
5
5
|
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; }
|
|
6
6
|
|
|
7
|
+
import { Transform } from 'stream';
|
|
7
8
|
import { ERROR_DIGEST } from "../../../constants";
|
|
8
9
|
import { createCache } from "./spr";
|
|
9
10
|
import { namespaceHash, withCoalescedInvoke } from "./util";
|
|
@@ -15,10 +16,28 @@ export default ((renderFn, ctx) => {
|
|
|
15
16
|
entry: context.entryName
|
|
16
17
|
}, context.request);
|
|
17
18
|
|
|
18
|
-
const cacheFile = await sprCache.get(cacheContext);
|
|
19
|
+
const cacheFile = await sprCache.get(cacheContext);
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
async function afterRender(source, onAfterRender) {
|
|
22
|
+
if (typeof source === 'string') {
|
|
23
|
+
await onAfterRender(source);
|
|
24
|
+
return source;
|
|
25
|
+
} else {
|
|
26
|
+
let htmlForStream = '';
|
|
27
|
+
const cacheStream = new Transform({
|
|
28
|
+
write(chunk, _, callback) {
|
|
29
|
+
htmlForStream += chunk.toString();
|
|
30
|
+
this.push(chunk);
|
|
31
|
+
callback();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
});
|
|
35
|
+
cacheStream.on('close', () => onAfterRender(htmlForStream));
|
|
36
|
+
return source(cacheStream);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function saveHtmlIntoCache(html) {
|
|
22
41
|
const {
|
|
23
42
|
cacheConfig
|
|
24
43
|
} = context;
|
|
@@ -26,34 +45,32 @@ export default ((renderFn, ctx) => {
|
|
|
26
45
|
if (html && cacheConfig) {
|
|
27
46
|
await sprCache.set(cacheContext, html, cacheConfig);
|
|
28
47
|
}
|
|
48
|
+
} // no cache, render sync
|
|
29
49
|
|
|
30
|
-
|
|
50
|
+
|
|
51
|
+
if (!cacheFile) {
|
|
52
|
+
const renderResult = await renderFn(context);
|
|
53
|
+
return afterRender(renderResult, saveHtmlIntoCache);
|
|
31
54
|
}
|
|
32
55
|
|
|
33
56
|
const cacheHash = cacheFile === null || cacheFile === void 0 ? void 0 : cacheFile.hash; // completely expired
|
|
34
57
|
|
|
35
58
|
if (cacheFile.isGarbage) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
cacheConfig
|
|
39
|
-
} = context;
|
|
40
|
-
|
|
41
|
-
if (html && cacheConfig) {
|
|
42
|
-
await sprCache.set(cacheContext, html, cacheConfig);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return html;
|
|
59
|
+
const renderResult = await renderFn(context);
|
|
60
|
+
return afterRender(renderResult, saveHtmlIntoCache);
|
|
46
61
|
} else if (cacheFile.isStale) {
|
|
47
62
|
// if file is stale, request async
|
|
48
63
|
const render = withCoalescedInvoke(() => renderFn(context)).bind(null, namespaceHash('render', cacheFile.hash), []);
|
|
49
|
-
render().then(res => {
|
|
64
|
+
render().then(async res => {
|
|
50
65
|
if (res.value && res.isOrigin) {
|
|
51
66
|
const {
|
|
52
67
|
cacheConfig
|
|
53
68
|
} = context;
|
|
54
69
|
|
|
55
70
|
if (cacheConfig) {
|
|
56
|
-
|
|
71
|
+
afterRender(res.value, async html => {
|
|
72
|
+
sprCache.set(cacheContext, html, cacheConfig);
|
|
73
|
+
});
|
|
57
74
|
} else {
|
|
58
75
|
sprCache.del(cacheContext, cacheHash);
|
|
59
76
|
}
|
|
@@ -4,6 +4,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
4
4
|
|
|
5
5
|
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; }
|
|
6
6
|
|
|
7
|
+
/* eslint-disable no-param-reassign */
|
|
7
8
|
import { headersWithoutCookie } from "../../utils";
|
|
8
9
|
export const createMetrics = (context, metrics) => {
|
|
9
10
|
const {
|
|
@@ -49,6 +50,11 @@ export const createLogger = (serverContext, logger) => {
|
|
|
49
50
|
};
|
|
50
51
|
|
|
51
52
|
const error = (message, e) => {
|
|
53
|
+
if (!e) {
|
|
54
|
+
e = message;
|
|
55
|
+
message = '';
|
|
56
|
+
}
|
|
57
|
+
|
|
52
58
|
logger.error(`SSR Error - ${message}, error = %s, req.url = %s, req.headers = %o`, e instanceof Error ? e.stack || e.message : e, pathname, headersWithoutCookie(headers));
|
|
53
59
|
};
|
|
54
60
|
|
|
@@ -57,4 +63,5 @@ export const createLogger = (serverContext, logger) => {
|
|
|
57
63
|
info,
|
|
58
64
|
debug
|
|
59
65
|
};
|
|
60
|
-
};
|
|
66
|
+
};
|
|
67
|
+
/* eslint-enable no-param-reassign */
|
|
@@ -4,6 +4,8 @@ import cookie from 'cookie';
|
|
|
4
4
|
import cache from "./cache";
|
|
5
5
|
import { createLogger, createMetrics } from "./measure";
|
|
6
6
|
export const render = async (ctx, renderOptions, runner) => {
|
|
7
|
+
var _ctx$res;
|
|
8
|
+
|
|
7
9
|
const {
|
|
8
10
|
urlPath,
|
|
9
11
|
bundle,
|
|
@@ -32,7 +34,8 @@ export const render = async (ctx, renderOptions, runner) => {
|
|
|
32
34
|
},
|
|
33
35
|
status: code => {
|
|
34
36
|
ctx.res.statusCode = code;
|
|
35
|
-
}
|
|
37
|
+
},
|
|
38
|
+
locals: ((_ctx$res = ctx.res) === null || _ctx$res === void 0 ? void 0 : _ctx$res.locals) || {}
|
|
36
39
|
},
|
|
37
40
|
redirection: {},
|
|
38
41
|
template,
|
|
@@ -40,7 +43,9 @@ export const render = async (ctx, renderOptions, runner) => {
|
|
|
40
43
|
entryName,
|
|
41
44
|
staticGenerate,
|
|
42
45
|
logger: undefined,
|
|
43
|
-
metrics: undefined
|
|
46
|
+
metrics: undefined,
|
|
47
|
+
req: ctx.req,
|
|
48
|
+
res: ctx.res
|
|
44
49
|
};
|
|
45
50
|
context.logger = createLogger(context, ctx.logger);
|
|
46
51
|
context.metrics = createMetrics(context, ctx.metrics);
|
|
@@ -48,7 +53,7 @@ export const render = async (ctx, renderOptions, runner) => {
|
|
|
48
53
|
|
|
49
54
|
const serverRender = require(bundleJS)[SERVER_RENDER_FUNCTION_NAME];
|
|
50
55
|
|
|
51
|
-
const
|
|
56
|
+
const content = await cache(serverRender, ctx)(context);
|
|
52
57
|
const {
|
|
53
58
|
url,
|
|
54
59
|
status = 302
|
|
@@ -63,8 +68,16 @@ export const render = async (ctx, renderOptions, runner) => {
|
|
|
63
68
|
};
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
if (typeof content === 'string') {
|
|
72
|
+
return {
|
|
73
|
+
content,
|
|
74
|
+
contentType: mime.contentType('html')
|
|
75
|
+
};
|
|
76
|
+
} else {
|
|
77
|
+
return {
|
|
78
|
+
content: '',
|
|
79
|
+
contentStream: content,
|
|
80
|
+
contentType: mime.contentType('html')
|
|
81
|
+
};
|
|
82
|
+
}
|
|
70
83
|
};
|
|
@@ -15,6 +15,14 @@ const removedPrefix = (req, prefix) => {
|
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
export const faviconFallbackHandler = (context, next) => {
|
|
19
|
+
if (context.url === '/favicon.ico') {
|
|
20
|
+
context.res.statusCode = 204;
|
|
21
|
+
context.res.end();
|
|
22
|
+
} else {
|
|
23
|
+
next();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
18
26
|
export const createStaticFileHandler = (rules, output = {}) => // eslint-disable-next-line consistent-return
|
|
19
27
|
async (context, next) => {
|
|
20
28
|
const {
|
|
@@ -6,7 +6,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
|
6
6
|
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import fs from 'fs';
|
|
9
|
-
import { Logger, SHARED_DIR, OUTPUT_CONFIG_FILE, dotenv, dotenvExpand } from '@modern-js/utils';
|
|
9
|
+
import { Logger, SHARED_DIR, OUTPUT_CONFIG_FILE, dotenv, dotenvExpand, INTERNAL_SERVER_PLUGINS } from '@modern-js/utils';
|
|
10
10
|
import { serverManager, AppContext, ConfigContext, loadPlugins } from '@modern-js/server-core';
|
|
11
11
|
import { metrics as defaultMetrics } from "../libs/metrics";
|
|
12
12
|
import { loadConfig, getServerConfigPath, requireConfig } from "../libs/loadConfig";
|
|
@@ -146,6 +146,10 @@ export class Server {
|
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
async render(req, res, url) {
|
|
150
|
+
return this.server.render(req, res, url);
|
|
151
|
+
}
|
|
152
|
+
|
|
149
153
|
async createHookRunner() {
|
|
150
154
|
// clear server manager every create time
|
|
151
155
|
serverManager.clear();
|
|
@@ -154,13 +158,15 @@ export class Server {
|
|
|
154
158
|
} = this; // TODO: 确认下这里是不是可以不从 options 中取插件,而是从 config 中取和过滤
|
|
155
159
|
|
|
156
160
|
const {
|
|
157
|
-
|
|
161
|
+
internalPlugins = INTERNAL_SERVER_PLUGINS,
|
|
158
162
|
pwd,
|
|
159
163
|
config
|
|
160
164
|
} = options;
|
|
161
165
|
const serverPlugins = this.serverConfig.plugins || []; // server app context for serve plugin
|
|
162
166
|
|
|
163
|
-
const loadedPlugins = loadPlugins(
|
|
167
|
+
const loadedPlugins = loadPlugins(pwd, serverPlugins, {
|
|
168
|
+
internalPlugins
|
|
169
|
+
});
|
|
164
170
|
debug('plugins', config.plugins, loadedPlugins);
|
|
165
171
|
loadedPlugins.forEach(p => {
|
|
166
172
|
serverManager.usePlugin(p);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { RUN_MODE } from "../constants";
|
|
2
1
|
import { ModernServer } from "./modern-server";
|
|
3
2
|
|
|
4
3
|
class ModernSSRServer extends ModernServer {
|
|
@@ -6,20 +5,8 @@ class ModernSSRServer extends ModernServer {
|
|
|
6
5
|
return null;
|
|
7
6
|
}
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
return
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async setupBeforeProdMiddleware() {
|
|
14
|
-
if (this.runMode === RUN_MODE.FULL) {
|
|
15
|
-
await super.setupBeforeProdMiddleware();
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async emitRouteHook(_, _input) {
|
|
20
|
-
if (this.runMode === RUN_MODE.FULL) {
|
|
21
|
-
await super.emitRouteHook(_, _input);
|
|
22
|
-
}
|
|
8
|
+
async handleAPI(context) {
|
|
9
|
+
return this.render404(context);
|
|
23
10
|
}
|
|
24
11
|
|
|
25
12
|
}
|
|
@@ -33,15 +20,6 @@ class ModernAPIServer extends ModernServer {
|
|
|
33
20
|
return routes.filter(route => route.isApi);
|
|
34
21
|
}
|
|
35
22
|
|
|
36
|
-
async setupBeforeProdMiddleware() {
|
|
37
|
-
if (this.runMode === RUN_MODE.FULL) {
|
|
38
|
-
await super.setupBeforeProdMiddleware();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async emitRouteHook(_, _input) {// empty
|
|
43
|
-
}
|
|
44
|
-
|
|
45
23
|
}
|
|
46
24
|
|
|
47
25
|
class ModernWebServer extends ModernServer {
|
|
@@ -50,29 +28,12 @@ class ModernWebServer extends ModernServer {
|
|
|
50
28
|
}
|
|
51
29
|
|
|
52
30
|
async handleAPI(context) {
|
|
53
|
-
|
|
54
|
-
proxyTarget
|
|
55
|
-
} = this;
|
|
56
|
-
|
|
57
|
-
if (proxyTarget !== null && proxyTarget !== void 0 && proxyTarget.api) {
|
|
58
|
-
return this.proxy();
|
|
59
|
-
} else {
|
|
60
|
-
return this.render404(context);
|
|
61
|
-
}
|
|
31
|
+
return this.render404(context);
|
|
62
32
|
}
|
|
63
33
|
|
|
64
34
|
async handleWeb(context, route) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
} = this;
|
|
68
|
-
|
|
69
|
-
if (route.isSSR && proxyTarget !== null && proxyTarget !== void 0 && proxyTarget.ssr) {
|
|
70
|
-
return this.proxy();
|
|
71
|
-
} else {
|
|
72
|
-
// if no proxyTarget but access web server, degradation to csr
|
|
73
|
-
route.isSSR = false;
|
|
74
|
-
return super.handleWeb(context, route);
|
|
75
|
-
}
|
|
35
|
+
route.isSSR = false;
|
|
36
|
+
return super.handleWeb(context, route);
|
|
76
37
|
}
|
|
77
38
|
|
|
78
39
|
}
|