@modern-js/server-core 2.54.5 → 2.55.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 (39) hide show
  1. package/dist/cjs/index.js +3 -1
  2. package/dist/cjs/plugins/render/dataHandler.js +3 -2
  3. package/dist/cjs/plugins/render/index.js +1 -1
  4. package/dist/cjs/plugins/render/render.js +37 -13
  5. package/dist/cjs/plugins/render/serverTiming.js +6 -4
  6. package/dist/cjs/plugins/render/ssrCache.js +72 -83
  7. package/dist/cjs/plugins/render/ssrRender.js +40 -145
  8. package/dist/cjs/types/requestHandler.js +16 -0
  9. package/dist/cjs/utils/transformStream.js +1 -1
  10. package/dist/esm/index.js +1 -0
  11. package/dist/esm/plugins/render/dataHandler.js +4 -3
  12. package/dist/esm/plugins/render/index.js +1 -1
  13. package/dist/esm/plugins/render/render.js +56 -22
  14. package/dist/esm/plugins/render/serverTiming.js +12 -4
  15. package/dist/esm/plugins/render/ssrCache.js +101 -131
  16. package/dist/esm/plugins/render/ssrRender.js +55 -175
  17. package/dist/esm/types/requestHandler.js +0 -0
  18. package/dist/esm/utils/transformStream.js +16 -2
  19. package/dist/esm-node/index.js +1 -0
  20. package/dist/esm-node/plugins/render/dataHandler.js +3 -2
  21. package/dist/esm-node/plugins/render/index.js +1 -1
  22. package/dist/esm-node/plugins/render/render.js +38 -14
  23. package/dist/esm-node/plugins/render/serverTiming.js +6 -4
  24. package/dist/esm-node/plugins/render/ssrCache.js +73 -74
  25. package/dist/esm-node/plugins/render/ssrRender.js +43 -137
  26. package/dist/esm-node/types/requestHandler.js +0 -0
  27. package/dist/esm-node/utils/transformStream.js +1 -1
  28. package/dist/types/index.d.ts +1 -0
  29. package/dist/types/plugins/render/dataHandler.d.ts +1 -1
  30. package/dist/types/plugins/render/render.d.ts +3 -2
  31. package/dist/types/plugins/render/serverTiming.d.ts +3 -2
  32. package/dist/types/plugins/render/ssrCache.d.ts +7 -11
  33. package/dist/types/plugins/render/ssrRender.d.ts +10 -10
  34. package/dist/types/types/config/html.d.ts +11 -0
  35. package/dist/types/types/config/output.d.ts +8 -0
  36. package/dist/types/types/requestHandler.d.ts +43 -0
  37. package/dist/types/types/server.d.ts +7 -2
  38. package/dist/types/utils/transformStream.d.ts +1 -1
  39. package/package.json +7 -8
@@ -1,42 +1,24 @@
1
1
  import { _ as _async_to_generator } from "@swc/helpers/_/_async_to_generator";
2
2
  import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
3
- import { _ as _instanceof } from "@swc/helpers/_/_instanceof";
4
3
  import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
5
- import { SERVER_RENDER_FUNCTION_NAME, MAIN_ENTRY_NAME } from "@modern-js/utils/universal/constants";
6
- import * as isbot from "isbot";
7
- import { getRuntimeEnv, parseHeaders, parseQuery, getHost, getPathname } from "../../utils";
8
- import { X_MODERNJS_RENDER, X_RENDER_CACHE } from "../../constants";
9
- import { ServerTiming } from "./serverTiming";
4
+ import { MAIN_ENTRY_NAME } from "@modern-js/utils/universal/constants";
5
+ import { parseHeaders, getPathname } from "../../utils";
6
+ import { X_MODERNJS_RENDER } from "../../constants";
10
7
  import { matchCacheControl, getCacheResult } from "./ssrCache";
11
- var defaultReporter = {
12
- init: function init() {
13
- },
14
- reportError: function reportError() {
15
- },
16
- reportTiming: function reportTiming() {
17
- },
18
- reportInfo: function reportInfo() {
19
- },
20
- reportWarn: function reportWarn() {
21
- }
22
- };
8
+ var SERVER_RUNTIME_ENTRY = "requestHandler";
23
9
  function ssrRender(request, _) {
24
10
  return _ssrRender.apply(this, arguments);
25
11
  }
