@modern-js/server-core 2.48.6 → 2.49.1-alpha.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.
Files changed (209) hide show
  1. package/dist/cjs/base/adapters/node/bff.js +70 -0
  2. package/dist/cjs/base/adapters/node/hono.js +63 -0
  3. package/dist/cjs/base/adapters/node/index.js +56 -0
  4. package/dist/cjs/base/adapters/node/loadServer.js +56 -0
  5. package/dist/cjs/base/adapters/node/middlewares/index.js +28 -0
  6. package/dist/cjs/base/adapters/node/middlewares/mock.js +113 -0
  7. package/dist/cjs/base/adapters/node/middlewares/serverManifest.js +90 -0
  8. package/dist/cjs/base/adapters/node/middlewares/serverPublic.js +67 -0
  9. package/dist/cjs/base/adapters/node/middlewares/serverStatic.js +109 -0
  10. package/dist/cjs/base/adapters/node/middlewares/templates.js +67 -0
  11. package/dist/cjs/base/adapters/node/node.js +127 -0
  12. package/dist/cjs/base/adapters/node/polyfills/index.js +24 -0
  13. package/dist/cjs/base/adapters/node/polyfills/install.js +72 -0
  14. package/dist/cjs/base/adapters/node/polyfills/stream.js +153 -0
  15. package/dist/cjs/base/constants.js +58 -0
  16. package/dist/cjs/base/index.js +49 -0
  17. package/dist/cjs/base/middlewares/customServer/base.js +171 -0
  18. package/dist/cjs/base/middlewares/customServer/context.js +73 -0
  19. package/dist/cjs/base/middlewares/customServer/index.js +136 -0
  20. package/dist/cjs/base/middlewares/customServer/routerApi.js +44 -0
  21. package/dist/cjs/base/middlewares/customServer/template.js +58 -0
  22. package/dist/cjs/base/middlewares/faviconFallback.js +34 -0
  23. package/dist/cjs/base/middlewares/frameworkHeader.js +31 -0
  24. package/dist/cjs/base/middlewares/index.js +30 -0
  25. package/dist/cjs/base/middlewares/logger.js +77 -0
  26. package/dist/cjs/base/middlewares/monitor.js +90 -0
  27. package/dist/cjs/base/middlewares/renderHandler/dataHandler.js +46 -0
  28. package/dist/cjs/base/middlewares/renderHandler/index.js +108 -0
  29. package/dist/cjs/base/middlewares/renderHandler/render.js +132 -0
  30. package/dist/cjs/base/middlewares/renderHandler/serverTiming.js +40 -0
  31. package/dist/cjs/base/middlewares/renderHandler/ssrCache.js +197 -0
  32. package/dist/cjs/base/middlewares/renderHandler/ssrRender.js +212 -0
  33. package/dist/cjs/base/serverBase.js +203 -0
  34. package/dist/cjs/base/utils/debug.js +29 -0
  35. package/dist/cjs/base/utils/entry.js +30 -0
  36. package/dist/cjs/base/utils/env.js +45 -0
  37. package/dist/cjs/base/utils/error.js +65 -0
  38. package/dist/cjs/base/utils/index.js +34 -0
  39. package/dist/cjs/base/utils/middlewareCollector.js +54 -0
  40. package/dist/cjs/base/utils/request.js +65 -0
  41. package/dist/cjs/base/utils/serverConfig.js +70 -0
  42. package/dist/cjs/base/utils/transformStream.js +61 -0
  43. package/dist/cjs/base/utils/warmup.js +43 -0
  44. package/dist/cjs/core/index.js +22 -0
  45. package/dist/cjs/{loadPlugins.js → core/loadPlugins.js} +4 -7
  46. package/dist/cjs/{plugin.js → core/plugin.js} +1 -42
  47. package/dist/cjs/core/render.js +16 -0
  48. package/dist/cjs/core/server.js +16 -0
  49. package/dist/cjs/index.js +6 -4
  50. package/dist/esm/base/adapters/node/bff.js +128 -0
  51. package/dist/esm/base/adapters/node/hono.js +83 -0
  52. package/dist/esm/base/adapters/node/index.js +20 -0
  53. package/dist/esm/base/adapters/node/loadServer.js +73 -0
  54. package/dist/esm/base/adapters/node/middlewares/index.js +4 -0
  55. package/dist/esm/base/adapters/node/middlewares/mock.js +198 -0
  56. package/dist/esm/base/adapters/node/middlewares/serverManifest.js +139 -0
  57. package/dist/esm/base/adapters/node/middlewares/serverPublic.js +85 -0
  58. package/dist/esm/base/adapters/node/middlewares/serverStatic.js +119 -0
  59. package/dist/esm/base/adapters/node/middlewares/templates.js +114 -0
  60. package/dist/esm/base/adapters/node/node.js +197 -0
  61. package/dist/esm/base/adapters/node/polyfills/index.js +2 -0
  62. package/dist/esm/base/adapters/node/polyfills/install.js +48 -0
  63. package/dist/esm/base/adapters/node/polyfills/stream.js +316 -0
  64. package/dist/esm/base/constants.js +31 -0
  65. package/dist/esm/base/index.js +16 -0
  66. package/dist/esm/base/middlewares/customServer/base.js +199 -0
  67. package/dist/esm/base/middlewares/customServer/context.js +68 -0
  68. package/dist/esm/base/middlewares/customServer/index.js +220 -0
  69. package/dist/esm/base/middlewares/customServer/routerApi.js +26 -0
  70. package/dist/esm/base/middlewares/customServer/template.js +47 -0
  71. package/dist/esm/base/middlewares/faviconFallback.js +28 -0
  72. package/dist/esm/base/middlewares/frameworkHeader.js +27 -0
  73. package/dist/esm/base/middlewares/index.js +5 -0
  74. package/dist/esm/base/middlewares/logger.js +75 -0
  75. package/dist/esm/base/middlewares/monitor.js +157 -0
  76. package/dist/esm/base/middlewares/renderHandler/dataHandler.js +45 -0
  77. package/dist/esm/base/middlewares/renderHandler/index.js +167 -0
  78. package/dist/esm/base/middlewares/renderHandler/render.js +225 -0
  79. package/dist/esm/base/middlewares/renderHandler/serverTiming.js +21 -0
  80. package/dist/esm/base/middlewares/renderHandler/ssrCache.js +306 -0
  81. package/dist/esm/base/middlewares/renderHandler/ssrRender.js +269 -0
  82. package/dist/esm/base/serverBase.js +383 -0
  83. package/dist/esm/base/utils/debug.js +5 -0
  84. package/dist/esm/base/utils/entry.js +6 -0
  85. package/dist/esm/base/utils/env.js +20 -0
  86. package/dist/esm/base/utils/error.js +12 -0
  87. package/dist/esm/base/utils/index.js +7 -0
  88. package/dist/esm/base/utils/middlewareCollector.js +31 -0
  89. package/dist/esm/base/utils/request.js +39 -0
  90. package/dist/esm/base/utils/serverConfig.js +58 -0
  91. package/dist/esm/base/utils/transformStream.js +90 -0
  92. package/dist/esm/base/utils/warmup.js +9 -0
  93. package/dist/esm/core/index.js +1 -0
  94. package/dist/esm/core/loadPlugins.js +26 -0
  95. package/dist/esm/core/plugin.js +59 -0
  96. package/dist/esm/core/render.js +0 -0
  97. package/dist/esm/core/server.js +0 -0
  98. package/dist/esm/index.js +3 -2
  99. package/dist/esm-node/base/adapters/node/bff.js +46 -0
  100. package/dist/esm-node/base/adapters/node/hono.js +38 -0
  101. package/dist/esm-node/base/adapters/node/index.js +20 -0
  102. package/dist/esm-node/base/adapters/node/loadServer.js +22 -0
  103. package/dist/esm-node/base/adapters/node/middlewares/index.js +4 -0
  104. package/dist/esm-node/base/adapters/node/middlewares/mock.js +79 -0
  105. package/dist/esm-node/base/adapters/node/middlewares/serverManifest.js +55 -0
  106. package/dist/esm-node/base/adapters/node/middlewares/serverPublic.js +33 -0
  107. package/dist/esm-node/base/adapters/node/middlewares/serverStatic.js +75 -0
  108. package/dist/esm-node/base/adapters/node/middlewares/templates.js +32 -0
  109. package/dist/esm-node/base/adapters/node/node.js +101 -0
  110. package/dist/esm-node/base/adapters/node/polyfills/index.js +2 -0
  111. package/dist/esm-node/base/adapters/node/polyfills/install.js +48 -0
  112. package/dist/esm-node/base/adapters/node/polyfills/stream.js +126 -0
  113. package/dist/esm-node/base/constants.js +31 -0
  114. package/dist/esm-node/base/index.js +16 -0
  115. package/dist/esm-node/base/middlewares/customServer/base.js +147 -0
  116. package/dist/esm-node/base/middlewares/customServer/context.js +46 -0
  117. package/dist/esm-node/base/middlewares/customServer/index.js +112 -0
  118. package/dist/esm-node/base/middlewares/customServer/routerApi.js +20 -0
  119. package/dist/esm-node/base/middlewares/customServer/template.js +34 -0
  120. package/dist/esm-node/base/middlewares/faviconFallback.js +10 -0
  121. package/dist/esm-node/base/middlewares/frameworkHeader.js +7 -0
  122. package/dist/esm-node/base/middlewares/index.js +5 -0
  123. package/dist/esm-node/base/middlewares/logger.js +53 -0
  124. package/dist/esm-node/base/middlewares/monitor.js +63 -0
  125. package/dist/esm-node/base/middlewares/renderHandler/dataHandler.js +22 -0
  126. package/dist/esm-node/base/middlewares/renderHandler/index.js +73 -0
  127. package/dist/esm-node/base/middlewares/renderHandler/render.js +108 -0
  128. package/dist/esm-node/base/middlewares/renderHandler/serverTiming.js +16 -0
  129. package/dist/esm-node/base/middlewares/renderHandler/ssrCache.js +162 -0
  130. package/dist/esm-node/base/middlewares/renderHandler/ssrRender.js +177 -0
  131. package/dist/esm-node/base/serverBase.js +168 -0
  132. package/dist/esm-node/base/utils/debug.js +5 -0
  133. package/dist/esm-node/base/utils/entry.js +6 -0
  134. package/dist/esm-node/base/utils/env.js +20 -0
  135. package/dist/esm-node/base/utils/error.js +41 -0
  136. package/dist/esm-node/base/utils/index.js +7 -0
  137. package/dist/esm-node/base/utils/middlewareCollector.js +29 -0
  138. package/dist/esm-node/base/utils/request.js +38 -0
  139. package/dist/esm-node/base/utils/serverConfig.js +34 -0
  140. package/dist/esm-node/base/utils/transformStream.js +36 -0
  141. package/dist/esm-node/base/utils/warmup.js +9 -0
  142. package/dist/esm-node/core/index.js +1 -0
  143. package/dist/{esm → esm-node/core}/loadPlugins.js +4 -7
  144. package/dist/{esm → esm-node/core}/plugin.js +1 -42
  145. package/dist/esm-node/core/render.js +0 -0
  146. package/dist/esm-node/core/server.js +0 -0
  147. package/dist/esm-node/index.js +5 -0
  148. package/dist/esm-node/types/config/bff.js +0 -0
  149. package/dist/esm-node/types/config/dev.js +0 -0
  150. package/dist/esm-node/types/config/html.js +0 -0
  151. package/dist/esm-node/types/config/index.js +6 -0
  152. package/dist/esm-node/types/config/output.js +0 -0
  153. package/dist/esm-node/types/config/security.js +0 -0
  154. package/dist/esm-node/types/config/server.js +0 -0
  155. package/dist/esm-node/types/config/share.js +0 -0
  156. package/dist/esm-node/types/config/source.js +0 -0
  157. package/dist/esm-node/types/config/tools.js +0 -0
  158. package/dist/types/base/adapters/node/bff.d.ts +3 -0
  159. package/dist/types/base/adapters/node/hono.d.ts +22 -0
  160. package/dist/types/base/adapters/node/index.d.ts +6 -0
  161. package/dist/types/base/adapters/node/loadServer.d.ts +3 -0
  162. package/dist/types/base/adapters/node/middlewares/index.d.ts +4 -0
  163. package/dist/types/base/adapters/node/middlewares/mock.d.ts +5 -0
  164. package/dist/types/base/adapters/node/middlewares/serverManifest.d.ts +4 -0
  165. package/dist/types/base/adapters/node/middlewares/serverPublic.d.ts +7 -0
  166. package/dist/types/base/adapters/node/middlewares/serverStatic.d.ts +11 -0
  167. package/dist/types/base/adapters/node/middlewares/templates.d.ts +4 -0
  168. package/dist/types/base/adapters/node/node.d.ts +13 -0
  169. package/dist/types/base/adapters/node/polyfills/index.d.ts +2 -0
  170. package/dist/types/base/adapters/node/polyfills/install.d.ts +1 -0
  171. package/dist/types/base/adapters/node/polyfills/stream.d.ts +18 -0
  172. package/dist/types/base/constants.d.ts +24 -0
  173. package/dist/types/base/index.d.ts +7 -0
  174. package/dist/types/base/middlewares/customServer/base.d.ts +3 -0
  175. package/dist/types/base/middlewares/customServer/context.d.ts +7 -0
  176. package/dist/types/base/middlewares/customServer/index.d.ts +13 -0
  177. package/dist/types/base/middlewares/customServer/routerApi.d.ts +9 -0
  178. package/dist/types/base/middlewares/customServer/template.d.ts +11 -0
  179. package/dist/types/base/middlewares/faviconFallback.d.ts +2 -0
  180. package/dist/types/base/middlewares/frameworkHeader.d.ts +2 -0
  181. package/dist/types/base/middlewares/index.d.ts +5 -0
  182. package/dist/types/base/middlewares/logger.d.ts +2 -0
  183. package/dist/types/base/middlewares/monitor.d.ts +6 -0
  184. package/dist/types/base/middlewares/renderHandler/dataHandler.d.ts +5 -0
  185. package/dist/types/base/middlewares/renderHandler/index.d.ts +9 -0
  186. package/dist/types/base/middlewares/renderHandler/render.d.ts +12 -0
  187. package/dist/types/base/middlewares/renderHandler/serverTiming.d.ts +7 -0
  188. package/dist/types/base/middlewares/renderHandler/ssrCache.d.ts +28 -0
  189. package/dist/types/base/middlewares/renderHandler/ssrRender.d.ts +21 -0
  190. package/dist/types/base/serverBase.d.ts +70 -0
  191. package/dist/types/base/utils/debug.d.ts +1 -0
  192. package/dist/types/base/utils/entry.d.ts +2 -0
  193. package/dist/types/base/utils/env.d.ts +2 -0
  194. package/dist/types/base/utils/error.d.ts +1 -0
  195. package/dist/types/base/utils/index.d.ts +7 -0
  196. package/dist/types/base/utils/middlewareCollector.d.ts +12 -0
  197. package/dist/types/base/utils/request.d.ts +12 -0
  198. package/dist/types/base/utils/serverConfig.d.ts +14 -0
  199. package/dist/types/base/utils/transformStream.d.ts +5 -0
  200. package/dist/types/base/utils/warmup.d.ts +1 -0
  201. package/dist/types/core/index.d.ts +1 -0
  202. package/dist/types/core/loadPlugins.d.ts +3 -0
  203. package/dist/types/core/plugin.d.ts +202 -0
  204. package/dist/types/core/render.d.ts +17 -0
  205. package/dist/types/core/server.d.ts +44 -0
  206. package/dist/types/index.d.ts +3 -2
  207. package/package.json +44 -6
  208. package/dist/types/loadPlugins.d.ts +0 -5
  209. package/dist/types/plugin.d.ts +0 -493
