@modern-js/server-core 3.9.1 → 3.9.3

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.
@@ -68,7 +68,9 @@ const createWebRequest = (req, res, body)=>{
68
68
  headers: headerRecord,
69
69
  signal: controller.signal
70
70
  };
71
- res.on('close', ()=>controller.abort('res closed'));
71
+ res.on('close', ()=>{
72
+ if (!res.writableFinished || req.aborted) controller.abort('res closed');
73
+ });
72
74
  const url = `http://${req.headers.host}${req.url}`;
73
75
  const needsRequestBody = body || !('GET' === method || 'HEAD' === method);
74
76
  const cloneableReq = needsRequestBody ? external_cloneable_readable_default()(req) : null;
@@ -143,7 +143,7 @@ function createStaticMiddleware(options) {
143
143
  pwd,
144
144
  routes: routes || []
145
145
  })(c, next);
146
- {
146
+ else {
147
147
  const filepath = external_path_default().join(pwd, pathname.replace(pathPrefix, ()=>''));
148
148
  if (!isPathInside(filepath, pwd)) return next();
149
149
  if (!await utils_namespaceObject.fs.pathExists(filepath)) return next();
@@ -31,7 +31,7 @@ const LOADER_CONTEXT = 'loaderContext';
31
31
  function getLoaderCtx(c) {
32
32
  const loaderContext = c.get(LOADER_CONTEXT);
33
33
  if (loaderContext) return loaderContext;
34
- {
34
+ else {
35
35
  const loaderContext = new Map();
36
36
  c.set(LOADER_CONTEXT, loaderContext);
37
37
  return loaderContext;
@@ -87,8 +87,7 @@ var __webpack_exports__ = {};
87
87
  void 0,
88
88
  {}
89
89
  ];
90
- }
91
- {
90
+ } else {
92
91
  const result = matchedRoutes[0];
93
92
  if (!result) return [
94
93
  void 0,
@@ -242,7 +241,7 @@ var __webpack_exports__ = {};
242
241
  if (req.headers.get('x-rsc-action')) return 'rsc-action';
243
242
  if (req.headers.get('x-rsc-tree')) return 'rsc-tree';
244
243
  if (!isSSR) return 'csr';
245
- {
244
+ else {
246
245
  if (query.__loader) return 'data';
247
246
  const fallbackHeaderValue = req.headers.get(fallbackHeader) || nodeReq?.headers[fallbackHeader];
248
247
  if (forceCSR && (query.csr || fallbackHeaderValue || contextForceCSR)) {
@@ -271,7 +270,7 @@ var __webpack_exports__ = {};
271
270
  [external_constants_js_namespaceObject.X_MODERNJS_RENDER]: 'client'
272
271
  })
273
272
  });
274
- return (0, external_csrRscRender_js_namespaceObject.csrRscRender)(request, options);
273
+ else return (0, external_csrRscRender_js_namespaceObject.csrRscRender)(request, options);
275
274
  }
276
275
  })();
277
276
  exports.createRender = __webpack_exports__.createRender;
@@ -59,30 +59,59 @@ async function processCache({ request, key, requestHandler, requestHandlerOption
59
59
  const reader = response.body.getReader();
60
60
  const writer = stream.writable.getWriter();
61
61
  let html = '';
62
- const push = ()=>reader.read().then(({ done, value })=>{
63
- if (done) {
64
- const match = ZERO_RENDER_LEVEL.test(html) || NO_SSR_CACHE.test(html);
65
- if (match) return void writer.close();
66
- const current = Date.now();
62
+ let cancelled = false;
63
+ const cancel = async (reason)=>{
64
+ cancelled = true;
65
+ await reader.cancel(reason);
66
+ };
67
+ writer.closed.catch(cancel).catch(()=>{});
68
+ const onAbort = ()=>{
69
+ Promise.allSettled([
70
+ cancel(request.signal.reason),
71
+ writer.abort(request.signal.reason)
72
+ ]);
73
+ };
74
+ request.signal.addEventListener('abort', onAbort, {
75
+ once: true
76
+ });
77
+ if (request.signal.aborted) onAbort();
78
+ const pumping = (async ()=>{
79
+ try {
80
+ for(;;){
81
+ const { done, value } = await reader.read();
82
+ if (cancelled) return;
83
+ if (done) break;
84
+ html += decoder.decode(value, {
85
+ stream: true
86
+ });
87
+ await writer.write(value);
88
+ }
89
+ html += decoder.decode();
90
+ await writer.close();
91
+ if (!cancelled && !ZERO_RENDER_LEVEL.test(html) && !NO_SSR_CACHE.test(html)) {
67
92
  const cache = {
68
93
  val: html,
69
- cursor: current
94
+ cursor: Date.now()
70
95
  };
71
- container.set(key, JSON.stringify(cache), {
72
- ttl
73
- }).catch(()=>{
74
- if (onError) onError(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
75
- else console.error(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
76
- });
77
- writer.close();
78
- return;
96
+ try {
97
+ await container.set(key, JSON.stringify(cache), {
98
+ ttl
99
+ });
100
+ } catch (error) {
101
+ if (onError) onError(error, 'render-cache');
102
+ else console.error(`[render-cache] set cache failed, key: ${key}`, error);
103
+ }
79
104
  }
80
- const content = decoder.decode(value);
81
- html += content;
82
- writer.write(value);
83
- push();
84
- });
85
- push();
105
+ } catch (error) {
106
+ await Promise.allSettled([
107
+ cancel(error),
108
+ writer.abort(error)
109
+ ]);
110
+ } finally{
111
+ request.signal.removeEventListener('abort', onAbort);
112
+ }
113
+ })();
114
+ pumping.catch(()=>{});
86
115
  cacheStatus && response.headers.set(external_constants_js_namespaceObject.X_RENDER_CACHE, cacheStatus);
87
116
  return new Response(stream.readable, {
88
117
  status: response.status,
@@ -98,8 +127,8 @@ function computedKey(req, cacheControl) {
98
127
  const { customKey } = cacheControl;
99
128
  const defaultKey = '/' === pathname ? pathname : removeTailSlash(pathname);
100
129
  if (!customKey) return defaultKey;
101
- if ('string' == typeof customKey) return customKey;
102
- return customKey(defaultKey);
130
+ else if ('string' == typeof customKey) return customKey;
131
+ else return customKey(defaultKey);
103
132
  }
104
133
  function shouldUseCache(request) {
105
134
  const url = new URL(request.url);
@@ -110,7 +139,7 @@ function shouldUseCache(request) {
110
139
  }
111
140
  function matchCacheControl(cacheOption, req) {
112
141
  if (!cacheOption || !req) return;
113
- {
142
+ else {
114
143
  if (isCacheControl(cacheOption)) return cacheOption;
115
144
  if (isCacheOptionProvider(cacheOption)) return cacheOption(req);
116
145
  const url = req.url;
@@ -149,7 +178,7 @@ async function getCacheResult(request, options) {
149
178
  container,
150
179
  cacheStatus: 'miss'
151
180
  });
152
- {
181
+ else {
153
182
  const cache = JSON.parse(value);
154
183
  const interval = Date.now() - cache.cursor;
155
184
  if (interval <= maxAge) {
@@ -159,17 +188,16 @@ async function getCacheResult(request, options) {
159
188
  [external_constants_js_namespaceObject.X_RENDER_CACHE]: cacheStatus
160
189
  }
161
190
  });
162
- }
163
- if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
164
- key,
165
- request,
166
- requestHandler,
167
- requestHandlerOptions,
168
- ttl,
169
- container,
170
- cacheStatus: 'expired'
171
- });
172
- {
191
+ } else {
192
+ if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
193
+ key,
194
+ request,
195
+ requestHandler,
196
+ requestHandlerOptions,
197
+ ttl,
198
+ container,
199
+ cacheStatus: 'expired'
200
+ });
173
201
  processCache({
174
202
  key,
175
203
  request,
@@ -179,6 +207,11 @@ async function getCacheResult(request, options) {
179
207
  container
180
208
  }).then(async (response)=>{
181
209
  await response.text();
210
+ }).catch((error)=>{
211
+ try {
212
+ if (onError) onError(error, 'render-cache');
213
+ else console.error('[render-cache] revalidation failed', error);
214
+ } catch {}
182
215
  });
183
216
  const cacheStatus = 'stale';
184
217
  return new Response(cache.val, {
@@ -138,7 +138,7 @@ function applyMiddlewares() {
138
138
  if (middleware.before) {
139
139
  const targetIndex = finalMiddlewares.findIndex((item)=>{
140
140
  if (middleware.before?.includes(item.name)) return true;
141
- return false;
141
+ else return false;
142
142
  });
143
143
  if (-1 !== targetIndex) finalMiddlewares.splice(targetIndex, 0, middleware);
144
144
  else finalMiddlewares.push(middleware);
@@ -159,7 +159,7 @@ function applyMiddlewares() {
159
159
  }
160
160
  function handler2Handlers(handler) {
161
161
  if (Array.isArray(handler)) return handler;
162
- return [
162
+ else return [
163
163
  handler
164
164
  ];
165
165
  }
@@ -43,7 +43,7 @@ function transformResponse(response, transformCb) {
43
43
  if (response.body) {
44
44
  const stream = createTransformStream(async (before)=>{
45
45
  if (Array.isArray(transformCb)) return transformCb.reduce(async (before, cb)=>cb(await before), Promise.resolve(before));
46
- return transformCb(before);
46
+ else return transformCb(before);
47
47
  });
48
48
  response.body.pipeThrough(stream);
49
49
  readable = stream.readable;
@@ -24,7 +24,9 @@ const createWebRequest = (req, res, body)=>{
24
24
  headers: headerRecord,
25
25
  signal: controller.signal
26
26
  };
27
- res.on('close', ()=>controller.abort('res closed'));
27
+ res.on('close', ()=>{
28
+ if (!res.writableFinished || req.aborted) controller.abort('res closed');
29
+ });
28
30
  const url = `http://${req.headers.host}${req.url}`;
29
31
  const needsRequestBody = body || !('GET' === method || 'HEAD' === method);
30
32
  const cloneableReq = needsRequestBody ? cloneable_readable(req) : null;
@@ -99,7 +99,7 @@ function createStaticMiddleware(options) {
99
99
  pwd,
100
100
  routes: routes || []
101
101
  })(c, next);
102
- {
102
+ else {
103
103
  const filepath = path.join(pwd, pathname.replace(pathPrefix, ()=>''));
104
104
  if (!isPathInside(filepath, pwd)) return next();
105
105
  if (!await fs.pathExists(filepath)) return next();
@@ -2,7 +2,7 @@ const LOADER_CONTEXT = 'loaderContext';
2
2
  function getLoaderCtx(c) {
3
3
  const loaderContext = c.get(LOADER_CONTEXT);
4
4
  if (loaderContext) return loaderContext;
5
- {
5
+ else {
6
6
  const loaderContext = new Map();
7
7
  c.set(LOADER_CONTEXT, loaderContext);
8
8
  return loaderContext;
@@ -7,12 +7,6 @@ import { dataHandler } from "./dataHandler.mjs";
7
7
  import { renderRscHandler } from "./renderRscHandler.mjs";
8
8
  import { serverActionHandler } from "./serverActionHandler.mjs";
9
9
  import { ssrRender } from "./ssrRender.mjs";
10
- import { __webpack_require__ } from "../../rslib-runtime~1.mjs";
11
- __webpack_require__.add({
12
- 718 (module) {
13
- module.exports = require("@modern-js/runtime-utils/router");
14
- }
15
- });
16
10
  const DYNAMIC_ROUTE_REG = /\/:./;
17
11
  function getRouter(routes) {
18
12
  const dynamicRoutes = [];
@@ -45,8 +39,7 @@ function matchRoute(router, pathname, entryName) {
45
39
  void 0,
46
40
  {}
47
41
  ];
48
- }
49
- {
42
+ } else {
50
43
  const result = matchedRoutes[0];
51
44
  if (!result) return [
52
45
  void 0,
@@ -162,7 +155,7 @@ async function renderHandler(request, options, mode, fallbackWrapper, framework)
162
155
  const { nestedRoutesJson } = serverManifest;
163
156
  const routes = nestedRoutesJson?.[options.routeInfo.entryName];
164
157
  if (routes) {
165
- const { matchRoutes } = __webpack_require__(718);
158
+ const { matchRoutes } = require("@modern-js/runtime-utils/router");
166
159
  const url = new URL(request.url);
167
160
  const matchedRoutes = matchRoutes(routes, url.pathname, options.routeInfo.urlPath);
168
161
  if (matchedRoutes) {
@@ -200,7 +193,7 @@ async function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFa
200
193
  if (req.headers.get('x-rsc-action')) return 'rsc-action';
201
194
  if (req.headers.get('x-rsc-tree')) return 'rsc-tree';
202
195
  if (!isSSR) return 'csr';
203
- {
196
+ else {
204
197
  if (query.__loader) return 'data';
205
198
  const fallbackHeaderValue = req.headers.get(fallbackHeader) || nodeReq?.headers[fallbackHeader];
206
199
  if (forceCSR && (query.csr || fallbackHeaderValue || contextForceCSR)) {
@@ -229,6 +222,6 @@ async function csrRender(request, options) {
229
222
  [X_MODERNJS_RENDER]: 'client'
230
223
  })
231
224
  });
232
- return csrRscRender(request, options);
225
+ else return csrRscRender(request, options);
233
226
  }
234
227
  export { createRender, matchRoute };
@@ -25,30 +25,59 @@ async function processCache({ request, key, requestHandler, requestHandlerOption
25
25
  const reader = response.body.getReader();
26
26
  const writer = stream.writable.getWriter();
27
27
  let html = '';
28
- const push = ()=>reader.read().then(({ done, value })=>{
29
- if (done) {
30
- const match = ZERO_RENDER_LEVEL.test(html) || NO_SSR_CACHE.test(html);
31
- if (match) return void writer.close();
32
- const current = Date.now();
28
+ let cancelled = false;
29
+ const cancel = async (reason)=>{
30
+ cancelled = true;
31
+ await reader.cancel(reason);
32
+ };
33
+ writer.closed.catch(cancel).catch(()=>{});
34
+ const onAbort = ()=>{
35
+ Promise.allSettled([
36
+ cancel(request.signal.reason),
37
+ writer.abort(request.signal.reason)
38
+ ]);
39
+ };
40
+ request.signal.addEventListener('abort', onAbort, {
41
+ once: true
42
+ });
43
+ if (request.signal.aborted) onAbort();
44
+ const pumping = (async ()=>{
45
+ try {
46
+ for(;;){
47
+ const { done, value } = await reader.read();
48
+ if (cancelled) return;
49
+ if (done) break;
50
+ html += decoder.decode(value, {
51
+ stream: true
52
+ });
53
+ await writer.write(value);
54
+ }
55
+ html += decoder.decode();
56
+ await writer.close();
57
+ if (!cancelled && !ZERO_RENDER_LEVEL.test(html) && !NO_SSR_CACHE.test(html)) {
33
58
  const cache = {
34
59
  val: html,
35
- cursor: current
60
+ cursor: Date.now()
36
61
  };
37
- container.set(key, JSON.stringify(cache), {
38
- ttl
39
- }).catch(()=>{
40
- if (onError) onError(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
41
- else console.error(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
42
- });
43
- writer.close();
44
- return;
62
+ try {
63
+ await container.set(key, JSON.stringify(cache), {
64
+ ttl
65
+ });
66
+ } catch (error) {
67
+ if (onError) onError(error, 'render-cache');
68
+ else console.error(`[render-cache] set cache failed, key: ${key}`, error);
69
+ }
45
70
  }
46
- const content = decoder.decode(value);
47
- html += content;
48
- writer.write(value);
49
- push();
50
- });
51
- push();
71
+ } catch (error) {
72
+ await Promise.allSettled([
73
+ cancel(error),
74
+ writer.abort(error)
75
+ ]);
76
+ } finally{
77
+ request.signal.removeEventListener('abort', onAbort);
78
+ }
79
+ })();
80
+ pumping.catch(()=>{});
52
81
  cacheStatus && response.headers.set(X_RENDER_CACHE, cacheStatus);
53
82
  return new Response(stream.readable, {
54
83
  status: response.status,
@@ -64,8 +93,8 @@ function computedKey(req, cacheControl) {
64
93
  const { customKey } = cacheControl;
65
94
  const defaultKey = '/' === pathname ? pathname : removeTailSlash(pathname);
66
95
  if (!customKey) return defaultKey;
67
- if ('string' == typeof customKey) return customKey;
68
- return customKey(defaultKey);
96
+ else if ('string' == typeof customKey) return customKey;
97
+ else return customKey(defaultKey);
69
98
  }
70
99
  function shouldUseCache(request) {
71
100
  const url = new URL(request.url);
@@ -76,7 +105,7 @@ function shouldUseCache(request) {
76
105
  }
77
106
  function matchCacheControl(cacheOption, req) {
78
107
  if (!cacheOption || !req) return;
79
- {
108
+ else {
80
109
  if (isCacheControl(cacheOption)) return cacheOption;
81
110
  if (isCacheOptionProvider(cacheOption)) return cacheOption(req);
82
111
  const url = req.url;
@@ -115,7 +144,7 @@ async function getCacheResult(request, options) {
115
144
  container,
116
145
  cacheStatus: 'miss'
117
146
  });
118
- {
147
+ else {
119
148
  const cache = JSON.parse(value);
120
149
  const interval = Date.now() - cache.cursor;
121
150
  if (interval <= maxAge) {
@@ -125,17 +154,16 @@ async function getCacheResult(request, options) {
125
154
  [X_RENDER_CACHE]: cacheStatus
126
155
  }
127
156
  });
128
- }
129
- if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
130
- key,
131
- request,
132
- requestHandler,
133
- requestHandlerOptions,
134
- ttl,
135
- container,
136
- cacheStatus: 'expired'
137
- });
138
- {
157
+ } else {
158
+ if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
159
+ key,
160
+ request,
161
+ requestHandler,
162
+ requestHandlerOptions,
163
+ ttl,
164
+ container,
165
+ cacheStatus: 'expired'
166
+ });
139
167
  processCache({
140
168
  key,
141
169
  request,
@@ -145,6 +173,11 @@ async function getCacheResult(request, options) {
145
173
  container
146
174
  }).then(async (response)=>{
147
175
  await response.text();
176
+ }).catch((error)=>{
177
+ try {
178
+ if (onError) onError(error, 'render-cache');
179
+ else console.error('[render-cache] revalidation failed', error);
180
+ } catch {}
148
181
  });
149
182
  const cacheStatus = 'stale';
150
183
  return new Response(cache.val, {
@@ -105,7 +105,7 @@ function applyMiddlewares() {
105
105
  if (middleware.before) {
106
106
  const targetIndex = finalMiddlewares.findIndex((item)=>{
107
107
  if (middleware.before?.includes(item.name)) return true;
108
- return false;
108
+ else return false;
109
109
  });
110
110
  if (-1 !== targetIndex) finalMiddlewares.splice(targetIndex, 0, middleware);
111
111
  else finalMiddlewares.push(middleware);
@@ -126,7 +126,7 @@ function applyMiddlewares() {
126
126
  }
127
127
  function handler2Handlers(handler) {
128
128
  if (Array.isArray(handler)) return handler;
129
- return [
129
+ else return [
130
130
  handler
131
131
  ];
132
132
  }
@@ -14,7 +14,7 @@ function transformResponse(response, transformCb) {
14
14
  if (response.body) {
15
15
  const stream = createTransformStream(async (before)=>{
16
16
  if (Array.isArray(transformCb)) return transformCb.reduce(async (before, cb)=>cb(await before), Promise.resolve(before));
17
- return transformCb(before);
17
+ else return transformCb(before);
18
18
  });
19
19
  response.body.pipeThrough(stream);
20
20
  readable = stream.readable;
@@ -25,7 +25,9 @@ const createWebRequest = (req, res, body)=>{
25
25
  headers: headerRecord,
26
26
  signal: controller.signal
27
27
  };
28
- res.on('close', ()=>controller.abort('res closed'));
28
+ res.on('close', ()=>{
29
+ if (!res.writableFinished || req.aborted) controller.abort('res closed');
30
+ });
29
31
  const url = `http://${req.headers.host}${req.url}`;
30
32
  const needsRequestBody = body || !('GET' === method || 'HEAD' === method);
31
33
  const cloneableReq = needsRequestBody ? cloneable_readable(req) : null;
@@ -100,7 +100,7 @@ function createStaticMiddleware(options) {
100
100
  pwd,
101
101
  routes: routes || []
102
102
  })(c, next);
103
- {
103
+ else {
104
104
  const filepath = path.join(pwd, pathname.replace(pathPrefix, ()=>''));
105
105
  if (!isPathInside(filepath, pwd)) return next();
106
106
  if (!await fs.pathExists(filepath)) return next();
@@ -3,7 +3,7 @@ const LOADER_CONTEXT = 'loaderContext';
3
3
  function getLoaderCtx(c) {
4
4
  const loaderContext = c.get(LOADER_CONTEXT);
5
5
  if (loaderContext) return loaderContext;
6
- {
6
+ else {
7
7
  const loaderContext = new Map();
8
8
  c.set(LOADER_CONTEXT, loaderContext);
9
9
  return loaderContext;
@@ -8,14 +8,8 @@ import { dataHandler } from "./dataHandler.mjs";
8
8
  import { renderRscHandler } from "./renderRscHandler.mjs";
9
9
  import { serverActionHandler } from "./serverActionHandler.mjs";
10
10
  import { ssrRender } from "./ssrRender.mjs";
11
- import { __webpack_require__ } from "../../rslib-runtime~0.mjs";
12
11
  import { createRequire as __rspack_createRequire } from "node:module";
13
12
  const __rspack_createRequire_require = __rspack_createRequire(import.meta.url);
14
- __webpack_require__.add({
15
- "@modern-js/runtime-utils/router" (module) {
16
- module.exports = __rspack_createRequire_require("@modern-js/runtime-utils/router");
17
- }
18
- });
19
13
  const DYNAMIC_ROUTE_REG = /\/:./;
20
14
  function getRouter(routes) {
21
15
  const dynamicRoutes = [];
@@ -48,8 +42,7 @@ function matchRoute(router, pathname, entryName) {
48
42
  void 0,
49
43
  {}
50
44
  ];
51
- }
52
- {
45
+ } else {
53
46
  const result = matchedRoutes[0];
54
47
  if (!result) return [
55
48
  void 0,
@@ -165,7 +158,7 @@ async function renderHandler(request, options, mode, fallbackWrapper, framework)
165
158
  const { nestedRoutesJson } = serverManifest;
166
159
  const routes = nestedRoutesJson?.[options.routeInfo.entryName];
167
160
  if (routes) {
168
- const { matchRoutes } = __webpack_require__("@modern-js/runtime-utils/router");
161
+ const { matchRoutes } = __rspack_createRequire_require("@modern-js/runtime-utils/router");
169
162
  const url = new URL(request.url);
170
163
  const matchedRoutes = matchRoutes(routes, url.pathname, options.routeInfo.urlPath);
171
164
  if (matchedRoutes) {
@@ -203,7 +196,7 @@ async function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFa
203
196
  if (req.headers.get('x-rsc-action')) return 'rsc-action';
204
197
  if (req.headers.get('x-rsc-tree')) return 'rsc-tree';
205
198
  if (!isSSR) return 'csr';
206
- {
199
+ else {
207
200
  if (query.__loader) return 'data';
208
201
  const fallbackHeaderValue = req.headers.get(fallbackHeader) || nodeReq?.headers[fallbackHeader];
209
202
  if (forceCSR && (query.csr || fallbackHeaderValue || contextForceCSR)) {
@@ -232,6 +225,6 @@ async function csrRender(request, options) {
232
225
  [X_MODERNJS_RENDER]: 'client'
233
226
  })
234
227
  });
235
- return csrRscRender(request, options);
228
+ else return csrRscRender(request, options);
236
229
  }
237
230
  export { createRender, matchRoute };
@@ -26,30 +26,59 @@ async function processCache({ request, key, requestHandler, requestHandlerOption
26
26
  const reader = response.body.getReader();
27
27
  const writer = stream.writable.getWriter();
28
28
  let html = '';
29
- const push = ()=>reader.read().then(({ done, value })=>{
30
- if (done) {
31
- const match = ZERO_RENDER_LEVEL.test(html) || NO_SSR_CACHE.test(html);
32
- if (match) return void writer.close();
33
- const current = Date.now();
29
+ let cancelled = false;
30
+ const cancel = async (reason)=>{
31
+ cancelled = true;
32
+ await reader.cancel(reason);
33
+ };
34
+ writer.closed.catch(cancel).catch(()=>{});
35
+ const onAbort = ()=>{
36
+ Promise.allSettled([
37
+ cancel(request.signal.reason),
38
+ writer.abort(request.signal.reason)
39
+ ]);
40
+ };
41
+ request.signal.addEventListener('abort', onAbort, {
42
+ once: true
43
+ });
44
+ if (request.signal.aborted) onAbort();
45
+ const pumping = (async ()=>{
46
+ try {
47
+ for(;;){
48
+ const { done, value } = await reader.read();
49
+ if (cancelled) return;
50
+ if (done) break;
51
+ html += decoder.decode(value, {
52
+ stream: true
53
+ });
54
+ await writer.write(value);
55
+ }
56
+ html += decoder.decode();
57
+ await writer.close();
58
+ if (!cancelled && !ZERO_RENDER_LEVEL.test(html) && !NO_SSR_CACHE.test(html)) {
34
59
  const cache = {
35
60
  val: html,
36
- cursor: current
61
+ cursor: Date.now()
37
62
  };
38
- container.set(key, JSON.stringify(cache), {
39
- ttl
40
- }).catch(()=>{
41
- if (onError) onError(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
42
- else console.error(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
43
- });
44
- writer.close();
45
- return;
63
+ try {
64
+ await container.set(key, JSON.stringify(cache), {
65
+ ttl
66
+ });
67
+ } catch (error) {
68
+ if (onError) onError(error, 'render-cache');
69
+ else console.error(`[render-cache] set cache failed, key: ${key}`, error);
70
+ }
46
71
  }
47
- const content = decoder.decode(value);
48
- html += content;
49
- writer.write(value);
50
- push();
51
- });
52
- push();
72
+ } catch (error) {
73
+ await Promise.allSettled([
74
+ cancel(error),
75
+ writer.abort(error)
76
+ ]);
77
+ } finally{
78
+ request.signal.removeEventListener('abort', onAbort);
79
+ }
80
+ })();
81
+ pumping.catch(()=>{});
53
82
  cacheStatus && response.headers.set(X_RENDER_CACHE, cacheStatus);
54
83
  return new Response(stream.readable, {
55
84
  status: response.status,
@@ -65,8 +94,8 @@ function computedKey(req, cacheControl) {
65
94
  const { customKey } = cacheControl;
66
95
  const defaultKey = '/' === pathname ? pathname : removeTailSlash(pathname);
67
96
  if (!customKey) return defaultKey;
68
- if ('string' == typeof customKey) return customKey;
69
- return customKey(defaultKey);
97
+ else if ('string' == typeof customKey) return customKey;
98
+ else return customKey(defaultKey);
70
99
  }
71
100
  function shouldUseCache(request) {
72
101
  const url = new URL(request.url);
@@ -77,7 +106,7 @@ function shouldUseCache(request) {
77
106
  }
78
107
  function matchCacheControl(cacheOption, req) {
79
108
  if (!cacheOption || !req) return;
80
- {
109
+ else {
81
110
  if (isCacheControl(cacheOption)) return cacheOption;
82
111
  if (isCacheOptionProvider(cacheOption)) return cacheOption(req);
83
112
  const url = req.url;
@@ -116,7 +145,7 @@ async function getCacheResult(request, options) {
116
145
  container,
117
146
  cacheStatus: 'miss'
118
147
  });
119
- {
148
+ else {
120
149
  const cache = JSON.parse(value);
121
150
  const interval = Date.now() - cache.cursor;
122
151
  if (interval <= maxAge) {
@@ -126,17 +155,16 @@ async function getCacheResult(request, options) {
126
155
  [X_RENDER_CACHE]: cacheStatus
127
156
  }
128
157
  });
129
- }
130
- if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
131
- key,
132
- request,
133
- requestHandler,
134
- requestHandlerOptions,
135
- ttl,
136
- container,
137
- cacheStatus: 'expired'
138
- });
139
- {
158
+ } else {
159
+ if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
160
+ key,
161
+ request,
162
+ requestHandler,
163
+ requestHandlerOptions,
164
+ ttl,
165
+ container,
166
+ cacheStatus: 'expired'
167
+ });
140
168
  processCache({
141
169
  key,
142
170
  request,
@@ -146,6 +174,11 @@ async function getCacheResult(request, options) {
146
174
  container
147
175
  }).then(async (response)=>{
148
176
  await response.text();
177
+ }).catch((error)=>{
178
+ try {
179
+ if (onError) onError(error, 'render-cache');
180
+ else console.error('[render-cache] revalidation failed', error);
181
+ } catch {}
149
182
  });
150
183
  const cacheStatus = 'stale';
151
184
  return new Response(cache.val, {
@@ -106,7 +106,7 @@ function applyMiddlewares() {
106
106
  if (middleware.before) {
107
107
  const targetIndex = finalMiddlewares.findIndex((item)=>{
108
108
  if (middleware.before?.includes(item.name)) return true;
109
- return false;
109
+ else return false;
110
110
  });
111
111
  if (-1 !== targetIndex) finalMiddlewares.splice(targetIndex, 0, middleware);
112
112
  else finalMiddlewares.push(middleware);
@@ -127,7 +127,7 @@ function applyMiddlewares() {
127
127
  }
128
128
  function handler2Handlers(handler) {
129
129
  if (Array.isArray(handler)) return handler;
130
- return [
130
+ else return [
131
131
  handler
132
132
  ];
133
133
  }
@@ -15,7 +15,7 @@ function transformResponse(response, transformCb) {
15
15
  if (response.body) {
16
16
  const stream = createTransformStream(async (before)=>{
17
17
  if (Array.isArray(transformCb)) return transformCb.reduce(async (before, cb)=>cb(await before), Promise.resolve(before));
18
- return transformCb(before);
18
+ else return transformCb(before);
19
19
  });
20
20
  response.body.pipeThrough(stream);
21
21
  readable = stream.readable;
@@ -1,11 +1,11 @@
1
1
  import type { ServerRoute } from '@modern-js/types';
2
2
  import type { HtmlNormalizedConfig, Middleware, OutputNormalizedConfig, ServerNormalizedConfig, ServerPlugin } from '../../../types/index.js';
3
3
  export declare const serverStaticPlugin: () => ServerPlugin;
4
- export type PublicMiddlwareOptions = {
4
+ export type PublicMiddlewareOptions = {
5
5
  pwd: string;
6
6
  routes: ServerRoute[];
7
7
  };
8
- export declare function createPublicMiddleware({ pwd, routes, }: PublicMiddlwareOptions): Middleware;
8
+ export declare function createPublicMiddleware({ pwd, routes, }: PublicMiddlewareOptions): Middleware;
9
9
  export interface ServerStaticOptions {
10
10
  pwd: string;
11
11
  output: OutputNormalizedConfig;
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "modern",
16
16
  "modern.js"
17
17
  ],
18
- "version": "3.9.1",
18
+ "version": "3.9.3",
19
19
  "types": "./dist/types/index.d.ts",
20
20
  "main": "./dist/cjs/index.js",
21
21
  "exports": {
@@ -70,20 +70,20 @@
70
70
  "cloneable-readable": "^3.0.0",
71
71
  "flatted": "^3.4.4",
72
72
  "hono": "^4.11.7",
73
- "ts-deepmerge": "7.0.3",
74
- "@modern-js/plugin": "3.9.1",
75
- "@modern-js/runtime-utils": "3.9.1",
76
- "@modern-js/utils": "3.9.1"
73
+ "ts-deepmerge": "8.0.0",
74
+ "@modern-js/plugin": "3.9.3",
75
+ "@modern-js/runtime-utils": "3.9.3",
76
+ "@modern-js/utils": "3.9.3"
77
77
  },
78
78
  "devDependencies": {
79
- "@rslib/core": "1.0.0",
79
+ "@rslib/core": "1.0.1",
80
80
  "@types/cloneable-readable": "^2.0.3",
81
81
  "@types/merge-deep": "^3.0.3",
82
82
  "@types/node": "^20",
83
83
  "http-proxy-middleware": "^2.0.10",
84
84
  "typescript": "^5",
85
85
  "@modern-js/rslib": "2.68.10",
86
- "@modern-js/types": "3.9.1",
86
+ "@modern-js/types": "3.9.3",
87
87
  "@scripts/rstest-config": "2.66.0"
88
88
  },
89
89
  "sideEffects": false,
@@ -1,18 +0,0 @@
1
- var __webpack_modules__ = {};
2
- var __webpack_module_cache__ = {};
3
- function __webpack_require__(moduleId) {
4
- var cachedModule = __webpack_module_cache__[moduleId];
5
- if (void 0 !== cachedModule) return cachedModule.exports;
6
- var module = __webpack_module_cache__[moduleId] = {
7
- exports: {}
8
- };
9
- __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
10
- return module.exports;
11
- }
12
- __webpack_require__.m = __webpack_modules__;
13
- (()=>{
14
- __webpack_require__.add = function(modules) {
15
- Object.assign(__webpack_require__.m, modules);
16
- };
17
- })();
18
- export { __webpack_require__ };
@@ -1,19 +0,0 @@
1
- import "node:module";
2
- var __webpack_modules__ = {};
3
- var __webpack_module_cache__ = {};
4
- function __webpack_require__(moduleId) {
5
- var cachedModule = __webpack_module_cache__[moduleId];
6
- if (void 0 !== cachedModule) return cachedModule.exports;
7
- var module = __webpack_module_cache__[moduleId] = {
8
- exports: {}
9
- };
10
- __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
11
- return module.exports;
12
- }
13
- __webpack_require__.m = __webpack_modules__;
14
- (()=>{
15
- __webpack_require__.add = function(modules) {
16
- Object.assign(__webpack_require__.m, modules);
17
- };
18
- })();
19
- export { __webpack_require__ };