@modern-js/prod-server 2.31.2 → 2.32.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +1 -1
  3. package/dist/cjs/constants.js +10 -0
  4. package/dist/cjs/libs/context/context.js +7 -2
  5. package/dist/cjs/libs/preload/flushServerHeader.js +67 -0
  6. package/dist/cjs/libs/preload/index.js +7 -0
  7. package/dist/cjs/libs/preload/parseLinks.js +100 -0
  8. package/dist/cjs/libs/preload/transformLinks2String.js +113 -0
  9. package/dist/cjs/libs/proxy.js +44 -41
  10. package/dist/cjs/libs/render/index.js +16 -2
  11. package/dist/cjs/libs/serverTiming.js +1 -1
  12. package/dist/cjs/server/modernServer.js +21 -16
  13. package/dist/esm/constants.js +7 -0
  14. package/dist/esm/libs/context/context.js +5 -2
  15. package/dist/esm/libs/preload/flushServerHeader.js +70 -0
  16. package/dist/esm/libs/preload/index.js +2 -0
  17. package/dist/esm/libs/preload/parseLinks.js +170 -0
  18. package/dist/esm/libs/preload/transformLinks2String.js +118 -0
  19. package/dist/esm/libs/proxy.js +88 -50
  20. package/dist/esm/libs/render/index.js +17 -3
  21. package/dist/esm/libs/serverTiming.js +1 -1
  22. package/dist/esm/renderHtml.js +6 -6
  23. package/dist/esm/server/modernServer.js +22 -17
  24. package/dist/esm/server/modernServerSplit.js +6 -6
  25. package/dist/esm-node/constants.js +7 -0
  26. package/dist/esm-node/libs/context/context.js +7 -2
  27. package/dist/esm-node/libs/preload/flushServerHeader.js +45 -0
  28. package/dist/esm-node/libs/preload/index.js +2 -0
  29. package/dist/esm-node/libs/preload/parseLinks.js +88 -0
  30. package/dist/esm-node/libs/preload/transformLinks2String.js +103 -0
  31. package/dist/esm-node/libs/proxy.js +44 -41
  32. package/dist/esm-node/libs/render/index.js +16 -2
  33. package/dist/esm-node/libs/serverTiming.js +1 -1
  34. package/dist/esm-node/server/modernServer.js +22 -17
  35. package/dist/types/constants.d.ts +7 -1
  36. package/dist/types/libs/context/context.d.ts +1 -1
  37. package/dist/types/libs/preload/flushServerHeader.d.ts +20 -0
  38. package/dist/types/libs/preload/index.d.ts +2 -0
  39. package/dist/types/libs/preload/parseLinks.d.ts +14 -0
  40. package/dist/types/libs/preload/transformLinks2String.d.ts +3 -0
  41. package/dist/types/libs/proxy.d.ts +3 -3
  42. package/dist/types/libs/render/index.d.ts +2 -0
  43. package/dist/types/libs/serverTiming.d.ts +1 -0
  44. package/dist/types/type.d.ts +3 -0
  45. package/dist/types/utils.d.ts +1 -1
  46. package/package.json +18 -17
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # @modern-js/prod-server
2
2
 
3
+ ## 2.32.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @modern-js/server-core@2.32.1
8
+ - @modern-js/utils@2.32.1
9
+ - @modern-js/plugin@2.32.1
10
+
11
+ ## 2.32.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 2447d64: feat: support ssr resources preload
16
+ feat: 支持 ssr 资源预加载
17
+
18
+ ### Patch Changes
19
+
20
+ - e6c7d33: fix about server timing not use metaName at some case
21
+ - 6076166: fix: packaging errors found by publint
22
+
23
+ fix: 修复 publint 检测到的 packaging 问题
24
+
25
+ - 5f7c714: fix: WebSocket upgrade handler cause HMR connection issue
26
+ fix: WebSocket upgrade handler 导致 HMR 连接错误
27
+ - 6d73519: fix: update server reportTimings name
28
+ fix: 更新 server reportTimings 名称
29
+ - 79658a0: fix: collects ServerReportTiming Names, and then reports it only when cost != 0
30
+ fix: 收集 ServerReportTiming Names, 然后只有在 cost !=0 时才报告它
31
+ - Updated dependencies [e5a3fb4]
32
+ - Updated dependencies [6076166]
33
+ - Updated dependencies [a030aff]
34
+ - Updated dependencies [3c91100]
35
+ - Updated dependencies [2447d64]
36
+ - Updated dependencies [5255eba]
37
+ - @modern-js/utils@2.32.0
38
+ - @modern-js/plugin@2.32.0
39
+ - @modern-js/server-core@2.32.0
40
+
3
41
  ## 2.31.2
