@modern-js/prod-server 2.21.0 → 2.22.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 +30 -0
- package/dist/cjs/constants.js +15 -5
- package/dist/cjs/index.js +12 -4
- package/dist/cjs/libs/context/context.js +4 -2
- package/dist/cjs/libs/context/index.js +6 -2
- package/dist/cjs/libs/hook-api/base.js +88 -0
- package/dist/cjs/libs/hook-api/index.js +17 -79
- package/dist/cjs/libs/hook-api/index.worker.js +109 -0
- package/dist/cjs/libs/hook-api/route.js +3 -1
- package/dist/cjs/libs/hook-api/template.js +6 -26
- package/dist/cjs/libs/hook-api/templateForStream.js +35 -0
- package/dist/cjs/libs/loadConfig.js +9 -3
- package/dist/cjs/libs/logger.js +6 -2
- package/dist/cjs/libs/metrics.js +3 -1
- package/dist/cjs/libs/proxy.js +6 -2
- package/dist/cjs/libs/render/cache/__tests__/cacheable.js +3 -1
- package/dist/cjs/libs/render/cache/__tests__/error-configuration.js +3 -1
- package/dist/cjs/libs/render/cache/__tests__/matched-cache.js +3 -1
- package/dist/cjs/libs/render/cache/index.js +3 -1
- package/dist/cjs/libs/render/cache/page-caches/index.js +3 -1
- package/dist/cjs/libs/render/cache/page-caches/lru.js +3 -1
- package/dist/cjs/libs/render/cache/spr.js +6 -2
- package/dist/cjs/libs/render/cache/util.js +24 -8
- package/dist/cjs/libs/render/index.js +3 -4
- package/dist/cjs/libs/render/measure.js +6 -2
- package/dist/cjs/libs/render/reader.js +32 -19
- package/dist/cjs/libs/render/ssr.js +3 -1
- package/dist/cjs/libs/render/static.js +3 -1
- package/dist/cjs/libs/render/type.js +3 -1
- package/dist/cjs/libs/render/utils.js +8 -3
- package/dist/cjs/libs/route/index.js +6 -2
- package/dist/cjs/libs/route/matcher.js +3 -1
- package/dist/cjs/libs/route/route.js +3 -1
- package/dist/cjs/libs/serveFile.js +6 -2
- package/dist/cjs/renderHtml.js +75 -0
- package/dist/cjs/server/index.js +9 -3
- package/dist/cjs/server/modernServer.js +21 -16
- package/dist/cjs/server/modernServerSplit.js +3 -1
- package/dist/cjs/utils.js +27 -9
- package/dist/cjs/workerServer.js +95 -11
- package/dist/esm/libs/context/context.js +1 -1
- package/dist/esm/libs/hook-api/base.js +104 -0
- package/dist/esm/libs/hook-api/index.js +5 -109
- package/dist/esm/libs/hook-api/index.worker.js +105 -0
- package/dist/esm/libs/hook-api/template.js +1 -28
- package/dist/esm/libs/hook-api/templateForStream.js +28 -0
- package/dist/esm/libs/render/index.js +1 -4
- package/dist/esm/libs/render/reader.js +26 -26
- package/dist/esm/libs/render/utils.js +2 -1
- package/dist/esm/renderHtml.js +141 -0
- package/dist/esm/server/index.js +11 -1
- package/dist/esm/server/modernServer.js +45 -37
- package/dist/esm/workerServer.js +103 -10
- package/dist/esm-node/libs/context/context.js +1 -1
- package/dist/esm-node/libs/hook-api/base.js +68 -0
- package/dist/esm-node/libs/hook-api/index.js +5 -74
- package/dist/esm-node/libs/hook-api/index.worker.js +84 -0
- package/dist/esm-node/libs/hook-api/template.js +1 -25
- package/dist/esm-node/libs/hook-api/templateForStream.js +25 -0
- package/dist/esm-node/libs/render/index.js +1 -4
- package/dist/esm-node/libs/render/reader.js +14 -11
- package/dist/esm-node/libs/render/utils.js +2 -1
- package/dist/esm-node/renderHtml.js +71 -0
- package/dist/esm-node/server/index.js +6 -2
- package/dist/esm-node/server/modernServer.js +18 -15
- package/dist/esm-node/workerServer.js +89 -9
- package/dist/types/libs/context/context.d.ts +1 -1
- package/dist/types/libs/hook-api/base.d.ts +53 -0
- package/dist/types/libs/hook-api/index.worker.d.ts +18 -0
- package/dist/types/libs/hook-api/template.d.ts +11 -14
- package/dist/types/libs/hook-api/templateForStream.d.ts +13 -0
- package/dist/types/libs/render/reader.d.ts +4 -2
- package/dist/types/renderHtml.d.ts +21 -0
- package/dist/types/server/index.d.ts +5 -1
- package/dist/types/server/modernServer.d.ts +4 -3
- package/dist/types/utils.d.ts +1 -1
- package/dist/types/workerServer.d.ts +19 -8
- package/package.json +21 -7
|
@@ -1,78 +1,11 @@
|
|
|
1
|
-
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
-
import cookie from "cookie";
|
|
3
1
|
import { RouteAPI } from "./route";
|
|
4
2
|
import { TemplateAPI } from "./template";
|
|
5
|
-
|
|
6
|
-
get(key) {
|
|
7
|
-
return this.res.getHeader(key);
|
|
8
|
-
}
|
|
9
|
-
set(key, value) {
|
|
10
|
-
return this.res.setHeader(key, value);
|
|
11
|
-
}
|
|
12
|
-
status(code) {
|
|
13
|
-
this.res.statusCode = code;
|
|
14
|
-
}
|
|
15
|
-
setCookie(key, value, options) {
|
|
16
|
-
const cookieValue = this.res.getHeader("set-cookie");
|
|
17
|
-
const fmt = Array.isArray(cookieValue) ? cookieValue : [
|
|
18
|
-
cookieValue
|
|
19
|
-
].filter(Boolean);
|
|
20
|
-
fmt.push(cookie.serialize(key, value, options));
|
|
21
|
-
this.res.setHeader("set-cookie", fmt.length === 1 ? fmt[0] : fmt);
|
|
22
|
-
}
|
|
23
|
-
clearCookie() {
|
|
24
|
-
this.res.removeHeader("set-cookie");
|
|
25
|
-
}
|
|
26
|
-
raw(body, options) {
|
|
27
|
-
const { status, headers = {} } = options || {};
|
|
28
|
-
Object.entries(headers).forEach(([key, value]) => {
|
|
29
|
-
this.res.setHeader(key, value);
|
|
30
|
-
});
|
|
31
|
-
if (status) {
|
|
32
|
-
this.res.statusCode = status;
|
|
33
|
-
}
|
|
34
|
-
this.res.end(body);
|
|
35
|
-
}
|
|
36
|
-
constructor(res) {
|
|
37
|
-
_define_property(this, "cookies", void 0);
|
|
38
|
-
_define_property(this, "res", void 0);
|
|
39
|
-
this.res = res;
|
|
40
|
-
this.cookies = {
|
|
41
|
-
set: this.setCookie.bind(this),
|
|
42
|
-
clear: this.clearCookie.bind(this)
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
class Request {
|
|
47
|
-
getCookie(key) {
|
|
48
|
-
return this._cookie[key];
|
|
49
|
-
}
|
|
50
|
-
constructor(ctx) {
|
|
51
|
-
_define_property(this, "url", void 0);
|
|
52
|
-
_define_property(this, "host", void 0);
|
|
53
|
-
_define_property(this, "pathname", void 0);
|
|
54
|
-
_define_property(this, "query", void 0);
|
|
55
|
-
_define_property(this, "headers", void 0);
|
|
56
|
-
_define_property(this, "cookie", void 0);
|
|
57
|
-
_define_property(this, "cookies", void 0);
|
|
58
|
-
_define_property(this, "_cookie", void 0);
|
|
59
|
-
this.url = ctx.url;
|
|
60
|
-
this.host = ctx.host;
|
|
61
|
-
this.pathname = ctx.path;
|
|
62
|
-
this.query = ctx.query;
|
|
63
|
-
this.headers = ctx.headers;
|
|
64
|
-
this.cookie = ctx.headers.cookie || "";
|
|
65
|
-
this._cookie = cookie.parse(this.cookie);
|
|
66
|
-
this.cookies = {
|
|
67
|
-
get: this.getCookie.bind(this)
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
3
|
+
import { BaseRequest, BaseResponse } from "./base";
|
|
71
4
|
export const base = (context) => {
|
|
72
5
|
const { res } = context;
|
|
73
6
|
return {
|
|
74
|
-
response: new
|
|
75
|
-
request: new
|
|
7
|
+
response: new BaseResponse(res),
|
|
8
|
+
request: new BaseRequest(context),
|
|
76
9
|
logger: context.logger,
|
|
77
10
|
metrics: context.metrics
|
|
78
11
|
};
|
|
@@ -93,12 +26,10 @@ export const createAfterRenderContext = (context, content) => {
|
|
|
93
26
|
};
|
|
94
27
|
export const createMiddlewareContext = (context) => {
|
|
95
28
|
const baseContext = base(context);
|
|
29
|
+
baseContext.response.locals = context.res.locals || {};
|
|
96
30
|
return {
|
|
97
31
|
...baseContext,
|
|
98
|
-
response:
|
|
99
|
-
...baseContext.response,
|
|
100
|
-
locals: context.res.locals || {}
|
|
101
|
-
},
|
|
32
|
+
response: baseContext.response,
|
|
102
33
|
source: {
|
|
103
34
|
req: context.req,
|
|
104
35
|
res: context.res
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
+
import { BaseRequest, BaseResponse } from "./base";
|
|
3
|
+
import { RouteAPI } from "./route";
|
|
4
|
+
import { TemplateAPI } from "./template";
|
|
5
|
+
class ServerResponse {
|
|
6
|
+
set statusCode(code) {
|
|
7
|
+
this.res.status = code;
|
|
8
|
+
}
|
|
9
|
+
get statusCode() {
|
|
10
|
+
return this.res.status;
|
|
11
|
+
}
|
|
12
|
+
getHeader(key) {
|
|
13
|
+
var _this_res_headers_get;
|
|
14
|
+
return (_this_res_headers_get = this.res.headers.get(key)) !== null && _this_res_headers_get !== void 0 ? _this_res_headers_get : void 0;
|
|
15
|
+
}
|
|
16
|
+
setHeader(key, value) {
|
|
17
|
+
this.res.headers.set(key, value);
|
|
18
|
+
}
|
|
19
|
+
removeHeader(key) {
|
|
20
|
+
this.res.headers.delete(key);
|
|
21
|
+
}
|
|
22
|
+
end(body) {
|
|
23
|
+
this.res.body = body;
|
|
24
|
+
this.res.isSent = true;
|
|
25
|
+
}
|
|
26
|
+
constructor(res) {
|
|
27
|
+
_define_property(this, "locals", void 0);
|
|
28
|
+
_define_property(this, "res", void 0);
|
|
29
|
+
this.res = res;
|
|
30
|
+
this.locals = res.locals;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export const base = (context) => {
|
|
34
|
+
const { req, res, logger, metrics } = context;
|
|
35
|
+
const serverResponse = new ServerResponse(res);
|
|
36
|
+
const { host, pathname, searchParams } = new URL(req.url);
|
|
37
|
+
const headers = {};
|
|
38
|
+
req.headers.forEach((value, key) => {
|
|
39
|
+
headers[key] = value;
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
response: new BaseResponse(serverResponse),
|
|
43
|
+
request: new BaseRequest({
|
|
44
|
+
url: req.url,
|
|
45
|
+
host,
|
|
46
|
+
path: pathname,
|
|
47
|
+
headers,
|
|
48
|
+
// eslint-disable-next-line node/no-unsupported-features/es-builtins
|
|
49
|
+
query: Object.fromEntries(searchParams)
|
|
50
|
+
}),
|
|
51
|
+
logger,
|
|
52
|
+
metrics
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
export const createAfterMatchContext = (context, entryName) => {
|
|
56
|
+
const baseContext = base(context);
|
|
57
|
+
return {
|
|
58
|
+
...baseContext,
|
|
59
|
+
router: new RouteAPI(entryName)
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export const createAfterRenderContext = (context, content) => {
|
|
63
|
+
const baseContext = base(context);
|
|
64
|
+
return {
|
|
65
|
+
...baseContext,
|
|
66
|
+
template: new TemplateAPI(content)
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
export const createMiddlewareContext = (context) => {
|
|
70
|
+
const baseContext = base(context);
|
|
71
|
+
baseContext.response.locals = context.res.locals;
|
|
72
|
+
const { url, headers } = context.req;
|
|
73
|
+
const rawRequest = new Request(url, {
|
|
74
|
+
headers
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
...baseContext,
|
|
78
|
+
response: baseContext.response,
|
|
79
|
+
source: {
|
|
80
|
+
req: rawRequest,
|
|
81
|
+
res: baseContext.response
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
-
|
|
3
|
-
const RegList = {
|
|
2
|
+
export const RegList = {
|
|
4
3
|
before: {
|
|
5
4
|
head: "<head>",
|
|
6
5
|
body: "<body>"
|
|
@@ -41,26 +40,3 @@ export class TemplateAPI {
|
|
|
41
40
|
this.content = content;
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
|
-
export const templateInjectableStream = ({ prependHead, appendHead, prependBody, appendBody }) => new Transform({
|
|
45
|
-
write(chunk, _, callback) {
|
|
46
|
-
let chunk_str = chunk.toString();
|
|
47
|
-
if (prependHead) {
|
|
48
|
-
const { head } = RegList.before;
|
|
49
|
-
chunk_str = chunk_str.replace(head, `${head}${prependHead}`);
|
|
50
|
-
}
|
|
51
|
-
if (appendHead) {
|
|
52
|
-
const { head } = RegList.after;
|
|
53
|
-
chunk_str = chunk_str.replace(head, `${appendHead}${head}`);
|
|
54
|
-
}
|
|
55
|
-
if (prependBody) {
|
|
56
|
-
const { body } = RegList.before;
|
|
57
|
-
chunk_str = chunk_str.replace(body, `${body}${prependBody}`);
|
|
58
|
-
}
|
|
59
|
-
if (appendBody) {
|
|
60
|
-
const { body } = RegList.after;
|
|
61
|
-
chunk_str = chunk_str.replace(body, `${appendBody}${body}`);
|
|
62
|
-
}
|
|
63
|
-
this.push(chunk_str);
|
|
64
|
-
callback();
|
|
65
|
-
}
|
|
66
|
-
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Transform } from "stream";
|
|
2
|
+
import { RegList } from "./template";
|
|
3
|
+
export const templateInjectableStream = ({ prependHead, appendHead, prependBody, appendBody }) => new Transform({
|
|
4
|
+
write(chunk, _, callback) {
|
|
5
|
+
let chunk_str = chunk.toString();
|
|
6
|
+
if (prependHead) {
|
|
7
|
+
const { head } = RegList.before;
|
|
8
|
+
chunk_str = chunk_str.replace(head, `${head}${prependHead}`);
|
|
9
|
+
}
|
|
10
|
+
if (appendHead) {
|
|
11
|
+
const { head } = RegList.after;
|
|
12
|
+
chunk_str = chunk_str.replace(head, `${appendHead}${head}`);
|
|
13
|
+
}
|
|
14
|
+
if (prependBody) {
|
|
15
|
+
const { body } = RegList.before;
|
|
16
|
+
chunk_str = chunk_str.replace(body, `${body}${prependBody}`);
|
|
17
|
+
}
|
|
18
|
+
if (appendBody) {
|
|
19
|
+
const { body } = RegList.after;
|
|
20
|
+
chunk_str = chunk_str.replace(body, `${appendBody}${body}`);
|
|
21
|
+
}
|
|
22
|
+
this.push(chunk_str);
|
|
23
|
+
callback();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import {
|
|
2
|
+
import { mime } from "@modern-js/utils";
|
|
3
3
|
import { ERROR_DIGEST } from "../../constants";
|
|
4
4
|
import { handleDirectory } from "./static";
|
|
5
5
|
import { readFile } from "./reader";
|
|
@@ -16,9 +16,6 @@ export const createRenderHandler = ({ distDir, staticGenerate, forceCSR, nonce }
|
|
|
16
16
|
return result;
|
|
17
17
|
}
|
|
18
18
|
const templatePath = entry;
|
|
19
|
-
if (!fs.existsSync(templatePath)) {
|
|
20
|
-
throw new Error(`Could not find template file: ${templatePath}`);
|
|
21
|
-
}
|
|
22
19
|
const content = await readFile(templatePath);
|
|
23
20
|
if (!content) {
|
|
24
21
|
return null;
|
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
-
import { fs } from "@modern-js/utils";
|
|
2
|
+
import { fs as extraFS } from "@modern-js/utils";
|
|
3
3
|
import LRU from "lru-cache";
|
|
4
4
|
const Byte = 1;
|
|
5
5
|
const KB = 1024 * Byte;
|
|
6
6
|
const MB = 1024 * KB;
|
|
7
7
|
const getContentLength = (cache) => cache.content.length;
|
|
8
|
-
const createCacheItem = async (
|
|
9
|
-
const content = await fs.readFile(filepath);
|
|
8
|
+
const createCacheItem = async (content, mtime) => {
|
|
10
9
|
return {
|
|
11
10
|
content,
|
|
12
11
|
mtime
|
|
13
12
|
};
|
|
14
13
|
};
|
|
15
14
|
export class LruReader {
|
|
16
|
-
init() {
|
|
15
|
+
init(fs) {
|
|
16
|
+
this.fs = fs || extraFS;
|
|
17
17
|
}
|
|
18
18
|
close() {
|
|
19
19
|
}
|
|
20
20
|
async read(filepath) {
|
|
21
|
+
const { fs } = this;
|
|
21
22
|
if (this.cache.has(filepath)) {
|
|
22
|
-
const { content } = this.cache.get(filepath);
|
|
23
|
+
const { content: content2 } = this.cache.get(filepath);
|
|
23
24
|
return {
|
|
24
|
-
content
|
|
25
|
+
content: content2
|
|
25
26
|
};
|
|
26
27
|
}
|
|
27
28
|
if (!fs.existsSync(filepath)) {
|
|
@@ -34,12 +35,13 @@ export class LruReader {
|
|
|
34
35
|
if (stat.size > 20 * MB) {
|
|
35
36
|
return null;
|
|
36
37
|
}
|
|
37
|
-
const
|
|
38
|
+
const content = await fs.promises.readFile(filepath);
|
|
39
|
+
const item = await createCacheItem(content, stat.mtime);
|
|
38
40
|
this.cache.set(filepath, item);
|
|
39
41
|
return item;
|
|
40
42
|
}
|
|
41
43
|
update() {
|
|
42
|
-
const { cache } = this;
|
|
44
|
+
const { cache, fs } = this;
|
|
43
45
|
const files = cache.keys();
|
|
44
46
|
for (const filepath of files) {
|
|
45
47
|
if (!fs.existsSync(filepath)) {
|
|
@@ -57,14 +59,15 @@ export class LruReader {
|
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
|
-
// private timer?: NodeJS.Timeout;
|
|
61
62
|
constructor() {
|
|
62
63
|
_define_property(this, "cache", void 0);
|
|
64
|
+
_define_property(this, "fs", void 0);
|
|
63
65
|
this.cache = new LRU({
|
|
64
66
|
max: 256 * MB,
|
|
65
67
|
length: getContentLength,
|
|
66
68
|
maxAge: 5 * 60 * 5e3
|
|
67
69
|
});
|
|
70
|
+
this.fs = extraFS;
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
const reader = new LruReader();
|
|
@@ -75,8 +78,8 @@ export const readFile = async (filepath) => {
|
|
|
75
78
|
export const updateFile = () => {
|
|
76
79
|
reader.update();
|
|
77
80
|
};
|
|
78
|
-
export const init = () => {
|
|
79
|
-
reader.init();
|
|
81
|
+
export const init = (fs) => {
|
|
82
|
+
reader.init(fs);
|
|
80
83
|
};
|
|
81
84
|
export const close = () => {
|
|
82
85
|
reader.close();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { TemplateAPI
|
|
1
|
+
import { TemplateAPI } from "../hook-api/template";
|
|
2
|
+
import { templateInjectableStream } from "../hook-api/templateForStream";
|
|
2
3
|
export const injectServerData = (content, context) => {
|
|
3
4
|
const template = new TemplateAPI(content);
|
|
4
5
|
template.prependHead(`<script type="application/json" id="__MODERN_SERVER_DATA__">${JSON.stringify(context.serverData)}</script>`);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
+
import { OutgoingMessage } from "http";
|
|
3
|
+
import { Readable } from "stream";
|
|
4
|
+
import { Socket } from "net";
|
|
5
|
+
import { Server } from "./server";
|
|
6
|
+
import { isRedirect } from "./utils";
|
|
7
|
+
class IncomingMessageLike extends Readable {
|
|
8
|
+
constructor({ method, url, headers }) {
|
|
9
|
+
super();
|
|
10
|
+
_define_property(this, "headers", void 0);
|
|
11
|
+
_define_property(this, "method", void 0);
|
|
12
|
+
_define_property(this, "url", void 0);
|
|
13
|
+
_define_property(this, "socket", void 0);
|
|
14
|
+
this.socket = new Socket();
|
|
15
|
+
this.headers = headers || {};
|
|
16
|
+
this.headers.host = "localhost:8080";
|
|
17
|
+
this.method = method || "get";
|
|
18
|
+
this.url = url;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class ServerResponseLike extends OutgoingMessage {
|
|
22
|
+
end(chunk, _encoding, cb) {
|
|
23
|
+
this.data.push(chunk.toString());
|
|
24
|
+
cb && cb();
|
|
25
|
+
this.emit("finish");
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
_define_property(this, "statusCode", void 0);
|
|
31
|
+
_define_property(this, "data", void 0);
|
|
32
|
+
this.statusCode = 200;
|
|
33
|
+
this.data = [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class CustomServer extends Server {
|
|
37
|
+
async render(req, res, _url) {
|
|
38
|
+
const handler = this.getRequestHandler();
|
|
39
|
+
handler(req, res);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function renderHtml({ url, method, headers, body, serverOptions }) {
|
|
44
|
+
const req = new IncomingMessageLike({
|
|
45
|
+
method,
|
|
46
|
+
url,
|
|
47
|
+
headers
|
|
48
|
+
});
|
|
49
|
+
if (body) {
|
|
50
|
+
req.push(body);
|
|
51
|
+
req.push(null);
|
|
52
|
+
}
|
|
53
|
+
const res = new ServerResponseLike();
|
|
54
|
+
const customServer = new CustomServer(serverOptions);
|
|
55
|
+
await customServer.init({
|
|
56
|
+
disableHttpServer: true
|
|
57
|
+
});
|
|
58
|
+
customServer.render(req, res);
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
res.addListener("finish", () => {
|
|
61
|
+
resolve({
|
|
62
|
+
headers: res.getHeaders(),
|
|
63
|
+
redirected: isRedirect(res.statusCode),
|
|
64
|
+
status: res.statusCode,
|
|
65
|
+
url,
|
|
66
|
+
body: res.data.join()
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
module.exports = renderHtml;
|
|
@@ -21,7 +21,9 @@ export class Server {
|
|
|
21
21
|
* - 执行 prepare hook
|
|
22
22
|
* - 执行 server init
|
|
23
23
|
*/
|
|
24
|
-
async init(
|
|
24
|
+
async init({ disableHttpServer = false } = {
|
|
25
|
+
disableHttpServer: false
|
|
26
|
+
}) {
|
|
25
27
|
const { options } = this;
|
|
26
28
|
await this.loadServerEnv(options);
|
|
27
29
|
this.initServerConfig(options);
|
|
@@ -31,7 +33,9 @@ export class Server {
|
|
|
31
33
|
await this.injectContext(this.runner, options);
|
|
32
34
|
this.server = this.serverImpl(options);
|
|
33
35
|
await this.runPrepareHook(this.runner);
|
|
34
|
-
|
|
36
|
+
if (!disableHttpServer) {
|
|
37
|
+
this.app = await this.server.createHTTPServer(this.getRequestHandler());
|
|
38
|
+
}
|
|
35
39
|
await this.server.onInit(this.runner, this.app);
|
|
36
40
|
return this;
|
|
37
41
|
}
|
|
@@ -18,6 +18,7 @@ export class ModernServer {
|
|
|
18
18
|
var _conf_bff, _this_conf_server, _conf_security, _this_conf_output;
|
|
19
19
|
this.runner = runner;
|
|
20
20
|
const { distDir, staticGenerate, conf } = this;
|
|
21
|
+
this.initReader();
|
|
21
22
|
debug("final server conf", this.conf);
|
|
22
23
|
this.proxyHandler = createProxyHandler((_conf_bff = conf.bff) === null || _conf_bff === void 0 ? void 0 : _conf_bff.proxy);
|
|
23
24
|
if (this.proxyHandler) {
|
|
@@ -25,8 +26,7 @@ export class ModernServer {
|
|
|
25
26
|
this.addHandler(handler);
|
|
26
27
|
});
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
app.on("close", () => {
|
|
29
|
+
app === null || app === void 0 ? void 0 : app.on("close", () => {
|
|
30
30
|
this.reader.close();
|
|
31
31
|
});
|
|
32
32
|
const usageRoutes = this.filterRoutes(this.getRoutes());
|
|
@@ -51,18 +51,6 @@ export class ModernServer {
|
|
|
51
51
|
// server ready
|
|
52
52
|
onRepack(_) {
|
|
53
53
|
}
|
|
54
|
-
async onServerChange({ filepath }) {
|
|
55
|
-
const { pwd } = this;
|
|
56
|
-
const { api, server } = AGGRED_DIR;
|
|
57
|
-
const apiPath = path.normalize(path.join(pwd, api));
|
|
58
|
-
const serverPath = path.normalize(path.join(pwd, server));
|
|
59
|
-
const onlyApi = filepath.startsWith(apiPath);
|
|
60
|
-
const onlyWeb = filepath.startsWith(serverPath);
|
|
61
|
-
await this.prepareFrameHandler({
|
|
62
|
-
onlyWeb,
|
|
63
|
-
onlyApi
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
54
|
// exposed requestHandler
|
|
67
55
|
getRequestHandler() {
|
|
68
56
|
return this.requestHandler.bind(this);
|
|
@@ -89,6 +77,21 @@ export class ModernServer {
|
|
|
89
77
|
return createServer(handler);
|
|
90
78
|
}
|
|
91
79
|
/* —————————————————————— function will be overwrite —————————————————————— */
|
|
80
|
+
initReader() {
|
|
81
|
+
this.reader.init();
|
|
82
|
+
}
|
|
83
|
+
async onServerChange({ filepath }) {
|
|
84
|
+
const { pwd } = this;
|
|
85
|
+
const { api, server } = AGGRED_DIR;
|
|
86
|
+
const apiPath = path.normalize(path.join(pwd, api));
|
|
87
|
+
const serverPath = path.normalize(path.join(pwd, server));
|
|
88
|
+
const onlyApi = filepath.startsWith(apiPath);
|
|
89
|
+
const onlyWeb = filepath.startsWith(serverPath);
|
|
90
|
+
await this.prepareFrameHandler({
|
|
91
|
+
onlyWeb,
|
|
92
|
+
onlyApi
|
|
93
|
+
});
|
|
94
|
+
}
|
|
92
95
|
// get routes info
|
|
93
96
|
getRoutes() {
|
|
94
97
|
if (this.presetRoutes) {
|
|
@@ -452,7 +455,7 @@ export class ModernServer {
|
|
|
452
455
|
_define_property(this, "staticGenerate", void 0);
|
|
453
456
|
require("ignore-styles");
|
|
454
457
|
this.pwd = pwd;
|
|
455
|
-
this.distDir = path.
|
|
458
|
+
this.distDir = path.resolve(pwd, config.output.path || "dist");
|
|
456
459
|
this.workDir = this.distDir;
|
|
457
460
|
this.conf = config;
|
|
458
461
|
debug("server conf", this.conf);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
+
import { createAsyncPipeline } from "@modern-js/plugin";
|
|
3
|
+
import { createAfterMatchContext, createAfterRenderContext, createMiddlewareContext } from "./libs/hook-api/index.worker";
|
|
2
4
|
import { Logger } from "./libs/logger";
|
|
3
5
|
import { RouteMatchManager } from "./libs/route";
|
|
4
6
|
import { metrics as defaultMetrics } from "./libs/metrics";
|
|
@@ -44,20 +46,56 @@ export class ReturnResponse {
|
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
const RESPONSE_NOTFOUND = new ReturnResponse("404: Page not found", 404);
|
|
49
|
+
const isRedirect = (code) => {
|
|
50
|
+
return [
|
|
51
|
+
301,
|
|
52
|
+
302,
|
|
53
|
+
307,
|
|
54
|
+
308
|
|
55
|
+
].includes(code);
|
|
56
|
+
};
|
|
57
|
+
const checkIsSent = (context) => {
|
|
58
|
+
if (context.res.isSent) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
if (context.res.headers.get("Location") && isRedirect(context.res.status)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
};
|
|
66
|
+
const middlewarePipeline = createAsyncPipeline();
|
|
47
67
|
export const createHandler = (manifest) => {
|
|
48
68
|
const routeMgr = new RouteMatchManager();
|
|
49
69
|
const { pages, routes } = manifest;
|
|
50
70
|
routeMgr.reset(routes);
|
|
51
71
|
return async (options) => {
|
|
72
|
+
var _page_serverHooks, _page_serverHooks_afterMatch;
|
|
52
73
|
const { request, loadableStats, routeManifest } = options;
|
|
53
74
|
const url = new URL(request.url);
|
|
54
75
|
const pageMatch = routeMgr.match(url.pathname);
|
|
55
76
|
if (!pageMatch) {
|
|
56
77
|
return RESPONSE_NOTFOUND;
|
|
57
78
|
}
|
|
58
|
-
const
|
|
79
|
+
const entryName = pageMatch.spec.urlPath;
|
|
80
|
+
const page = pages[entryName];
|
|
81
|
+
const logger = new Logger({
|
|
82
|
+
level: "warn"
|
|
83
|
+
});
|
|
84
|
+
const metrics = defaultMetrics;
|
|
85
|
+
const hookContext = createWorkerHookContext(request.url, logger, metrics);
|
|
86
|
+
const afterMatchHookContext = createAfterMatchContext(hookContext, entryName);
|
|
87
|
+
page === null || page === void 0 ? void 0 : (_page_serverHooks = page.serverHooks) === null || _page_serverHooks === void 0 ? void 0 : (_page_serverHooks_afterMatch = _page_serverHooks.afterMatch) === null || _page_serverHooks_afterMatch === void 0 ? void 0 : _page_serverHooks_afterMatch.call(_page_serverHooks, afterMatchHookContext, () => void 0);
|
|
88
|
+
if (checkIsSent(hookContext)) {
|
|
89
|
+
return new ReturnResponse(hookContext.res.body || "Unkown body", hookContext.res.status, hookContext.res.headers);
|
|
90
|
+
}
|
|
59
91
|
if (page.serverRender) {
|
|
60
92
|
try {
|
|
93
|
+
var _page_serverHooks1, _page_serverHooks2, _page_serverHooks_afterRender;
|
|
94
|
+
const middlewarsHookContext = createMiddlewareContext(hookContext);
|
|
95
|
+
applyMiddlewares(middlewarsHookContext, (_page_serverHooks1 = page.serverHooks) === null || _page_serverHooks1 === void 0 ? void 0 : _page_serverHooks1.middleware);
|
|
96
|
+
if (checkIsSent(hookContext)) {
|
|
97
|
+
return new ReturnResponse(hookContext.res.body || "Unkown body", hookContext.res.status, hookContext.res.headers);
|
|
98
|
+
}
|
|
61
99
|
const responseLike = {
|
|
62
100
|
headers: {},
|
|
63
101
|
statusCode: 200,
|
|
@@ -70,33 +108,37 @@ export const createHandler = (manifest) => {
|
|
|
70
108
|
}
|
|
71
109
|
};
|
|
72
110
|
const params = pageMatch.parseURLParams(url.pathname) || {};
|
|
111
|
+
const { urlPath: baseUrl } = pageMatch;
|
|
73
112
|
const serverRenderContext = {
|
|
74
|
-
request: createServerRequest(url, request, params),
|
|
113
|
+
request: createServerRequest(url, baseUrl, request, params),
|
|
75
114
|
response: responseLike,
|
|
76
115
|
loadableStats,
|
|
77
116
|
routeManifest,
|
|
78
117
|
redirection: {},
|
|
79
118
|
template: page.template,
|
|
80
119
|
entryName: page.entryName,
|
|
81
|
-
logger
|
|
82
|
-
|
|
83
|
-
}),
|
|
84
|
-
metrics: defaultMetrics,
|
|
120
|
+
logger,
|
|
121
|
+
metrics,
|
|
85
122
|
// FIXME: pass correctly req & res
|
|
86
123
|
req: request,
|
|
87
124
|
res: responseLike
|
|
88
125
|
};
|
|
89
126
|
const body = await page.serverRender(serverRenderContext);
|
|
90
|
-
|
|
127
|
+
const afterRenderHookContext = createAfterRenderContext(hookContext, body);
|
|
128
|
+
(_page_serverHooks2 = page.serverHooks) === null || _page_serverHooks2 === void 0 ? void 0 : (_page_serverHooks_afterRender = _page_serverHooks2.afterRender) === null || _page_serverHooks_afterRender === void 0 ? void 0 : _page_serverHooks_afterRender.call(_page_serverHooks2, afterRenderHookContext, () => void 0);
|
|
129
|
+
if (checkIsSent(hookContext)) {
|
|
130
|
+
return new ReturnResponse(hookContext.res.body || "Unkown body", hookContext.res.status, hookContext.res.headers);
|
|
131
|
+
}
|
|
132
|
+
return new ReturnResponse(afterRenderHookContext.template.get(), responseLike.statusCode, responseLike.headers);
|
|
91
133
|
} catch (e) {
|
|
92
134
|
console.warn(`page(${pageMatch.spec.urlPath}) serverRender occur error: `);
|
|
93
135
|
console.warn(e);
|
|
94
136
|
return createResponse(page.template);
|
|
95
137
|
}
|
|
96
138
|
}
|
|
97
|
-
console.warn(`Can't not page(${
|
|
139
|
+
console.warn(`Can't not page(${entryName}) serverRender`);
|
|
98
140
|
return createResponse(page.template);
|
|
99
|
-
function createServerRequest(url2, request2, params) {
|
|
141
|
+
function createServerRequest(url2, baseUrl, request2, params) {
|
|
100
142
|
const { pathname, host, searchParams } = url2;
|
|
101
143
|
const { headers: rawHeaders } = request2;
|
|
102
144
|
const headers = {};
|
|
@@ -105,6 +147,8 @@ export const createHandler = (manifest) => {
|
|
|
105
147
|
});
|
|
106
148
|
const query = Object.fromEntries(searchParams);
|
|
107
149
|
return {
|
|
150
|
+
url: url2.href,
|
|
151
|
+
baseUrl,
|
|
108
152
|
pathname,
|
|
109
153
|
host,
|
|
110
154
|
headers,
|
|
@@ -121,3 +165,39 @@ function createResponse(template) {
|
|
|
121
165
|
return RESPONSE_NOTFOUND;
|
|
122
166
|
}
|
|
123
167
|
}
|
|
168
|
+
function createWorkerHookContext(url, logger, metrics) {
|
|
169
|
+
const [res, req] = [
|
|
170
|
+
{
|
|
171
|
+
headers: new Headers(),
|
|
172
|
+
body: "",
|
|
173
|
+
status: 200,
|
|
174
|
+
isSent: false
|
|
175
|
+
},
|
|
176
|
+
new Request(url)
|
|
177
|
+
];
|
|
178
|
+
return {
|
|
179
|
+
res,
|
|
180
|
+
req,
|
|
181
|
+
logger,
|
|
182
|
+
metrics
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function applyMiddlewares(ctx, middleware) {
|
|
186
|
+
if (middleware) {
|
|
187
|
+
const middlewares = (() => {
|
|
188
|
+
if (Array.isArray(middleware)) {
|
|
189
|
+
return middleware;
|
|
190
|
+
} else {
|
|
191
|
+
return [
|
|
192
|
+
middleware
|
|
193
|
+
];
|
|
194
|
+
}
|
|
195
|
+
})();
|
|
196
|
+
middlewares.forEach((middleware2) => {
|
|
197
|
+
middlewarePipeline.use(middleware2);
|
|
198
|
+
});
|
|
199
|
+
middlewarePipeline.run(ctx, {
|
|
200
|
+
onLast: () => void 0
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
/// <reference types="node" />
|
|
4
4
|
/// <reference types="node/http" />
|
|
5
|
-
/// <reference types=".dts-temp/
|
|
5
|
+
/// <reference types=".dts-temp/t0a-Q86lFJHlugCUZWCMB/src/type" />
|
|
6
6
|
import { IncomingMessage, ServerResponse } from 'http';
|
|
7
7
|
import qs from 'querystring';
|
|
8
8
|
import type { ModernServerContext as ModernServerContextInterface } from '@modern-js/types';
|