@@ -0,0 +1,22 @@
1
+ import { MAIN_ENTRY_NAME } from "@modern-js/utils/universal/constants";
2
+ const dataHandler = async (request, { routeInfo, serverRoutes, reporter, logger, serverManifest }) => {
3
+ var _serverManifest_loaderBundles;
4
+ const serverLoaderModule = serverManifest === null || serverManifest === void 0 ? void 0 : (_serverManifest_loaderBundles = serverManifest.loaderBundles) === null || _serverManifest_loaderBundles === void 0 ? void 0 : _serverManifest_loaderBundles[routeInfo.entryName || MAIN_ENTRY_NAME];
5
+ if (!serverLoaderModule) {
6
+ return;
7
+ }
8
+ const { routes, handleRequest } = serverLoaderModule;
9
+ const response = await handleRequest({
10
+ request,
11
+ serverRoutes,
12
+ context: {
13
+ logger,
14
+ reporter
15
+ },
16
+ routes
17
+ });
18
+ return response;
19
+ };
20
+ export {
21
+ dataHandler
22
+ };
@@ -0,0 +1,73 @@
1
+ import { checkIsProd, sortRoutes, getRuntimeEnv } from "../../utils";
2
+ import { initReporter } from "../monitor";
3
+ import { CustomServer } from "../customServer";
4
+ import { createRender } from "./render";
5
+ function createRenderHandler(render) {
6
+ return async (c, _) => {
7
+ var _c_env_node;
8
+ const logger = c.get("logger");
9
+ const reporter = c.get("reporter");
10
+ const templates = c.get("templates") || {};
11
+ const serverManifest = c.get("serverManifest") || {};
12
+ const locals = c.get("locals");
13
+ const metrics = c.get("metrics");
14
+ const request = c.req.raw;
15
+ const nodeReq = (_c_env_node = c.env.node) === null || _c_env_node === void 0 ? void 0 : _c_env_node.req;
16
+ const res = await render(request, {
17
+ logger,
18
+ nodeReq,
19
+ reporter,
20
+ templates,
21
+ metrics,
22
+ serverManifest,
23
+ locals
24
+ });
25
+ return res;
26
+ };
27
+ }
28
+ async function getRenderHandler(options) {
29
+ const { routes, pwd, config } = options;
30
+ if (routes && routes.length > 0) {
31
+ var _config_server, _options_config_security;
32
+ const ssrConfig = (_config_server = config.server) === null || _config_server === void 0 ? void 0 : _config_server.ssr;
33
+ const forceCSR = typeof ssrConfig === "object" ? ssrConfig.forceCSR : false;
34
+ const render = createRender({
35
+ routes,
36
+ pwd,
37
+ staticGenerate: options.staticGenerate,
38
+ metaName: options.metaName || "modern-js",
39
+ forceCSR,
40
+ nonce: (_options_config_security = options.config.security) === null || _options_config_security === void 0 ? void 0 : _options_config_security.nonce
41
+ });
42
+ return render;
43
+ }
44
+ return null;
45
+ }
46
+ async function bindRenderHandler(server, options) {
47
+ const { routes, pwd, disableCustomHook } = options;
48
+ const { runner } = server;
49
+ if (routes && routes.length > 0) {
50
+ const customServer = new CustomServer(runner, server, pwd);
51
+ if (getRuntimeEnv() === "node") {
52
+ const cacheModuleName = "./ssrCache";
53
+ const { ssrCache } = await import(cacheModuleName);
54
+ await ssrCache.loadCacheMod(checkIsProd() ? pwd : void 0);
55
+ }
56
+ const pageRoutes = routes.filter((route) => !route.isApi).sort(sortRoutes);
57
+ const render = await getRenderHandler(options);
58
+ for (const route of pageRoutes) {
59
+ const { urlPath: originUrlPath, entryName } = route;
60
+ const urlPath = originUrlPath.endsWith("/") ? `${originUrlPath}*` : `${originUrlPath}/*`;
61
+ const customServerHookMiddleware = customServer.getHookMiddleware(entryName || "main", routes);
62
+ server.use(urlPath, initReporter(entryName));
63
+ !disableCustomHook && server.use(urlPath, customServerHookMiddleware);
64
+ const customServerMiddleware = customServer.getServerMiddleware();
65
+ server.use(urlPath, customServerMiddleware);
66
+ render && server.all(urlPath, createRenderHandler(render));
67
+ }
68
+ }
69
+ }
70
+ export {
71
+ bindRenderHandler,
72
+ getRenderHandler
73
+ };
@@ -0,0 +1,108 @@
1
+ import { cutNameByHyphen } from "@modern-js/utils/universal";
2
+ import { REPLACE_REG } from "../../../base/constants";
3
+ import { createErrorHtml, sortRoutes, parseQuery, transformResponse, getPathname } from "../../utils";
4
+ import { dataHandler } from "./dataHandler";
5
+ import { ssrRender } from "./ssrRender";
6
+ async function createRender({ routes, pwd, metaName, staticGenerate, forceCSR, nonce }) {
7
+ return async (req, { logger, nodeReq, reporter, templates, serverManifest, locals, metrics }) => {
8
+ const routeInfo = matchRoute(req, routes);
9
+ if (!routeInfo) {
10
+ return new Response(createErrorHtml(404), {
11
+ status: 404,
12
+ headers: {
13
+ "content-type": "text/html; charset=UTF-8"
14
+ }
15
+ });
16
+ }
17
+ const html = templates[routeInfo.entryName];
18
+ if (!html) {
19
+ return new Response(createErrorHtml(404), {
20
+ status: 404,
21
+ headers: {
22
+ "content-type": "text/html; charset=UTF-8"
23
+ }
24
+ });
25
+ }
26
+ const renderMode = getRenderMode(req, metaName || "modern-js", routeInfo.isSSR, forceCSR, nodeReq);
27
+ const renderOptions = {
28
+ pwd,
29
+ html,
30
+ routeInfo,
31
+ staticGenerate: staticGenerate || false,
32
+ metaName: metaName || "modern-js",
33
+ nonce,
34
+ logger,
35
+ nodeReq,
36
+ reporter,
37
+ serverRoutes: routes,
38
+ locals,
39
+ serverManifest,
40
+ metrics
41
+ };
42
+ switch (renderMode) {
43
+ case "data":
44
+ let response = await dataHandler(req, renderOptions);
45
+ if (!response) {
46
+ response = await renderHandler(req, renderOptions, "ssr");
47
+ }
48
+ return response;
49
+ case "ssr":
50
+ case "csr":
51
+ return renderHandler(req, renderOptions, renderMode);
52
+ default:
53
+ throw new Error(`Unknown render mode: ${renderMode}`);
54
+ }
55
+ };
56
+ }
57
+ async function renderHandler(request, options, mode) {
58
+ const serverData = {
59
+ router: {
60
+ baseUrl: options.routeInfo.urlPath,
61
+ params: {}
62
+ }
63
+ };
64
+ const response = await (mode === "ssr" ? ssrRender(request, options) : csrRender(options.html));
65
+ return transformResponse(response, injectServerData(serverData));
66
+ }
67
+ function matchRoute(req, routes) {
68
+ const sorted = routes.sort(sortRoutes);
69
+ for (const route of sorted) {
70
+ const pathname = getPathname(req);
71
+ if (pathname.startsWith(route.urlPath)) {
72
+ return route;
73
+ }
74
+ }
75
+ return void 0;
76
+ }
77
+ function getRenderMode(req, framework, isSSR, forceCSR, nodeReq) {
78
+ const query = parseQuery(req);
79
+ const fallbackHeader = `x-${cutNameByHyphen(framework)}-ssr-fallback`;
80
+ if (isSSR) {
81
+ if (query.__loader) {
82
+ return "data";
83
+ }
84
+ if (forceCSR && (query.csr || req.headers.get(fallbackHeader) || (nodeReq === null || nodeReq === void 0 ? void 0 : nodeReq.headers[fallbackHeader]))) {
85
+ return "csr";
86
+ }
87
+ return "ssr";
88
+ } else {
89
+ return "csr";
90
+ }
91
+ }
92
+ function csrRender(html) {
93
+ return new Response(html, {
94
+ status: 200,
95
+ headers: new Headers({
96
+ "content-type": "text/html; charset=UTF-8"
97
+ })
98
+ });
99
+ }
100
+ function injectServerData(serverData) {
101
+ const { head } = REPLACE_REG.before;
102
+ const searchValue = new RegExp(head);
103
+ const replcaeCb = (beforeHead) => `${beforeHead}<script type="application/json" id="__MODERN_SERVER_DATA__">${JSON.stringify(serverData)}</script>`;
104
+ return (template) => template.replace(searchValue, replcaeCb);
105
+ }
106
+ export {
107
+ createRender
108
+ };
@@ -0,0 +1,16 @@
1
+ const SERVER_TIMING = "Server-Timing";
2
+ class ServerTiming {
3
+ addServeTiming(name, dur, desc) {
4
+ const _name = `bd-${this.meta}-${name}`;
5
+ const value = `${_name};${desc ? `decs="${desc}";` : ""} dur=${dur}`;
6
+ this.headers.append(SERVER_TIMING, value);
7
+ return this;
8
+ }
9
+ constructor(headers, meta) {
10
+ this.meta = meta;
11
+ this.headers = headers;
12
+ }
13
+ }
14
+ export {
15
+ ServerTiming
16
+ };
@@ -0,0 +1,162 @@
1
+ import { Readable } from "stream";
2
+ import { SERVER_DIR, requireExistModule } from "@modern-js/utils";
3
+ import { createMemoryStorage } from "@modern-js/runtime-utils/storer";
4
+ import { createReadableStreamFromReadable } from "../../adapters/node/polyfills/stream";
5
+ import { createTransformStream, getPathname } from "../../utils";
6
+ class CacheManager {
7
+ async getCacheResult(req, cacheControl, render, ssrContext) {
8
+ const key = this.computedKey(req, cacheControl);
9
+ const value = await this.container.get(key);
10
+ const { maxAge, staleWhileRevalidate } = cacheControl;
11
+ const ttl = maxAge + staleWhileRevalidate;
12
+ if (value) {
13
+ const cache = JSON.parse(value);
14
+ const interval = Date.now() - cache.cursor;
15
+ if (interval <= maxAge) {
16
+ return {
17
+ data: cache.val,
18
+ status: "hit"
19
+ };
20
+ } else if (interval <= staleWhileRevalidate + maxAge) {
21
+ this.processCache(key, render, ssrContext, ttl);
22
+ return {
23
+ data: cache.val,
24
+ status: "stale"
25
+ };
26
+ } else {
27
+ return this.processCache(key, render, ssrContext, ttl, "expired");
28
+ }
29
+ } else {
30
+ return this.processCache(key, render, ssrContext, ttl, "miss");
31
+ }
32
+ }
33
+ async processCache(key, render, ssrContext, ttl, status) {
34
+ const renderResult = await render(ssrContext);
35
+ if (!renderResult) {
36
+ return {
37
+ data: ""
38
+ };
39
+ } else if (typeof renderResult === "string") {
40
+ const current = Date.now();
41
+ const cache = {
42
+ val: renderResult,
43
+ cursor: current
44
+ };
45
+ await this.container.set(key, JSON.stringify(cache), {
46
+ ttl
47
+ });
48
+ return {
49
+ data: renderResult,
50
+ status
51
+ };
52
+ } else {
53
+ const body = (
54
+ // TODO: remove node:stream, move it to ssr entry.
55
+ renderResult instanceof Readable ? createReadableStreamFromReadable(renderResult) : renderResult
56
+ );
57
+ let html = "";
58
+ const stream = createTransformStream((chunk) => {
59
+ html += chunk;
60
+ return chunk;
61
+ });
62
+ stream.readable.getReader().closed.then(() => {
63
+ const current = Date.now();
64
+ const cache = {
65
+ val: html,
66
+ cursor: current
67
+ };
68
+ this.container.set(key, JSON.stringify(cache), {
69
+ ttl
70
+ });
71
+ });
72
+ body.pipeThrough(stream);
73
+ return {
74
+ data: stream.readable,
75
+ status
76
+ };
77
+ }
78
+ }
79
+ computedKey(req, cacheControl) {
80
+ const pathname = getPathname(req);
81
+ const { customKey } = cacheControl;
82
+ const defaultKey = pathname.replace(/.+\/+$/, "");
83
+ if (customKey) {
84
+ if (typeof customKey === "string") {
85
+ return customKey;
86
+ } else {
87
+ return customKey(defaultKey);
88
+ }
89
+ } else {
90
+ return defaultKey;
91
+ }
92
+ }
93
+ constructor(container) {
94
+ this.container = container;
95
+ }
96
+ }
97
+ const CACHE_FILENAME = "cache";
98
+ class ServerCache {
99
+ async loadCacheMod(pwd = process.cwd()) {
100
+ const path = await import("path").catch(() => {
101
+ return {};
102
+ });
103
+ const serverCacheFilepath = path.resolve(pwd, SERVER_DIR, CACHE_FILENAME);
104
+ const mod = requireExistModule(serverCacheFilepath, {
105
+ interop: false
106
+ });
107
+ this.cacheOption = mod === null || mod === void 0 ? void 0 : mod.cacheOption;
108
+ if (this.cacheOption && !(mod === null || mod === void 0 ? void 0 : mod.customContainer)) {
109
+ const cacheStorage = createMemoryStorage("__ssr__cache");
110
+ this.customContainer = cacheStorage;
111
+ } else {
112
+ this.customContainer = mod === null || mod === void 0 ? void 0 : mod.customContainer;
113
+ }
114
+ if (this.customContainer) {
115
+ this.cacheManger = new CacheManager(this.customContainer);
116
+ }
117
+ }
118
+ matchCacheControl(req) {
119
+ const { cacheOption } = this;
120
+ if (!cacheOption || !req) {
121
+ return void 0;
122
+ } else if (isCacheControl(cacheOption)) {
123
+ return cacheOption;
124
+ } else if (isCacheOptionProvider(cacheOption)) {
125
+ return cacheOption(req);
126
+ } else {
127
+ const url = req.url;
128
+ const options = Object.entries(cacheOption);
129
+ for (const [key, option] of options) {
130
+ if (key === "*" || new RegExp(key).test(url)) {
131
+ if (typeof option === "function") {
132
+ return option(req);
133
+ } else {
134
+ return option;
135
+ }
136
+ }
137
+ }
138
+ return void 0;
139
+ }
140
+ function isCacheOptionProvider(option) {
141
+ return typeof option === "function";
142
+ }
143
+ function isCacheControl(option) {
144
+ return typeof option === "object" && option !== null && "maxAge" in option;
145
+ }
146
+ }
147
+ async getCache(req, cacheControl, render, ssrContext) {
148
+ if (this.cacheManger) {
149
+ return this.cacheManger.getCacheResult(req, cacheControl, render, ssrContext);
150
+ } else {
151
+ const renderResult = await render(ssrContext);
152
+ return {
153
+ data: renderResult
154
+ };
155
+ }
156
+ }
157
+ }
158
+ const ssrCache = new ServerCache();
159
+ export {
160
+ CacheManager,
161
+ ssrCache
162
+ };
@@ -0,0 +1,177 @@
1
+ import { SERVER_RENDER_FUNCTION_NAME, MAIN_ENTRY_NAME } from "@modern-js/utils/universal/constants";
2
+ import * as isbot from "isbot";
3
+ import { getRuntimeEnv, parseHeaders, parseQuery, getHost, getPathname } from "../../utils";
4
+ import { X_RENDER_CACHE } from "../../constants";
5
+ import { ServerTiming } from "./serverTiming";
6
+ const defaultReporter = {
7
+ init() {
8
+ },
9
+ reportError() {
10
+ },
11
+ reportTiming() {
12
+ },
13
+ reportInfo() {
14
+ },
15
+ reportWarn() {
16
+ }
17
+ };
18
+ async function ssrRender(request, { routeInfo, html, staticGenerate, nonce, metaName, reporter, logger, nodeReq, serverManifest, locals, metrics }) {
19
+ var _serverManifest_renderBundles;
20
+ const { entryName } = routeInfo;
21
+ const loadableStats = serverManifest.loadableStats || {};
22
+ const routeManifest = serverManifest.routeManifest || {};
23
+ const host = getHost(request);
24
+ const isSpider = isbot.default(request.headers.get("user-agent"));
25
+ const responseProxy = new ResponseProxy();
26
+ const query = parseQuery(request);
27
+ const headers = parseHeaders(request);
28
+ if (nodeReq) {
29
+ for (const key in nodeReq.headers) {
30
+ if (!headers[key]) {
31
+ headers[key] = nodeReq.headers[key];
32
+ }
33
+ }
34
+ }
35
+ const ssrContext = {
36
+ request: {
37
+ baseUrl: routeInfo.urlPath,
38
+ params: {},
39
+ pathname: nodeReq ? getPathnameFromNodeReq(nodeReq) : getPathname(request),
40
+ host,
41
+ query,
42
+ url: nodeReq ? getHrefFromNodeReq(nodeReq) : request.url,
43
+ headers
44
+ },
45
+ response: {
46
+ setHeader(key, value) {
47
+ responseProxy.headers.set(key, value);
48
+ },
49
+ status(code) {
50
+ responseProxy.status = code;
51
+ },
52
+ locals: locals || {}
53
+ },
54
+ redirection: {},
55
+ template: html,
56
+ loadableStats,
57
+ routeManifest,
58
+ entryName,
59
+ staticGenerate,
60
+ logger,
61
+ metrics,
62
+ serverTiming: new ServerTiming(responseProxy.headers, metaName),
63
+ reporter: reporter || defaultReporter,
64
+ /** @deprecated node req */
65
+ req: nodeReq || request,
66
+ /** @deprecated node res */
67
+ res: void 0,
68
+ isSpider,
69
+ nonce
70
+ };
71
+ const renderBundle = (_serverManifest_renderBundles = serverManifest.renderBundles) === null || _serverManifest_renderBundles === void 0 ? void 0 : _serverManifest_renderBundles[entryName || MAIN_ENTRY_NAME];
72
+ if (!renderBundle) {
73
+ throw new Error(`Can't found renderBundle ${entryName || MAIN_ENTRY_NAME}`);
74
+ }
75
+ const runtimeEnv = getRuntimeEnv();
76
+ let ssrResult;
77
+ let cacheStatus;
78
+ const render = renderBundle[SERVER_RENDER_FUNCTION_NAME];
79
+ if (runtimeEnv === "node") {
80
+ const cacheModuleName = "./ssrCache";
81
+ const { ssrCache } = await import(cacheModuleName);
82
+ const incomingMessage = nodeReq ? nodeReq : new IncomingMessgeProxy(request);
83
+ const cacheControl = await ssrCache.matchCacheControl(incomingMessage);
84
+ if (cacheControl) {
85
+ const { data: data2, status } = await ssrCache.getCache(request, cacheControl, render, ssrContext);
86
+ ssrResult = data2;
87
+ cacheStatus = status;
88
+ } else {
89
+ ssrResult = await render(ssrContext);
90
+ }
91
+ } else {
92
+ ssrResult = await render(ssrContext);
93
+ }
94
+ const { redirection } = ssrContext;
95
+ if (cacheStatus) {
96
+ responseProxy.headers.set(X_RENDER_CACHE, cacheStatus);
97
+ }
98
+ if (redirection.url) {
99
+ const { headers: headers2 } = responseProxy;
100
+ headers2.set("Location", redirection.url);
101
+ return new Response(null, {
102
+ status: redirection.status || 302,
103
+ headers: {
104
+ Location: redirection.url
105
+ }
106
+ });
107
+ }
108
+ const { Readable } = await import("stream").catch((_) => ({
109
+ Readable: void 0
110
+ }));
111
+ const streamModule = "../../adapters/node/polyfills/stream";
112
+ const { createReadableStreamFromReadable } = runtimeEnv === "node" ? await import(streamModule).catch((_) => ({
113
+ createReadableStreamFromReadable: void 0
114
+ })) : {
115
+ createReadableStreamFromReadable: void 0
116
+ };
117
+ const data = Readable && ssrResult instanceof Readable ? (createReadableStreamFromReadable === null || createReadableStreamFromReadable === void 0 ? void 0 : createReadableStreamFromReadable(ssrResult)) || "" : ssrResult;
118
+ if (typeof data !== "string") {
119
+ responseProxy.headers.set("transfer-encoding", "chunked");
120
+ }
121
+ return new Response(data, {
122
+ status: responseProxy.status,
123
+ headers: responseProxy.headers
124
+ });
125
+ }
126
+ class ResponseProxy {
127
+ constructor() {
128
+ this.headers = new Headers();
129
+ this.status = 200;
130
+ this.headers.set("content-type", "text/html; charset=UTF-8");
131
+ }
132
+ }
133
+ class IncomingMessgeProxy {
134
+ constructor(req) {
135
+ this.headers = {};
136
+ req.headers.forEach((value, key) => {
137
+ this.headers[key] = value;
138
+ });
139
+ this.method = req.method;
140
+ this.url = getPathname(req);
141
+ }
142
+ }
143
+ function getHrefFromNodeReq(nodeReq) {
144
+ function getProtocal() {
145
+ if (nodeReq.socket.encrypted) {
146
+ return "https";
147
+ }
148
+ const proto = nodeReq.headers["x-forwarded-proto"];
149
+ return proto ? proto.split(/\s*,\s*/, 1)[0] : "http";
150
+ }
151
+ function getHost2() {
152
+ let host = nodeReq.headers["x-forwarded-host"];
153
+ if (!host) {
154
+ host = nodeReq.headers.host;
155
+ }
156
+ host = host.split(/\s*,\s*/, 1)[0] || "undefined";
157
+ return host;
158
+ }
159
+ const href = `${getProtocal()}://${getHost2()}${nodeReq.url || ""}`;
160
+ return href;
161
+ }
162
+ function getPathnameFromNodeReq(nodeReq) {
163
+ const { url } = nodeReq;
164
+ if (!url) {
165
+ return "/";
166
+ }
167
+ const match = url.match(/\/[^?]*/);
168
+ let pathname = match ? match[0] : "/";
169
+ if (pathname !== "/" && pathname.endsWith("/")) {
170
+ pathname = pathname.slice(0, -1);
171
+ }
172
+ return pathname;
173
+ }
174
+ export {
175
+ getPathnameFromNodeReq,
176
+ ssrRender
177
+ };