26
12
  function _ssrRender() {
27
13
  _ssrRender = _async_to_generator(function(request, param) {
28
- var routeInfo, html, staticGenerate, nonce, metaName, reporter, logger, nodeReq, serverManifest, locals, params, metrics, loaderContext, cacheConfig, _serverManifest_renderBundles, entryName, loadableStats, routeManifest, host, isSpider, responseProxy, query, headers, key, ssrContext, renderBundle, runtimeEnv, ssrResult, cacheStatus, render, cacheControl, _ref, data, status, redirection, headers1, Readable, streamModule, createReadableStreamFromReadable, _tmp, data1;
14
+ var routeInfo, html, userConfig, staticGenerate, nodeReq, serverManifest, locals, params, loaderContext, reporter, cacheConfig, logger, metrics, onError, onTiming, _serverManifest_renderBundles, entryName, loadableStats, routeManifest, headers, key, renderBundle, requestHandler, config, requestHandlerOptions, cacheControl, response;
29
15
  return _ts_generator(this, function(_state) {
30
16
  switch (_state.label) {
31
17
  case 0:
32
- routeInfo = param.routeInfo, html = param.html, staticGenerate = param.staticGenerate, nonce = param.nonce, metaName = param.metaName, reporter = param.reporter, logger = param.logger, nodeReq = param.nodeReq, serverManifest = param.serverManifest, locals = param.locals, params = param.params, metrics = param.metrics, loaderContext = param.loaderContext, cacheConfig = param.cacheConfig;
18
+ routeInfo = param.routeInfo, html = param.html, userConfig = param.config, staticGenerate = param.staticGenerate, nodeReq = param.nodeReq, serverManifest = param.serverManifest, locals = param.locals, params = param.params, loaderContext = param.loaderContext, reporter = param.reporter, cacheConfig = param.cacheConfig, logger = param.logger, metrics = param.metrics, onError = param.onError, onTiming = param.onTiming;
33
19
  entryName = routeInfo.entryName;
34
20
  loadableStats = serverManifest.loadableStats || {};
35
21
  routeManifest = serverManifest.routeManifest || {};
36
- host = getHost(request);
37
- isSpider = isbot.default(request.headers.get("user-agent"));
38
- responseProxy = new ResponseProxy();
39
- query = parseQuery(request);
40
22
  headers = parseHeaders(request);
41
23
  if (nodeReq) {
42
24
  for (var key2 in nodeReq.headers) {
@@ -45,164 +27,82 @@ function _ssrRender() {
45
27
  }
46
28
  }
47
29
  }
48
- ssrContext = {
49
- request: {
50
- baseUrl: routeInfo.urlPath,
51
- params,
52
- pathname: nodeReq ? getPathnameFromNodeReq(nodeReq) : getPathname(request),
53
- host,
54
- query,
55
- url: nodeReq ? getHrefFromNodeReq(nodeReq) : request.url,
56
- headers
57
- },
58
- response: {
59
- setHeader: function setHeader(key3, value) {
60
- responseProxy.headers.set(key3, value);
61
- },
62
- status: function status2(code) {
63
- responseProxy.status = code;
64
- },
65
- locals: locals || {}
30
+ renderBundle = (_serverManifest_renderBundles = serverManifest.renderBundles) === null || _serverManifest_renderBundles === void 0 ? void 0 : _serverManifest_renderBundles[entryName || MAIN_ENTRY_NAME];
31
+ if (!renderBundle) {
32
+ throw new Error("Can't found renderBundle ".concat(entryName || MAIN_ENTRY_NAME));
33
+ }
34
+ return [
35
+ 4,
36
+ renderBundle[SERVER_RUNTIME_ENTRY]
37
+ ];
38
+ case 1:
39
+ requestHandler = _state.sent();
40
+ config = createRequestHandlerConfig(userConfig);
41
+ requestHandlerOptions = {
42
+ resource: {
43
+ route: routeInfo,
44
+ loadableStats,
45
+ routeManifest,
46
+ htmlTemplate: html,
47
+ entryName: entryName || MAIN_ENTRY_NAME
66
48
  },
67
- redirection: {},
68
- template: html,
69
- loadableStats,
49
+ params,
70
50
  loaderContext,
71
- routeManifest,
72
- entryName,
51
+ config,
52
+ locals,
53
+ reporter,
73
54
  staticGenerate,
74
55
  logger,
75
56
  metrics,
76
- serverTiming: new ServerTiming(responseProxy.headers, metaName),
77
- reporter: reporter || defaultReporter,
78
- /** @deprecated node req */
79
- req: nodeReq || request,
80
- /** @deprecated node res */
81
- res: void 0,
82
- isSpider,
83
- nonce
57
+ onError,
58
+ onTiming
84
59
  };
85
- renderBundle = (_serverManifest_renderBundles = serverManifest.renderBundles) === null || _serverManifest_renderBundles === void 0 ? void 0 : _serverManifest_renderBundles[entryName || MAIN_ENTRY_NAME];
86
- if (!renderBundle) {
87
- throw new Error("Can't found renderBundle ".concat(entryName || MAIN_ENTRY_NAME));
88
- }
89
- runtimeEnv = getRuntimeEnv();
90
- render = renderBundle[SERVER_RENDER_FUNCTION_NAME];
91
60
  return [
92
61
  4,
93
62
  matchCacheControl(cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.strategy, nodeReq || new IncomingMessgeProxy(request))
94
63
  ];
95
- case 1:
64
+ case 2:
96
65
  cacheControl = _state.sent();
97
66
  if (!cacheControl)
98
67
  return [
99
68
  3,
100
- 3
69
+ 4
101
70
  ];
102
71
  return [
103
72
  4,
104
73
  getCacheResult(request, {
105
74
  cacheControl,
106
75
  container: cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.container,
107
- render,
108
- ssrContext
76
+ requestHandler,
77
+ requestHandlerOptions
109
78
  })
110
79
  ];
111
- case 2:
112
- _ref = _state.sent(), data = _ref.data, status = _ref.status;
113
- ssrResult = data;
114
- cacheStatus = status;
115
- return [
116
- 3,
117
- 5
118
- ];
119
80
  case 3:
81
+ response = _state.sent();
120
82
  return [
121
- 4,
122
- render(ssrContext)
83
+ 3,
84
+ 6
123
85
  ];
124
86
  case 4:
125
- ssrResult = _state.sent();
126
- _state.label = 5;
127
- case 5:
128
- redirection = ssrContext.redirection;
129
- if (cacheStatus) {
130
- responseProxy.headers.set(X_RENDER_CACHE, cacheStatus);
131
- }
132
- responseProxy.headers.set(X_MODERNJS_RENDER, "server");
133
- if (redirection.url) {
134
- headers1 = responseProxy.headers;
135
- headers1.set("Location", redirection.url);
136
- return [
137
- 2,
138
- new Response(null, {
139
- status: redirection.status || 302,
140
- headers: {
141
- Location: redirection.url
142
- }
143
- })
144
- ];
145
- }
146
87
  return [
147
88
  4,
148
- import("stream").catch(function(_) {
149
- return {
150
- Readable: void 0
151
- };
152
- })
89
+ requestHandler(request, requestHandlerOptions)
153
90
  ];
91
+ case 5:
92
+ response = _state.sent();
93
+ _state.label = 6;
154
94
  case 6:
155
- Readable = _state.sent().Readable;
156
- streamModule = "../../adapters/node/polyfills/stream";
157
- if (!(runtimeEnv === "node"))
158
- return [
159
- 3,
160
- 8
161
- ];
162
- return [
163
- 4,
164
- import(streamModule).catch(function(_) {
165
- return {
166
- createReadableStreamFromReadable: void 0
167
- };
168
- })
169
- ];
170
- case 7:
171
- _tmp = _state.sent();
172
- return [
173
- 3,
174
- 9
175
- ];
176
- case 8:
177
- _tmp = {
178
- createReadableStreamFromReadable: void 0
179
- };
180
- _state.label = 9;
181
- case 9:
182
- createReadableStreamFromReadable = _tmp.createReadableStreamFromReadable;
183
- data1 = Readable && _instanceof(ssrResult, Readable) ? (createReadableStreamFromReadable === null || createReadableStreamFromReadable === void 0 ? void 0 : createReadableStreamFromReadable(ssrResult)) || "" : ssrResult;
184
- if (typeof data1 !== "string") {
185
- responseProxy.headers.set("transfer-encoding", "chunked");
186
- }
95
+ response.headers.set(X_MODERNJS_RENDER, "server");
96
+ response.headers.set("content-type", "text/html; charset=UTF-8");
187
97
  return [
188
98
  2,
189
- new Response(data1, {
190
- status: responseProxy.status,
191
- headers: responseProxy.headers
192
- })
99
+ response
193
100
  ];
194
101
  }
195
102
  });
196
103
  });
197
104
  return _ssrRender.apply(this, arguments);
198
105
  }
199
- var ResponseProxy = function ResponseProxy2() {
200
- "use strict";
201
- _class_call_check(this, ResponseProxy2);
202
- this.headers = new Headers();
203
- this.status = 200;
204
- this.headers.set("content-type", "text/html; charset=UTF-8");
205
- };
206
106
  var IncomingMessgeProxy = function IncomingMessgeProxy2(req) {
207
107
  "use strict";
208
108
  var _this = this;
@@ -214,38 +114,18 @@ var IncomingMessgeProxy = function IncomingMessgeProxy2(req) {
214
114
  this.method = req.method;
215
115
  this.url = getPathname(req);
216
116
  };
217
- function getHrefFromNodeReq(nodeReq) {
218
- function getProtocal() {
219
- if (nodeReq.socket.encrypted) {
220
- return "https";
221
- }
222
- var proto = nodeReq.headers["x-forwarded-proto"];
223
- return proto ? proto.split(/\s*,\s*/, 1)[0] : "http";
224
- }
225
- function getHost2() {
226
- var host = nodeReq.headers["x-forwarded-host"];
227
- if (!host) {
228
- host = nodeReq.headers.host;
229
- }
230
- host = host.split(/\s*,\s*/, 1)[0] || "undefined";
231
- return host;
232
- }
233
- var href = "".concat(getProtocal(), "://").concat(getHost2()).concat(nodeReq.url || "");
234
- return href;
235
- }
236
- function getPathnameFromNodeReq(nodeReq) {
237
- var url = nodeReq.url;
238
- if (!url) {
239
- return "/";
240
- }
241
- var match = url.match(/\/[^?]*/);
242
- var pathname = match ? match[0] : "/";
243
- if (pathname !== "/" && pathname.endsWith("/")) {
244
- pathname = pathname.slice(0, -1);
245
- }
246
- return pathname;
117
+ function createRequestHandlerConfig(userConfig) {
118
+ var output = userConfig.output, server = userConfig.server, security = userConfig.security, html = userConfig.html;
119
+ return {
120
+ ssr: server === null || server === void 0 ? void 0 : server.ssr,
121
+ ssrByEntries: server === null || server === void 0 ? void 0 : server.ssrByEntries,
122
+ nonce: security === null || security === void 0 ? void 0 : security.nonce,
123
+ enableInlineScripts: output === null || output === void 0 ? void 0 : output.enableInlineScripts,
124
+ enableInlineStyles: output === null || output === void 0 ? void 0 : output.enableInlineStyles,
125
+ crossorigin: html === null || html === void 0 ? void 0 : html.crossorigin,
126
+ scriptLoading: html === null || html === void 0 ? void 0 : html.scriptLoading
127
+ };
247
128
  }
248
129
  export {
249
- getPathnameFromNodeReq,
250
130
  ssrRender
251
131
  };
File without changes
@@ -6,17 +6,31 @@ function createTransformStream(fn) {
6
6
  return new TransformStream({
7
7
  transform: function transform(chunk, controller) {
8
8
  return _async_to_generator(function() {
9
- var content, newContent;
9
+ var content, newContent, _tmp;
10
10
  return _ts_generator(this, function(_state) {
11
11
  switch (_state.label) {
12
12
  case 0:
13
13
  content = decoder.decode(chunk);
14
+ if (!fn)
15
+ return [
16
+ 3,
17
+ 2
18
+ ];
14
19
  return [
15
20
  4,
16
21
  fn(content)
17
22
  ];
18
23
  case 1:
19
- newContent = _state.sent();
24
+ _tmp = _state.sent();
25
+ return [
26
+ 3,
27
+ 3
28
+ ];
29
+ case 2:
30
+ _tmp = content;
31
+ _state.label = 3;
32
+ case 3:
33
+ newContent = _tmp;
20
34
  controller.enqueue(encoder.encode(newContent));
21
35
  return [
22
36
  2
@@ -7,6 +7,7 @@ export * from "./types/plugin";
7
7
  export * from "./types/render";
8
8
  export * from "@modern-js/plugin";
9
9
  export * from "./types/config";
10
+ export * from "./types/requestHandler";
10
11
  export {
11
12
  AGGRED_DIR,
12
13
  ErrorDigest,
@@ -1,5 +1,5 @@
1
1
  import { MAIN_ENTRY_NAME } from "@modern-js/utils/universal/constants";
2
- const dataHandler = async (request, { routeInfo, serverRoutes, reporter, logger, serverManifest }) => {
2
+ const dataHandler = async (request, { routeInfo, serverRoutes, reporter, onError, onTiming, serverManifest }) => {
3
3
  var _serverManifest_loaderBundles;
4
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
5
  if (!serverLoaderModule) {
@@ -10,9 +10,10 @@ const dataHandler = async (request, { routeInfo, serverRoutes, reporter, logger,
10
10
  request,
11
11
  serverRoutes,
12
12
  context: {
13
- logger,
14
13
  reporter
15
14
  },
15
+ onTiming,
16
+ onError,
16
17
  routes
17
18
  });
18
19
  return response;
@@ -96,7 +96,7 @@ async function getRenderHandler({ pwd, routes, config, cacheConfig, metaName, st
96
96
  const render = createRender({
97
97
  routes,
98
98
  pwd,
99
- // TODO: need static Genrate
99
+ config,
100
100
  staticGenerate,
101
101
  cacheConfig,
102
102
  forceCSR,
@@ -1,9 +1,10 @@
1
1
  import { cutNameByHyphen } from "@modern-js/utils/universal";
2
2
  import { TrieRouter } from "hono/router/trie-router";
3
- import { parseQuery, getPathname, createErrorHtml, sortRoutes, transformResponse, onError as onErrorFn, ErrorDigest } from "../../utils";
3
+ import { parseQuery, getPathname, createErrorHtml, sortRoutes, transformResponse, onError as onErrorFn, ErrorDigest, parseHeaders } from "../../utils";
4
4
  import { REPLACE_REG, X_MODERNJS_RENDER } from "../../constants";
5
5
  import { dataHandler } from "./dataHandler";
6
6
  import { ssrRender } from "./ssrRender";
7
+ import { ServerTiming } from "./serverTiming";
7
8
  const DYNAMIC_ROUTE_REG = /\/:./;
8
9
  function getRouter(routes) {
9
10
  const dynamicRoutes = [];
@@ -33,7 +34,16 @@ function matchRoute(router, request) {
33
34
  const result = matched[0][0];
34
35
  return result || [];
35
36
  }
36
- async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig, forceCSR, nonce, onFallback: onFallbackFn }) {
37
+ function getHeadersWithoutCookie(headers) {
38
+ const _headers = {
39
+ ...headers,
40
+ cookie: void 0
41
+ };
42
+ delete _headers.cookie;
43
+ return _headers;
44
+ }
45
+ const SERVER_TIMING = "Server-Timing";
46
+ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig, forceCSR, config, onFallback: onFallbackFn }) {
37
47
  const router = getRouter(routes);
38
48
  return async (req, { logger, nodeReq, reporter, templates, serverManifest, locals, metrics, loaderContext }) => {
39
49
  const [routeInfo, params] = matchRoute(router, req);
@@ -62,7 +72,17 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
62
72
  });
63
73
  }
64
74
  const renderMode = await getRenderMode(req, metaName || "modern-js", routeInfo.isSSR, forceCSR, nodeReq, onFallback);
65
- const onError = async (e) => {
75
+ const pathname = getPathname(req);
76
+ const headerData = parseHeaders(req);
77
+ const serverTimingInstance = new ServerTiming(metaName || "modern");
78
+ const onError = (e) => {
79
+ logger.error(`SSR Error - ${e instanceof Error ? e.name : e}, error = %s, req.url = %s, req.headers = %o`, e instanceof Error ? e.stack || e.message : e, pathname, getHeadersWithoutCookie(headerData));
80
+ };
81
+ const onTiming = (name, dur) => {
82
+ logger.debug(`SSR Debug - ${name}, cost = %s, req.url = %s`, dur, pathname);
83
+ serverTimingInstance.addServeTiming(name, dur);
84
+ };
85
+ const onBoundError = async (e) => {
66
86
  onErrorFn(ErrorDigest.ERENDER, e, logger, req);
67
87
  await (onFallback === null || onFallback === void 0 ? void 0 : onFallback("error", e));
68
88
  };
@@ -71,32 +91,36 @@ async function createRender({ routes, pwd, metaName, staticGenerate, cacheConfig
71
91
  html,
72
92
  routeInfo,
73
93
  staticGenerate: staticGenerate || false,
74
- metaName: metaName || "modern-js",
75
- nonce,
76
- logger,
94
+ config,
77
95
  nodeReq,
78
96
  cacheConfig,
79
97
  reporter,
80
98
  serverRoutes: routes,
81
99
  params,
100
+ logger,
101
+ metrics,
82
102
  locals,
83
103
  serverManifest,
84
- metrics,
85
- loaderContext: loaderContext || /* @__PURE__ */ new Map()
104
+ loaderContext: loaderContext || /* @__PURE__ */ new Map(),
105
+ onError,
106
+ onTiming
86
107
  };
108
+ let response;
87
109
  switch (renderMode) {
88
110
  case "data":
89
- let response = await dataHandler(req, renderOptions);
90
- if (!response) {
91
- response = await renderHandler(req, renderOptions, "ssr", onError);
92
- }
93
- return response;
111
+ response = await dataHandler(req, renderOptions) || await renderHandler(req, renderOptions, "ssr", onBoundError);
112
+ break;
94
113
  case "ssr":
95
114
  case "csr":
96
- return renderHandler(req, renderOptions, renderMode, onError);
115
+ response = await renderHandler(req, renderOptions, renderMode, onBoundError);
116
+ break;
97
117
  default:
98
118
  throw new Error(`Unknown render mode: ${renderMode}`);
99
119
  }
120
+ serverTimingInstance.headers.forEach((value) => {
121
+ response.headers.append(SERVER_TIMING, value);
122
+ });
123
+ return response;
100
124
  };
101
125
  }
102
126
  async function renderHandler(request, options, mode, onError) {
@@ -1,14 +1,16 @@
1
- const SERVER_TIMING = "Server-Timing";
2
1
  class ServerTiming {
2
+ get headers() {
3
+ return this.headerList;
4
+ }
3
5
  addServeTiming(name, dur, desc) {
4
6
  const _name = `bd-${this.meta}-${name}`;
5
7
  const value = `${_name};${desc ? `decs="${desc}";` : ""} dur=${dur}`;
6
- this.headers.append(SERVER_TIMING, value);
8
+ this.headerList.push(value);
7
9
  return this;
8
10
  }
9
- constructor(headers, meta) {
11
+ constructor(meta) {
12
+ this.headerList = [];
10
13
  this.meta = meta;
11
- this.headers = headers;
12
14
  }
13
15
  }
14
16
  export {
@@ -1,70 +1,40 @@
1
1
  import { createMemoryStorage } from "@modern-js/runtime-utils/storer";
2
- import { createTransformStream, getPathname, getRuntimeEnv } from "../../utils";
3
- async function processCache(key, render, ssrContext, ttl, container, status) {
4
- const renderResult = await render(ssrContext);
5
- if (!renderResult) {
6
- return {
7
- data: ""
8
- };
9
- } else if (typeof renderResult === "string") {
10
- const current = Date.now();
11
- const cache = {
12
- val: renderResult,
13
- cursor: current
14
- };
15
- await container.set(key, JSON.stringify(cache), {
16
- ttl
17
- });
18
- return {
19
- data: renderResult,
20
- status
21
- };
22
- } else {
23
- const { Readable } = await import("stream").catch((_) => ({
24
- Readable: void 0
25
- }));
26
- const runtimeEnv = getRuntimeEnv();
27
- const streamModule = "../../adapters/node/polyfills/stream";
28
- const { createReadableStreamFromReadable } = runtimeEnv === "node" ? await import(streamModule).catch((_) => ({
29
- createReadableStreamFromReadable: void 0
30
- })) : {
31
- createReadableStreamFromReadable: void 0
32
- };
33
- const body = (
34
- // TODO: remove node:stream, move it to ssr entry.
35
- Readable && renderResult instanceof Readable ? createReadableStreamFromReadable === null || createReadableStreamFromReadable === void 0 ? void 0 : createReadableStreamFromReadable(renderResult) : renderResult
36
- );
2
+ import { X_RENDER_CACHE } from "../../constants";
3
+ import { createTransformStream, getPathname } from "../../utils";
4
+ async function processCache({ request, key, requestHandler, requestHandlerOptions, ttl, container, cacheStatus }) {
5
+ const response = await requestHandler(request, requestHandlerOptions);
6
+ const decoder = new TextDecoder();
7
+ if (response.body) {
8
+ const stream = createTransformStream();
9
+ const reader = response.body.getReader();
10
+ const writer = stream.writable.getWriter();
37
11
  let html = "";
38
- const stream = createTransformStream((chunk) => {
39
- html += chunk;
40
- return chunk;
12
+ const push = () => reader.read().then(({ done, value }) => {
13
+ if (done) {
14
+ const current = Date.now();
15
+ const cache = {
16
+ val: html,
17
+ cursor: current
18
+ };
19
+ container.set(key, JSON.stringify(cache), {
20
+ ttl
21
+ });
22
+ writer.close();
23
+ return;
24
+ }
25
+ const content = decoder.decode(value);
26
+ html += content;
27
+ writer.write(value);
28
+ push();
41
29
  });
42
- const reader = body.getReader();
43
- const writer = stream.writable.getWriter();
44
- const push = () => {
45
- reader.read().then(({ done, value }) => {
46
- if (done) {
47
- const current = Date.now();
48
- const cache = {
49
- val: html,
50
- cursor: current
51
- };
52
- container.set(key, JSON.stringify(cache), {
53
- ttl
54
- });
55
- writer.close();
56
- return;
57
- }
58
- writer.write(value);
59
- push();
60
- });
61
- };
62
30
  push();
63
- return {
64
- data: stream.readable,
65
- status
66
- };
31
+ cacheStatus && response.headers.set(X_RENDER_CACHE, cacheStatus);
32
+ return new Response(stream.readable, {
33
+ status: response.status,
34
+ headers: response.headers
35
+ });
67
36
  }
37
+ return response;
68
38
  }
69
39
  const CACHE_NAMESPACE = "__ssr__cache";
70
40
  const storage = createMemoryStorage(CACHE_NAMESPACE);
@@ -111,7 +81,7 @@ function matchCacheControl(cacheOption, req) {
111
81
  }
112
82
  }
113
83
  async function getCacheResult(request, options) {
114
- const { cacheControl, render, ssrContext, container = storage } = options;
84
+ const { cacheControl, container = storage, requestHandler, requestHandlerOptions } = options;
115
85
  const key = computedKey(request, cacheControl);
116
86
  const value = await container.get(key);
117
87
  const { maxAge, staleWhileRevalidate } = cacheControl;
@@ -120,21 +90,50 @@ async function getCacheResult(request, options) {
120
90
  const cache = JSON.parse(value);
121
91
  const interval = Date.now() - cache.cursor;
122
92
  if (interval <= maxAge) {
123
- return {
124
- data: cache.val,
125
- status: "hit"
126
- };
93
+ const cacheStatus = "hit";
94
+ return new Response(cache.val, {
95
+ headers: {
96
+ [X_RENDER_CACHE]: cacheStatus
97
+ }
98
+ });
127
99
  } else if (interval <= staleWhileRevalidate + maxAge) {
128
- processCache(key, render, ssrContext, ttl, container);
129
- return {
130
- data: cache.val,
131
- status: "stale"
132
- };
100
+ processCache({
101
+ key,
102
+ request,
103
+ requestHandler,
104
+ requestHandlerOptions,
105
+ ttl,
106
+ container
107
+ }).then(async (response) => {
108
+ await response.text();
109
+ });
110
+ const cacheStatus = "stale";
111
+ return new Response(cache.val, {
112
+ headers: {
113
+ [X_RENDER_CACHE]: cacheStatus
114
+ }
115
+ });
133
116
  } else {
134
- return processCache(key, render, ssrContext, ttl, container, "expired");
117
+ return processCache({
118
+ key,
119
+ request,
120
+ requestHandler,
121
+ requestHandlerOptions,
122
+ ttl,
123
+ container,
124
+ cacheStatus: "expired"
125
+ });
135
126
  }
136
127
  } else {
137
- return processCache(key, render, ssrContext, ttl, container, "miss");
128
+ return processCache({
129
+ key,
130
+ request,
131
+ requestHandler,
132
+ requestHandlerOptions,
133
+ ttl,
134
+ container,
135
+ cacheStatus: "miss"
136
+ });
138
137
  }
139
138
  }
140
139
  export {