4
42
 
5
43
  ### Patch Changes
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 Modern.js
3
+ Copyright (c) 2021-present Modern.js
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -13,6 +13,9 @@ _export(exports, {
13
13
  ApiServerMode: function() {
14
14
  return ApiServerMode;
15
15
  },
16
+ ServerReportTimings: function() {
17
+ return ServerReportTimings;
18
+ },
16
19
  AGGRED_DIR: function() {
17
20
  return AGGRED_DIR;
18
21
  },
@@ -54,3 +57,10 @@ const RUN_MODE = {
54
57
  FULL: "full",
55
58
  TYPE: "type"
56
59
  };
60
+ var ServerReportTimings;
61
+ (function(ServerReportTimings2) {
62
+ ServerReportTimings2["SERVER_HANDLE_REQUEST"] = "server-handle-request";
63
+ ServerReportTimings2["SERVER_MIDDLEWARE"] = "server-middleware";
64
+ ServerReportTimings2["SERVER_HOOK_AFTER_RENDER"] = "server-hook-after-render";
65
+ ServerReportTimings2["SERVER_HOOK_AFTER_MATCH"] = "server-hook-after-match";
66
+ })(ServerReportTimings || (ServerReportTimings = {}));
@@ -38,7 +38,12 @@ class ModernServerContext {
38
38
  bind() {
39
39
  const { req, res } = this;
40
40
  req.get = (key) => this.getReqHeader(key);
41
- res.set = (key, value) => this.res.setHeader(key, value);
41
+ res.set = (key, value) => {
42
+ if (!res.headersSent) {
43
+ res.setHeader(key, value);
44
+ }
45
+ return res;
46
+ };
42
47
  res.send = (body) => {
43
48
  this.send(body);
44
49
  };
@@ -178,7 +183,7 @@ class ModernServerContext {
178
183
  this.req = req;
179
184
  this.res = res;
180
185
  this.options = options || {};
181
- this.serverTiming = new _serverTiming.ServerTiming(res, (0, _utils.cutNameByHyphen)(((_options = options) === null || _options === void 0 ? void 0 : _options.metaName) || "modern-js"));
182
186
  this.bind();
187
+ this.serverTiming = new _serverTiming.ServerTiming(this.res, (0, _utils.cutNameByHyphen)(((_options = options) === null || _options === void 0 ? void 0 : _options.metaName) || "modern-js"));
183
188
  }
184
189
  }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for (var name in all)
7
+ Object.defineProperty(target, name, {
8
+ enumerable: true,
9
+ get: all[name]
10
+ });
11
+ }
12
+ _export(exports, {
13
+ transformToRegExp: function() {
14
+ return transformToRegExp;
15
+ },
16
+ shouldFlushServerHeader: function() {
17
+ return shouldFlushServerHeader;
18
+ },
19
+ flushServerHeader: function() {
20
+ return flushServerHeader;
21
+ }
22
+ });
23
+ const _parseLinks = require("./parseLinks");
24
+ const _transformLinks2String = require("./transformLinks2String");
25
+ function transformToRegExp(input) {
26
+ if (typeof input === "string") {
27
+ return new RegExp(input);
28
+ }
29
+ return input;
30
+ }
31
+ function shouldFlushServerHeader(serverConf, userAgent, disablePreload) {
32
+ const { ssr: ssrConf } = serverConf || {};
33
+ if (disablePreload) {
34
+ return false;
35
+ }
36
+ if (typeof ssrConf === "object" && ssrConf.preload) {
37
+ if (typeof ssrConf.preload === "object") {
38
+ const { userAgentFilter } = ssrConf.preload;
39
+ if (userAgentFilter && userAgent) {
40
+ return !transformToRegExp(userAgentFilter).test(userAgent);
41
+ }
42
+ return true;
43
+ }
44
+ return true;
45
+ }
46
+ return false;
47
+ }
48
+ async function flushServerHeader({ serverConf, ctx, distDir, template, headers }) {
49
+ const { ssr: ssrConf } = serverConf || {};
50
+ if (typeof ssrConf !== "object") {
51
+ return;
52
+ }
53
+ const { res } = ctx;
54
+ const links = await (0, _parseLinks.parseLinks)({
55
+ template,
56
+ distDir,
57
+ pathname: ctx.path
58
+ });
59
+ const link = (0, _transformLinks2String.transformLinks2String)(links, ssrConf.preload);
60
+ res.set("link", link);
61
+ for (const key in headers || {}) {
62
+ var _headers;
63
+ const value = (_headers = headers) === null || _headers === void 0 ? void 0 : _headers[key];
64
+ value && res.set(key, value);
65
+ }
66
+ res.flushHeaders();
67
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ const _export_star = require("@swc/helpers/_/_export_star");
6
+ _export_star._(require("./parseLinks"), exports);
7
+ _export_star._(require("./flushServerHeader"), exports);
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "parseLinks", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return parseLinks;
9
+ }
10
+ });
11
+ const _interop_require_default = require("@swc/helpers/_/_interop_require_default");
12
+ const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
13
+ const _path = /* @__PURE__ */ _interop_require_default._(require("path"));
14
+ const _utils = require("@modern-js/utils");
15
+ const _nodehtmlparser = require("node-html-parser");
16
+ const _remixrouter = require("@modern-js/utils/runtime/remix-router");
17
+ const _runtimenode = require("@modern-js/utils/runtime-node");
18
+ async function parseLinks({ pathname, distDir, template }) {
19
+ const links = await parseLinksFromRoutes(pathname, distDir);
20
+ return links.length > 0 ? links : parseLinksFromHtml(template);
21
+ }
22
+ function parseLinksFromHtml(html) {
23
+ const root = (0, _nodehtmlparser.parse)(html);
24
+ const scripts = root.querySelectorAll("script").filter((elem) => Boolean(elem.getAttribute("src")));
25
+ const css = root.querySelectorAll("link").filter((elem) => {
26
+ const href = elem.getAttribute("href");
27
+ const rel = elem.getAttribute("rel");
28
+ return href && rel === "stylesheet";
29
+ });
30
+ const images = root.querySelectorAll("img").filter((elem) => Boolean(elem.getAttribute("src")));
31
+ return scripts.map((elem) => {
32
+ const src = elem.getAttribute("src");
33
+ return {
34
+ uri: src,
35
+ as: "script"
36
+ };
37
+ }).concat(css.map((elem) => {
38
+ const href = elem.getAttribute("href");
39
+ return {
40
+ uri: href,
41
+ as: "style"
42
+ };
43
+ })).concat(images.map((elem) => {
44
+ const src = elem.getAttribute("src");
45
+ return {
46
+ uri: src,
47
+ as: "image"
48
+ };
49
+ }));
50
+ }
51
+ async function parseLinksFromRoutes(pathname, distDir) {
52
+ const noopLinks = [];
53
+ const nestedRoutesSpec = _path.default.join(distDir, _utils.NESTED_ROUTE_SPEC_FILE);
54
+ const routesJsonPath = _path.default.join(distDir, _utils.ROUTE_SPEC_FILE);
55
+ const routeManifestPath = _path.default.join(distDir, _utils.ROUTE_MANIFEST_FILE);
56
+ if (!_utils.fs.existsSync(nestedRoutesSpec) || !_utils.fs.existsSync(routesJsonPath) || !_utils.fs.existsSync(routeManifestPath)) {
57
+ return noopLinks;
58
+ }
59
+ const routesJson = await Promise.resolve(routesJsonPath).then((p) => /* @__PURE__ */ _interop_require_wildcard._(require(p)));
60
+ const serverRoutes = routesJson.routes;
61
+ const entry = (0, _runtimenode.matchEntry)(pathname, serverRoutes);
62
+ if (entry) {
63
+ var _routeAssets_entryName, _matches, _assets_filter, _assets, _assets_filter1, _assets1;
64
+ const routes = await Promise.resolve(nestedRoutesSpec).then((p) => /* @__PURE__ */ _interop_require_wildcard._(require(p)));
65
+ const { entryName } = entry;
66
+ if (!entryName) {
67
+ return noopLinks;
68
+ }
69
+ const entryRoutes = routes[entryName];
70
+ if (!entryRoutes) {
71
+ return noopLinks;
72
+ }
73
+ const routesManifest = await Promise.resolve(routeManifestPath).then((p) => /* @__PURE__ */ _interop_require_wildcard._(require(p)));
74
+ const { routeAssets } = routesManifest;
75
+ const matches = (0, _remixrouter.matchRoutes)(entryRoutes, pathname, entry.urlPath);
76
+ const entryAssets = (_routeAssets_entryName = routeAssets[entryName]) === null || _routeAssets_entryName === void 0 ? void 0 : _routeAssets_entryName.assets;
77
+ const assets = (_matches = matches) === null || _matches === void 0 ? void 0 : _matches.reduce((acc, match) => {
78
+ const routeId = match.route.id;
79
+ if (routeId) {
80
+ var _matchedManifest;
81
+ const matchedManifest = routeAssets[routeId];
82
+ const assets2 = (_matchedManifest = matchedManifest) === null || _matchedManifest === void 0 ? void 0 : _matchedManifest.assets;
83
+ if (Array.isArray(assets2)) {
84
+ acc.push(...assets2);
85
+ }
86
+ }
87
+ return acc;
88
+ }, []).concat(entryAssets || []);
89
+ const cssLinks = (_assets = assets) === null || _assets === void 0 ? void 0 : (_assets_filter = _assets.filter((asset) => asset.endsWith(".css"))) === null || _assets_filter === void 0 ? void 0 : _assets_filter.map((uri) => ({
90
+ uri,
91
+ as: "style"
92
+ }));
93
+ const scriptLinks = (_assets1 = assets) === null || _assets1 === void 0 ? void 0 : (_assets_filter1 = _assets1.filter((asset) => asset.endsWith(".js"))) === null || _assets_filter1 === void 0 ? void 0 : _assets_filter1.map((uri) => ({
94
+ uri,
95
+ as: "script"
96
+ }));
97
+ return (cssLinks || []).concat(scriptLinks || []);
98
+ }
99
+ return noopLinks;
100
+ }
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "transformLinks2String", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return transformLinks2String;
9
+ }
10
+ });
11
+ const _flushServerHeader = require("./flushServerHeader");
12
+ function transformLinks2String(links, preload) {
13
+ if (typeof preload === "boolean") {
14
+ return links.map(({ uri, as }) => as ? `<${uri}>; rel=preload; as=${as}` : `<${uri}>; rel=preload`).join(", ");
15
+ }
16
+ const { include, exclude, attributes } = preload;
17
+ const resolveLinks = addAttributes(removeExclude(addInclude(links, include), exclude), attributes);
18
+ return resolveLinks.join(", ");
19
+ function addInclude(links2, include2) {
20
+ var _include;
21
+ const images = [
22
+ "gif",
23
+ "jpg",
24
+ "jpeg",
25
+ "png",
26
+ "webp",
27
+ "bmp",
28
+ "tiff",
29
+ "anpg",
30
+ "ico"
31
+ ];
32
+ const videos = [
33
+ "mp4",
34
+ "webm",
35
+ "ogm",
36
+ "ogv",
37
+ "ogg"
38
+ ];
39
+ const fonts = [
40
+ "woff",
41
+ "woff2",
42
+ "eot",
43
+ "ttf",
44
+ "otf"
45
+ ];
46
+ const includes = ((_include = include2) === null || _include === void 0 ? void 0 : _include.map((item) => {
47
+ if (typeof item === "string") {
48
+ const type = (() => {
49
+ if (item.endsWith(".js")) {
50
+ return "script";
51
+ }
52
+ if (item.endsWith(".css")) {
53
+ return "style";
54
+ }
55
+ if (images.some((image) => item.endsWith(`.${image}`))) {
56
+ return "image";
57
+ }
58
+ if (videos.some((video) => item.endsWith(`.${video}`))) {
59
+ return "video";
60
+ }
61
+ if (fonts.some((font) => item.endsWith(`.${font}`))) {
62
+ return "font";
63
+ }
64
+ })();
65
+ return {
66
+ uri: item,
67
+ as: type
68
+ };
69
+ }
70
+ return {
71
+ uri: item.url,
72
+ as: item.type
73
+ };
74
+ })) || [];
75
+ return links2.concat(includes);
76
+ }
77
+ function removeExclude(links2, exclude2) {
78
+ return exclude2 ? links2.filter(({ uri }) => !(0, _flushServerHeader.transformToRegExp)(exclude2).test(uri)) : links2;
79
+ }
80
+ function addAttributes(links2, attributes2) {
81
+ const parseAttributes = (_attributes) => {
82
+ return Object.entries(_attributes || {}).reduce((results, [key, value]) => {
83
+ if (typeof value === "boolean") {
84
+ value && results.push(`; ${key}`);
85
+ return results;
86
+ }
87
+ results.push(`; ${key}=${value}`);
88
+ return results;
89
+ }, []).join("");
90
+ };
91
+ return links2.map(({ uri, as }) => {
92
+ if (as) {
93
+ const attributesStr = (() => {
94
+ const { style, script, image, font } = attributes2 || {};
95
+ switch (as) {
96
+ case "script":
97
+ return parseAttributes(script);
98
+ case "style":
99
+ return parseAttributes(style);
100
+ case "image":
101
+ return parseAttributes(image);
102
+ case "font":
103
+ return parseAttributes(font);
104
+ default:
105
+ return "";
106
+ }
107
+ })();
108
+ return `<${uri}>; rel=preload; as=${as}${attributesStr}`;
109
+ }
110
+ return `<${uri}>; rel=preload`;
111
+ });
112
+ }
113
+ }
@@ -17,55 +17,49 @@ _export(exports, {
17
17
  return createProxyHandler;
18
18
  }
19
19
  });
20
- const _httpproxymiddleware = require("http-proxy-middleware");
20
+ const _httpproxymiddleware = require("http-proxy-middleware/dist/http-proxy-middleware");
21
21
  const _utils = require("../utils");
22
22
  function formatProxyOptions(proxyOptions) {
23
- const formattedProxy = [];
24
- if (!Array.isArray(proxyOptions)) {
25
- if ("target" in proxyOptions) {
26
- formattedProxy.push(proxyOptions);
27
- } else {
28
- Array.prototype.push.apply(formattedProxy, Object.keys(proxyOptions).reduce((total, source) => {
29
- const option = proxyOptions[source];
30
- total.push({
31
- context: source,
32
- changeOrigin: true,
33
- logLevel: "warn",
34
- ...typeof option === "string" ? {
35
- target: option
36
- } : option
37
- });
38
- return total;
39
- }, []));
40
- }
23
+ const ret = [];
24
+ if (Array.isArray(proxyOptions)) {
25
+ ret.push(...proxyOptions);
26
+ } else if ("target" in proxyOptions) {
27
+ ret.push(proxyOptions);
41
28
  } else {
42
- formattedProxy.push(...proxyOptions);
43
- }
44
- return formattedProxy;
45
- }
46
- const createProxyHandler = (proxyOptions) => {
47
- (0, _utils.debug)("createProxyHandler", proxyOptions);
48
- const middlewares = [];
49
- const handlers = [];
50
- const handleUpgrade = (req, socket, head) => {
51
- for (const middleware of middlewares) {
52
- if (typeof middleware.upgrade === "function") {
53
- middleware.upgrade(req, socket, head);
29
+ for (const [context, options] of Object.entries(proxyOptions)) {
30
+ const opts = {
31
+ context,
32
+ changeOrigin: true,
33
+ logLevel: "warn"
34
+ };
35
+ if (typeof options === "string") {
36
+ opts.target = options;
37
+ } else {
38
+ Object.assign(opts, options);
54
39
  }
40
+ ret.push(opts);
55
41
  }
42
+ }
43
+ const handleError = (err, _req, _res, _target) => {
44
+ console.error(err);
56
45
  };
57
- if (!proxyOptions) {
58
- return {
59
- handlers,
60
- handleUpgrade
61
- };
46
+ for (const opts of ret) {
47
+ var _opts;
48
+ var _onError;
49
+ (_onError = (_opts = opts).onError) !== null && _onError !== void 0 ? _onError : _opts.onError = handleError;
62
50
  }
51
+ return ret;
52
+ }
53
+ const createProxyHandler = (proxyOptions) => {
54
+ (0, _utils.debug)("createProxyHandler", proxyOptions);
63
55
  const formattedOptionsList = formatProxyOptions(proxyOptions);
64
- for (const options of formattedOptionsList) {
65
- const middleware = (0, _httpproxymiddleware.createProxyMiddleware)(options.context, options);
56
+ const proxies = [];
57
+ const handlers = [];
58
+ for (const opts of formattedOptionsList) {
59
+ const proxy = new _httpproxymiddleware.HttpProxyMiddleware(opts.context, opts);
66
60
  const handler = async (ctx, next) => {
67
61
  const { req, res } = ctx;
68
- const bypassUrl = typeof options.bypass === "function" ? options.bypass(req, res, options) : null;
62
+ const bypassUrl = typeof opts.bypass === "function" ? opts.bypass(req, res, opts) : null;
69
63
  if (typeof bypassUrl === "boolean") {
70
64
  ctx.status = 404;
71
65
  next();
@@ -73,12 +67,21 @@ const createProxyHandler = (proxyOptions) => {
73
67
  ctx.url = bypassUrl;
74
68
  next();
75
69
  } else {
76
- middleware(req, res, next);
70
+ proxy.middleware(req, res, next);
77
71
  }
78
72
  };
79
- middlewares.push(middleware);
73
+ proxies.push(proxy);
80
74
  handlers.push(handler);
81
75
  }
76
+ const handleUpgrade = (server) => {
77
+ for (const proxy of proxies) {
78
+ const raw = proxy;
79
+ if (raw.proxyOptions.ws === true && !raw.wsInternalSubscribed) {
80
+ server.on("upgrade", raw.handleUpgrade);
81
+ raw.wsInternalSubscribed = true;
82
+ }
83
+ }
84
+ };
82
85
  return {
83
86
  handlers,
84
87
  handleUpgrade
@@ -13,11 +13,12 @@ const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildc
13
13
  const _path = /* @__PURE__ */ _interop_require_default._(require("path"));
14
14
  const _utils = require("@modern-js/utils");
15
15
  const _constants = require("../../constants");
16
+ const _preload = require("../preload");
16
17
  const _static = require("./static");
17
18
  const _reader = require("./reader");
18
19
  const _ssr = /* @__PURE__ */ _interop_require_wildcard._(require("./ssr"));
19
20
  const _utils1 = require("./utils");
20
- const createRenderHandler = ({ distDir, staticGenerate, forceCSR, nonce, ssrRender, metaName = "modern-js" }) => async function render({ ctx, route, runner }) {
21
+ const createRenderHandler = ({ distDir, staticGenerate, conf, forceCSR, nonce, ssrRender, metaName = "modern-js" }) => async function render({ ctx, route, runner }) {
21
22
  if (ctx.resHasHandled()) {
22
23
  return null;
23
24
  }
@@ -35,6 +36,19 @@ const createRenderHandler = ({ distDir, staticGenerate, forceCSR, nonce, ssrRend
35
36
  const useCSR = forceCSR && (ctx.query.csr || ctx.headers[`x-${(0, _utils.cutNameByHyphen)(metaName)}-ssr-fallback`]);
36
37
  if (route.isSSR && !useCSR) {
37
38
  try {
39
+ const userAgent = ctx.getReqHeader("User-Agent");
40
+ const disablePreload = Boolean(ctx.headers[`x-${(0, _utils.cutNameByHyphen)(metaName)}-disable-preload`]);
41
+ if ((0, _preload.shouldFlushServerHeader)(conf.server, userAgent, disablePreload)) {
42
+ (0, _preload.flushServerHeader)({
43
+ serverConf: conf.server,
44
+ ctx,
45
+ distDir,
46
+ template: content.toString(),
47
+ headers: {
48
+ "Content-Type": _utils.mime.contentType(_path.default.extname(templatePath))
49
+ }
50
+ });
51
+ }
38
52
  const ssrRenderOptions = {
39
53
  distDir,
40
54
  entryName: route.entryName,
@@ -56,7 +70,7 @@ const createRenderHandler = ({ distDir, staticGenerate, forceCSR, nonce, ssrRend
56
70
  return result;
57
71
  } catch (err) {
58
72
  ctx.error(_constants.ERROR_DIGEST.ERENDER, err.stack || err.message);
59
- ctx.res.setHeader("x-modern-ssr-fallback", "1");
73
+ ctx.res.set("x-modern-ssr-fallback", "1");
60
74
  }
61
75
  }
62
76
  return {
@@ -15,7 +15,7 @@ class ServerTiming {
15
15
  const _name = `bd-${this.meta}-${name}`;
16
16
  const serverTiming = this.res.getHeader(SERVER_TIMING) || this.res.getHeader(SERVER_TIMING.toLocaleLowerCase());
17
17
  const value = `${_name};${desc ? `decs="${desc}";` : ""} dur=${dur}`;
18
- this.res.setHeader(SERVER_TIMING, serverTiming ? `${serverTiming}, ${value}` : value);
18
+ this.res.set(SERVER_TIMING, serverTiming ? `${serverTiming}, ${value}` : value);
19
19
  return this;
20
20
  }
21
21
  constructor(res, meta) {
@@ -28,17 +28,19 @@ const SERVER_DIR = "./server";
28
28
  class ModernServer {
29
29
  // server prepare
30
30
  async onInit(runner, app) {
31
- var _conf_bff, _app, _app1, _this_conf_output;
31
+ var _conf_bff, _app, _this_conf_output;
32
32
  this.runner = runner;
33
33
  const { distDir, conf } = this;
34
34
  this.initReader();
35
35
  (0, _utils1.debug)("final server conf", this.conf);
36
- const proxyHandlers = (0, _proxy.createProxyHandler)((_conf_bff = conf.bff) === null || _conf_bff === void 0 ? void 0 : _conf_bff.proxy);
37
- (_app = app) === null || _app === void 0 ? void 0 : _app.on("upgrade", proxyHandlers.handleUpgrade);
38
- proxyHandlers.handlers.forEach((handler) => {
39
- this.addHandler(handler);
40
- });
41
- (_app1 = app) === null || _app1 === void 0 ? void 0 : _app1.on("close", () => {
36
+ if ((_conf_bff = conf.bff) === null || _conf_bff === void 0 ? void 0 : _conf_bff.proxy) {
37
+ const { handlers, handleUpgrade } = (0, _proxy.createProxyHandler)(conf.bff.proxy);
38
+ app && handleUpgrade(app);
39
+ handlers.forEach((handler) => {
40
+ this.addHandler(handler);
41
+ });
42
+ }
43
+ (_app = app) === null || _app === void 0 ? void 0 : _app.on("close", () => {
42
44
  this.reader.close();
43
45
  });
44
46
  const usageRoutes = this.filterRoutes(this.getRoutes());
@@ -62,6 +64,7 @@ class ModernServer {
62
64
  distDir,
63
65
  staticGenerate,
64
66
  forceCSR,
67
+ conf: this.conf,
65
68
  nonce: (_conf_security = conf.security) === null || _conf_security === void 0 ? void 0 : _conf_security.nonce,
66
69
  metaName
67
70
  });
@@ -256,7 +259,7 @@ class ModernServer {
256
259
  if (this.isSend(res)) {
257
260
  return null;
258
261
  }
259
- res.setHeader("content-type", renderResult.contentType);
262
+ res.set("content-type", renderResult.contentType);
260
263
  return renderResult;
261
264
  }
262
265
  async proxy() {
@@ -291,7 +294,7 @@ class ModernServer {
291
294
  const end = (0, _time.time)();
292
295
  res.on("finish", () => {
293
296
  const cost = end();
294
- reporter.reportTiming("server_handle_request", cost);
297
+ reporter.reportTiming(_constants.ServerReportTimings.SERVER_HANDLE_REQUEST, cost);
295
298
  });
296
299
  let route = matched.generate(context.url);
297
300
  if (route.isApi) {
@@ -306,7 +309,7 @@ class ModernServer {
306
309
  onLast: _utils1.noop
307
310
  });
308
311
  const cost = end2();
309
- reporter.reportTiming("server_hook_after_render", cost);
312
+ cost && reporter.reportTiming(_constants.ServerReportTimings.SERVER_HOOK_AFTER_MATCH, cost);
310
313
  }
311
314
  if (this.isSend(res)) {
312
315
  return;
@@ -331,7 +334,7 @@ class ModernServer {
331
334
  const end2 = (0, _time.time)();
332
335
  await this.frameWebHandler(middlewareContext);
333
336
  const cost = end2();
334
- reporter.reportTiming("server_middleware", cost);
337
+ cost && reporter.reportTiming(_constants.ServerReportTimings.SERVER_MIDDLEWARE, cost);
335
338
  res.locals = {
336
339
  ...res.locals,
337
340
  ...middlewareContext.response.locals
@@ -358,7 +361,7 @@ class ModernServer {
358
361
  onLast: _utils1.noop
359
362
  });
360
363
  const cost = end2();
361
- reporter.reportTiming("server_hook_after_render", cost);
364
+ cost && reporter.reportTiming(_constants.ServerReportTimings.SERVER_HOOK_AFTER_RENDER, cost);
362
365
  }
363
366
  if (this.isSend(res)) {
364
367
  return;
@@ -368,7 +371,7 @@ class ModernServer {
368
371
  res.end(response);
369
372
  }
370
373
  isSend(res) {
371
- if (res.headersSent) {
374
+ if (res.writableEnded) {
372
375
  return true;
373
376
  }
374
377
  if (res.getHeader("Location") && (0, _utils1.isRedirect)(res.statusCode)) {
@@ -420,7 +423,9 @@ class ModernServer {
420
423
  req.metrics = req.metrics || this.metrics;
421
424
  let context;
422
425
  try {
423
- context = this.createContext(req, res);
426
+ context = this.createContext(req, res, {
427
+ metaName: this.metaName
428
+ });
424
429
  } catch (e) {
425
430
  this.logger.error(e);
426
431
  res.statusCode = 500;
@@ -434,7 +439,7 @@ class ModernServer {
434
439
  }
435
440
  }
436
441
  redirect(res, url, status = 302) {
437
- res.setHeader("Location", url);
442
+ res.set("Location", url);
438
443
  res.statusCode = status;
439
444
  res.end();
440
445
  }
@@ -445,7 +450,7 @@ class ModernServer {
445
450
  async renderErrorPage(context, status) {
446
451
  const { res } = context;
447
452
  context.status = status;
448
- res.setHeader("content-type", _utils.mime.contentType("html"));
453
+ res.set("content-type", _utils.mime.contentType("html"));
449
454
  const statusPage = `/${status}`;
450
455
  const customErrorPage = `/_error`;
451
456
  const matched = this.router.match(statusPage) || this.router.match(customErrorPage);
@@ -26,3 +26,10 @@ export var RUN_MODE = {
26
26
  FULL: "full",
27
27
  TYPE: "type"
28
28
  };
29
+ export var ServerReportTimings;
30
+ (function(ServerReportTimings2) {
31
+ ServerReportTimings2["SERVER_HANDLE_REQUEST"] = "server-handle-request";
32
+ ServerReportTimings2["SERVER_MIDDLEWARE"] = "server-middleware";
33
+ ServerReportTimings2["SERVER_HOOK_AFTER_RENDER"] = "server-hook-after-render";
34
+ ServerReportTimings2["SERVER_HOOK_AFTER_MATCH"] = "server-hook-after-match";
35
+ })(ServerReportTimings || (ServerReportTimings = {}));