@bleedingdev/modern-js-server-core 3.9.0-ultramodern.2 → 3.9.0-ultramodern.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/adapters/node/hono.js +15 -5
- package/dist/cjs/adapters/node/index.js +4 -0
- package/dist/cjs/adapters/node/plugins/static.js +107 -29
- package/dist/cjs/helper.js +1 -1
- package/dist/cjs/index.js +10 -34
- package/dist/cjs/plugins/compat/index.js +1 -0
- package/dist/cjs/plugins/render/render.js +3 -4
- package/dist/cjs/plugins/render/ssrCache.js +63 -42
- package/dist/cjs/serverBase.js +60 -19
- package/dist/cjs/utils/error.js +0 -10
- package/dist/cjs/utils/transformStream.js +1 -1
- package/dist/esm/adapters/node/hono.mjs +15 -5
- package/dist/esm/adapters/node/index.mjs +1 -0
- package/dist/esm/adapters/node/plugins/static.mjs +107 -32
- package/dist/esm/helper.mjs +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/plugins/compat/index.mjs +1 -0
- package/dist/esm/plugins/render/render.mjs +4 -11
- package/dist/esm/plugins/render/ssrCache.mjs +63 -42
- package/dist/esm/serverBase.mjs +60 -19
- package/dist/esm/utils/error.mjs +0 -1
- package/dist/esm/utils/transformStream.mjs +1 -1
- package/dist/esm-node/adapters/node/hono.mjs +15 -5
- package/dist/esm-node/adapters/node/index.mjs +1 -0
- package/dist/esm-node/adapters/node/plugins/static.mjs +107 -32
- package/dist/esm-node/helper.mjs +1 -1
- package/dist/esm-node/index.mjs +1 -1
- package/dist/esm-node/plugins/compat/index.mjs +1 -0
- package/dist/esm-node/plugins/render/render.mjs +4 -11
- package/dist/esm-node/plugins/render/ssrCache.mjs +63 -42
- package/dist/esm-node/serverBase.mjs +60 -19
- package/dist/esm-node/utils/error.mjs +0 -1
- package/dist/esm-node/utils/transformStream.mjs +1 -1
- package/dist/types/adapters/node/index.d.ts +2 -0
- package/dist/types/adapters/node/plugins/static.d.ts +42 -4
- package/dist/types/index.d.ts +1 -2
- package/dist/types/serverBase.d.ts +6 -0
- package/dist/types/types/config/bff.d.ts +4 -15
- package/dist/types/types/config/server.d.ts +1 -3
- package/dist/types/types/plugins/plugin.d.ts +15 -1
- package/dist/types/types/requestHandler.d.ts +2 -3
- package/dist/types/utils/error.d.ts +0 -2
- package/package.json +9 -10
- package/dist/cjs/adapters/node/plugins/staticModuleFederation.js +0 -173
- package/dist/cjs/adapters/node/plugins/staticPrecompressed.js +0 -152
- package/dist/cjs/adapters/node/plugins/staticServing.js +0 -206
- package/dist/cjs/types/config/bffRuntime.js +0 -18
- package/dist/cjs/types/config/serverTelemetry.js +0 -18
- package/dist/esm/adapters/node/plugins/staticModuleFederation.mjs +0 -104
- package/dist/esm/adapters/node/plugins/staticPrecompressed.mjs +0 -111
- package/dist/esm/adapters/node/plugins/staticServing.mjs +0 -152
- package/dist/esm/rslib-runtime~1.mjs +0 -18
- package/dist/esm/types/config/bffRuntime.mjs +0 -0
- package/dist/esm/types/config/serverTelemetry.mjs +0 -0
- package/dist/esm-node/adapters/node/plugins/staticModuleFederation.mjs +0 -105
- package/dist/esm-node/adapters/node/plugins/staticPrecompressed.mjs +0 -112
- package/dist/esm-node/adapters/node/plugins/staticServing.mjs +0 -153
- package/dist/esm-node/rslib-runtime~0.mjs +0 -19
- package/dist/esm-node/types/config/bffRuntime.mjs +0 -1
- package/dist/esm-node/types/config/serverTelemetry.mjs +0 -1
- package/dist/types/adapters/node/plugins/staticModuleFederation.d.ts +0 -13
- package/dist/types/adapters/node/plugins/staticPrecompressed.d.ts +0 -13
- package/dist/types/adapters/node/plugins/staticServing.d.ts +0 -25
- package/dist/types/types/config/bffRuntime.d.ts +0 -116
- package/dist/types/types/config/serverTelemetry.d.ts +0 -319
package/dist/cjs/serverBase.js
CHANGED
|
@@ -32,6 +32,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
32
32
|
createServerBase: ()=>createServerBase
|
|
33
33
|
});
|
|
34
34
|
const server_namespaceObject = require("@modern-js/plugin/server");
|
|
35
|
+
const utils_namespaceObject = require("@modern-js/utils");
|
|
35
36
|
const external_hono_namespaceObject = require("hono");
|
|
36
37
|
const external_context_js_namespaceObject = require("./context.js");
|
|
37
38
|
const hooks_js_namespaceObject = require("./plugins/compat/hooks.js");
|
|
@@ -50,22 +51,54 @@ function _class_private_method_init(obj, privateSet) {
|
|
|
50
51
|
var _applyMiddlewares = /*#__PURE__*/ new WeakSet();
|
|
51
52
|
class ServerBase {
|
|
52
53
|
async init() {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
try {
|
|
55
|
+
const { serverConfig, config: cliConfig } = this.serverOptions;
|
|
56
|
+
const mergedConfig = (0, index_js_namespaceObject.loadConfig)({
|
|
57
|
+
cliConfig,
|
|
58
|
+
serverConfig: serverConfig || {}
|
|
59
|
+
});
|
|
60
|
+
const { serverContext } = await server_namespaceObject.server.run({
|
|
61
|
+
plugins: this.plugins,
|
|
62
|
+
options: this.serverOptions,
|
|
63
|
+
config: mergedConfig,
|
|
64
|
+
handleSetupResult: hooks_js_namespaceObject.handleSetupResult
|
|
65
|
+
});
|
|
66
|
+
serverContext.serverBase = this;
|
|
67
|
+
this.serverContext = serverContext;
|
|
68
|
+
await serverContext.hooks.onPrepare.call();
|
|
69
|
+
_class_private_method_get(this, _applyMiddlewares, applyMiddlewares).call(this);
|
|
70
|
+
return this;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
await this.dispose().catch((disposeError)=>{
|
|
73
|
+
utils_namespaceObject.logger.error(disposeError);
|
|
74
|
+
});
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
onDispose(disposer) {
|
|
79
|
+
if (this.disposePromise) throw new Error('Cannot register a disposer on a retired server.');
|
|
80
|
+
this.disposers.add(disposer);
|
|
81
|
+
return ()=>{
|
|
82
|
+
this.disposers.delete(disposer);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
dispose() {
|
|
86
|
+
if (!this.disposePromise) {
|
|
87
|
+
const disposers = [
|
|
88
|
+
...this.disposers
|
|
89
|
+
].reverse();
|
|
90
|
+
this.disposers.clear();
|
|
91
|
+
this.disposePromise = Promise.resolve().then(async ()=>{
|
|
92
|
+
const errors = [];
|
|
93
|
+
for (const disposer of disposers)try {
|
|
94
|
+
await disposer();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
errors.push(error);
|
|
97
|
+
}
|
|
98
|
+
if (errors.length > 0) throw new AggregateError(errors, 'Failed to dispose server.');
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return this.disposePromise;
|
|
69
102
|
}
|
|
70
103
|
addPlugins(plugins) {
|
|
71
104
|
this.plugins.push(...plugins);
|
|
@@ -111,7 +144,15 @@ class ServerBase {
|
|
|
111
144
|
}
|
|
112
145
|
constructor(options){
|
|
113
146
|
_class_private_method_init(this, _applyMiddlewares);
|
|
114
|
-
this.plugins = [
|
|
147
|
+
this.plugins = [
|
|
148
|
+
{
|
|
149
|
+
name: '@modern-js/server-lifecycle',
|
|
150
|
+
_registryApi: ()=>({
|
|
151
|
+
onDispose: (disposer)=>this.onDispose(disposer)
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
];
|
|
155
|
+
this.disposers = new Set();
|
|
115
156
|
this.serverContext = null;
|
|
116
157
|
this.serverOptions = options;
|
|
117
158
|
this.app = new external_hono_namespaceObject.Hono();
|
|
@@ -138,7 +179,7 @@ function applyMiddlewares() {
|
|
|
138
179
|
if (middleware.before) {
|
|
139
180
|
const targetIndex = finalMiddlewares.findIndex((item)=>{
|
|
140
181
|
if (middleware.before?.includes(item.name)) return true;
|
|
141
|
-
return false;
|
|
182
|
+
else return false;
|
|
142
183
|
});
|
|
143
184
|
if (-1 !== targetIndex) finalMiddlewares.splice(targetIndex, 0, middleware);
|
|
144
185
|
else finalMiddlewares.push(middleware);
|
|
@@ -159,7 +200,7 @@ function applyMiddlewares() {
|
|
|
159
200
|
}
|
|
160
201
|
function handler2Handlers(handler) {
|
|
161
202
|
if (Array.isArray(handler)) return handler;
|
|
162
|
-
return [
|
|
203
|
+
else return [
|
|
163
204
|
handler
|
|
164
205
|
];
|
|
165
206
|
}
|
package/dist/cjs/utils/error.js
CHANGED
|
@@ -30,12 +30,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
30
30
|
__webpack_require__.d(__webpack_exports__, {
|
|
31
31
|
ErrorDigest: ()=>error_ErrorDigest,
|
|
32
32
|
createErrorHtml: ()=>createErrorHtml,
|
|
33
|
-
createSafeFailureHttpResult: ()=>safe_failure_namespaceObject.createSafeFailureHttpResult,
|
|
34
|
-
createSafeJsonFailureResponse: ()=>safe_failure_namespaceObject.createSafeJsonFailureResponse,
|
|
35
|
-
getSafeFailureStatus: ()=>safe_failure_namespaceObject.getSafeFailureStatus,
|
|
36
33
|
onError: ()=>onError
|
|
37
34
|
});
|
|
38
|
-
const safe_failure_namespaceObject = require("@modern-js/runtime-extensions/safe-failure");
|
|
39
35
|
const external_request_js_namespaceObject = require("./request.js");
|
|
40
36
|
const ERROR_PAGE_TEXT = {
|
|
41
37
|
404: 'This page could not be found.',
|
|
@@ -90,16 +86,10 @@ function onError(digest, error, monitors, req) {
|
|
|
90
86
|
}
|
|
91
87
|
exports.ErrorDigest = __webpack_exports__.ErrorDigest;
|
|
92
88
|
exports.createErrorHtml = __webpack_exports__.createErrorHtml;
|
|
93
|
-
exports.createSafeFailureHttpResult = __webpack_exports__.createSafeFailureHttpResult;
|
|
94
|
-
exports.createSafeJsonFailureResponse = __webpack_exports__.createSafeJsonFailureResponse;
|
|
95
|
-
exports.getSafeFailureStatus = __webpack_exports__.getSafeFailureStatus;
|
|
96
89
|
exports.onError = __webpack_exports__.onError;
|
|
97
90
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
98
91
|
"ErrorDigest",
|
|
99
92
|
"createErrorHtml",
|
|
100
|
-
"createSafeFailureHttpResult",
|
|
101
|
-
"createSafeJsonFailureResponse",
|
|
102
|
-
"getSafeFailureStatus",
|
|
103
93
|
"onError"
|
|
104
94
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
105
95
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -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;
|
|
@@ -30,12 +30,22 @@ const httpCallBack2HonoMid = (handler)=>async (context, next)=>{
|
|
|
30
30
|
};
|
|
31
31
|
const noop = ()=>{};
|
|
32
32
|
const connectMid2HonoMid = (handler)=>async (context, next)=>new Promise((resolve, reject)=>{
|
|
33
|
-
const { req, res } = context.env.node;
|
|
33
|
+
const { req, res: rawRes } = context.env.node;
|
|
34
|
+
const res = rawRes;
|
|
34
35
|
if (handler.length < 3) resolve(handler(req, res, noop));
|
|
35
|
-
else
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
else {
|
|
37
|
+
const onFinish = ()=>{
|
|
38
|
+
context.res;
|
|
39
|
+
context.finalized = true;
|
|
40
|
+
resolve();
|
|
41
|
+
};
|
|
42
|
+
res.once?.('finish', onFinish);
|
|
43
|
+
handler(req, res, (err)=>{
|
|
44
|
+
res.removeListener?.('finish', onFinish);
|
|
45
|
+
if (err) reject(err);
|
|
46
|
+
else resolve(next());
|
|
47
|
+
});
|
|
48
|
+
}
|
|
39
49
|
});
|
|
40
50
|
const connectMockMid2HonoMid = (handler)=>async (context, next)=>new Promise((resolve, reject)=>{
|
|
41
51
|
const { req, res: rawRes } = context.env.node;
|
|
@@ -2,3 +2,4 @@ export { loadCacheConfig, loadServerCliConfig, loadServerEnv, loadServerPlugins,
|
|
|
2
2
|
export { connectMid2HonoMid, connectMockMid2HonoMid, httpCallBack2HonoMid } from "./hono.mjs";
|
|
3
3
|
export { createNodeServer, createWebRequest, sendResponse } from "./node.mjs";
|
|
4
4
|
export { getHtmlTemplates, getServerManifest, injectNodeSeverPlugin, injectResourcePlugin, injectRscManifestPlugin, serverStaticPlugin } from "./plugins/index.mjs";
|
|
5
|
+
export { serveStaticAsset } from "./plugins/static.mjs";
|
|
@@ -1,8 +1,55 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { fileReader } from "@modern-js/runtime-utils/fileReader";
|
|
2
|
+
import { fs } from "@modern-js/utils";
|
|
3
|
+
import { getMimeType } from "hono/utils/mime";
|
|
4
|
+
import path from "path";
|
|
2
5
|
import { sortRoutes } from "../../../utils/index.mjs";
|
|
3
6
|
import { getPublicDirPatterns } from "../../../utils/publicDir.mjs";
|
|
4
|
-
|
|
5
|
-
const
|
|
7
|
+
const isPathInside = (target, root)=>{
|
|
8
|
+
const relative = path.relative(path.resolve(root), path.resolve(target));
|
|
9
|
+
return '' === relative || !relative.startsWith(`..${path.sep}`) && '..' !== relative && !path.isAbsolute(relative);
|
|
10
|
+
};
|
|
11
|
+
async function serveStaticAsset(context, asset, respond) {
|
|
12
|
+
let { filename } = asset;
|
|
13
|
+
const { kind } = asset;
|
|
14
|
+
if (asset.root && !isPathInside(filename, asset.root)) return null;
|
|
15
|
+
if (asset.realpath) try {
|
|
16
|
+
const [realFilename, realRoot, stat] = await Promise.all([
|
|
17
|
+
fs.realpath(filename),
|
|
18
|
+
asset.root ? fs.realpath(asset.root) : Promise.resolve(void 0),
|
|
19
|
+
fs.stat(filename)
|
|
20
|
+
]);
|
|
21
|
+
if (!stat.isFile() || realRoot && !isPathInside(realFilename, realRoot)) return null;
|
|
22
|
+
filename = realFilename;
|
|
23
|
+
asset = {
|
|
24
|
+
...asset,
|
|
25
|
+
filename,
|
|
26
|
+
root: realRoot
|
|
27
|
+
};
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
if ('static' === kind && !await fs.pathExists(filename)) return null;
|
|
32
|
+
if (respond) return respond(asset, (representation)=>serveStaticAsset(context, {
|
|
33
|
+
...asset,
|
|
34
|
+
...representation,
|
|
35
|
+
filename: representation?.filename ?? asset.filename,
|
|
36
|
+
mimeFilename: asset.mimeFilename ?? filename
|
|
37
|
+
}));
|
|
38
|
+
const mimeType = getMimeType(asset.mimeFilename ?? filename);
|
|
39
|
+
if ('static' === kind && mimeType) context.header('Content-Type', mimeType);
|
|
40
|
+
const size = 'static' === kind ? (await fs.lstat(filename)).size : void 0;
|
|
41
|
+
const data = 'static' === kind ? await fileReader.readFileFromSystem(filename, 'buffer') : await fileReader.readFile(filename, 'buffer');
|
|
42
|
+
if ('static' === kind && (asset.contentLength ?? true)) context.header('Content-Length', String(true === asset.contentLength && data ? data.byteLength : size));
|
|
43
|
+
if (null === data) return null;
|
|
44
|
+
if ('public' === kind && mimeType) context.header('Content-Type', mimeType);
|
|
45
|
+
Object.entries(asset.responseHeaders || {}).forEach(([key, value])=>{
|
|
46
|
+
context.header(key, value);
|
|
47
|
+
});
|
|
48
|
+
if ('public' === kind && asset.contentLength) context.header('Content-Length', String(data.byteLength));
|
|
49
|
+
const body = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
50
|
+
return context.body(body, 200);
|
|
51
|
+
}
|
|
52
|
+
const serverStaticPlugin = (options = {})=>({
|
|
6
53
|
name: '@modern-js/plugin-server-static',
|
|
7
54
|
setup (api) {
|
|
8
55
|
api.onPrepare(()=>{
|
|
@@ -13,7 +60,9 @@ const serverStaticPlugin = ()=>({
|
|
|
13
60
|
routes,
|
|
14
61
|
output: config.output || {},
|
|
15
62
|
html: config.html || {},
|
|
16
|
-
server: config.server || {}
|
|
63
|
+
server: config.server || {},
|
|
64
|
+
...api.getServerContext().staticAssetResponders,
|
|
65
|
+
...options
|
|
17
66
|
});
|
|
18
67
|
middlewares.push({
|
|
19
68
|
name: 'server-static',
|
|
@@ -22,16 +71,33 @@ const serverStaticPlugin = ()=>({
|
|
|
22
71
|
});
|
|
23
72
|
}
|
|
24
73
|
});
|
|
25
|
-
function createPublicMiddleware({ pwd, routes }) {
|
|
74
|
+
function createPublicMiddleware({ pwd, routes, pathPrefix = '/', respondAsset, respondPublicFallback }) {
|
|
26
75
|
return async (c, next)=>{
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
76
|
+
const respondPublic = async ()=>{
|
|
77
|
+
const route = matchPublicRoute(c.req, routes);
|
|
78
|
+
if (!route) return null;
|
|
79
|
+
const asset = {
|
|
80
|
+
filename: path.join(pwd, route.entryPath),
|
|
81
|
+
kind: 'public',
|
|
82
|
+
responseHeaders: route.responseHeaders
|
|
83
|
+
};
|
|
84
|
+
const serve = (representation)=>serveStaticAsset(c, {
|
|
85
|
+
...asset,
|
|
86
|
+
...representation,
|
|
87
|
+
filename: representation?.filename ?? asset.filename,
|
|
88
|
+
mimeFilename: asset.filename
|
|
89
|
+
});
|
|
90
|
+
const response = respondAsset ? await respondAsset(c, asset, serve, {
|
|
91
|
+
root: pwd,
|
|
92
|
+
pathPrefix
|
|
93
|
+
}) : void 0;
|
|
94
|
+
return void 0 === response ? serve() : response;
|
|
95
|
+
};
|
|
96
|
+
const response = respondPublicFallback ? await respondPublicFallback(c, respondPublic, {
|
|
97
|
+
root: pwd,
|
|
98
|
+
pathPrefix
|
|
99
|
+
}) : await respondPublic();
|
|
100
|
+
return response ?? next();
|
|
35
101
|
};
|
|
36
102
|
}
|
|
37
103
|
function matchPublicRoute(req, routes) {
|
|
@@ -76,29 +142,38 @@ function createStaticMiddleware(options) {
|
|
|
76
142
|
...staticReg,
|
|
77
143
|
...iconReg
|
|
78
144
|
].join('|')})`);
|
|
79
|
-
const publicMiddleware = createPublicMiddleware({
|
|
80
|
-
pwd,
|
|
81
|
-
routes: routes || []
|
|
82
|
-
});
|
|
83
|
-
const moduleFederationStaticServing = createModuleFederationStaticServing({
|
|
84
|
-
pwd,
|
|
85
|
-
pathPrefix
|
|
86
|
-
});
|
|
87
145
|
return async (c, next)=>{
|
|
88
146
|
const pageRoute = c.get('route');
|
|
89
147
|
const pathname = c.req.path;
|
|
90
|
-
if (pageRoute && '' ===
|
|
148
|
+
if (pageRoute && '' === path.extname(pathname)) return next();
|
|
91
149
|
const hit = staticPathRegExp.test(pathname);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
150
|
+
if (!hit) return createPublicMiddleware({
|
|
151
|
+
pwd,
|
|
152
|
+
routes: routes || [],
|
|
153
|
+
pathPrefix,
|
|
154
|
+
respondAsset: options.respondAsset,
|
|
155
|
+
respondPublicFallback: options.respondPublicFallback
|
|
156
|
+
})(c, next);
|
|
157
|
+
else {
|
|
158
|
+
const filepath = path.join(pwd, pathname.replace(pathPrefix, ()=>''));
|
|
159
|
+
if (!isPathInside(filepath, pwd)) return next();
|
|
160
|
+
if (!await fs.pathExists(filepath)) return next();
|
|
161
|
+
const asset = {
|
|
162
|
+
filename: filepath,
|
|
163
|
+
kind: 'static'
|
|
164
|
+
};
|
|
165
|
+
const serve = (representation)=>serveStaticAsset(c, {
|
|
166
|
+
...asset,
|
|
167
|
+
...representation,
|
|
168
|
+
filename: representation?.filename ?? asset.filename,
|
|
169
|
+
mimeFilename: filepath
|
|
170
|
+
});
|
|
171
|
+
const response = options.respondAsset ? await options.respondAsset(c, asset, serve, {
|
|
172
|
+
root: pwd,
|
|
173
|
+
pathPrefix
|
|
174
|
+
}) : void 0;
|
|
175
|
+
return (void 0 === response ? await serve() : response) ?? next();
|
|
98
176
|
}
|
|
99
|
-
const moduleFederationResponse = await moduleFederationStaticServing.serveModuleFederationAsset(c, staticServingRequest);
|
|
100
|
-
if (null !== moduleFederationResponse) return moduleFederationResponse;
|
|
101
|
-
return publicMiddleware(c, next);
|
|
102
177
|
};
|
|
103
178
|
}
|
|
104
179
|
const prepareFavicons = (favicon)=>{
|
|
@@ -106,4 +181,4 @@ const prepareFavicons = (favicon)=>{
|
|
|
106
181
|
if (favicon && 'string' == typeof favicon) faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
|
|
107
182
|
return faviconNames;
|
|
108
183
|
};
|
|
109
|
-
export { createPublicMiddleware, createStaticMiddleware, serverStaticPlugin };
|
|
184
|
+
export { createPublicMiddleware, createStaticMiddleware, serveStaticAsset, serverStaticPlugin };
|
package/dist/esm/helper.mjs
CHANGED
|
@@ -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;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -8,5 +8,5 @@ export { AGGRED_DIR } from "./constants.mjs";
|
|
|
8
8
|
export { run, useHonoContext } from "./context.mjs";
|
|
9
9
|
export { getLoaderCtx } from "./helper.mjs";
|
|
10
10
|
export { createServerBase } from "./serverBase.mjs";
|
|
11
|
-
export { ErrorDigest, createErrorHtml,
|
|
11
|
+
export { ErrorDigest, createErrorHtml, onError } from "./utils/index.mjs";
|
|
12
12
|
export { getPublicDirConfig, getPublicDirPatterns, getPublicDirRoutePrefixes, normalizePublicDir, normalizePublicDirPath, resolvePublicDirPaths } from "./utils/publicDir.mjs";
|
|
@@ -3,6 +3,7 @@ import { getHookRunners, handleSetupResult } from "./hooks.mjs";
|
|
|
3
3
|
const compatPlugin = ()=>({
|
|
4
4
|
name: '@modern-js/server-compat',
|
|
5
5
|
registryHooks: {
|
|
6
|
+
handleError: createAsyncPipelineHook(),
|
|
6
7
|
prepareWebServer: createAsyncPipelineHook(),
|
|
7
8
|
prepareApiServer: createAsyncPipelineHook(),
|
|
8
9
|
afterMatch: createAsyncPipelineHook(),
|
|
@@ -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,
|
|
@@ -163,7 +156,7 @@ async function renderHandler(request, options, mode, fallbackWrapper, framework)
|
|
|
163
156
|
const { nestedRoutesJson } = serverManifest;
|
|
164
157
|
const routes = nestedRoutesJson?.[options.routeInfo.entryName];
|
|
165
158
|
if (routes) {
|
|
166
|
-
const { matchRoutes } =
|
|
159
|
+
const { matchRoutes } = require("@modern-js/runtime-utils/router");
|
|
167
160
|
const url = new URL(request.url);
|
|
168
161
|
const matchedRoutes = matchRoutes(routes, url.pathname, options.routeInfo.urlPath);
|
|
169
162
|
if (matchedRoutes) {
|
|
@@ -201,7 +194,7 @@ async function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFa
|
|
|
201
194
|
if (req.headers.get('x-rsc-action')) return 'rsc-action';
|
|
202
195
|
if (req.headers.get('x-rsc-tree')) return 'rsc-tree';
|
|
203
196
|
if (!isSSR) return 'csr';
|
|
204
|
-
{
|
|
197
|
+
else {
|
|
205
198
|
if (query.__loader) return 'data';
|
|
206
199
|
const fallbackHeaderValue = req.headers.get(fallbackHeader) || nodeReq?.headers[fallbackHeader];
|
|
207
200
|
if (forceCSR && (query.csr || fallbackHeaderValue || contextForceCSR)) {
|
|
@@ -230,6 +223,6 @@ async function csrRender(request, options) {
|
|
|
230
223
|
[X_MODERNJS_RENDER]: 'client'
|
|
231
224
|
})
|
|
232
225
|
});
|
|
233
|
-
return csrRscRender(request, options);
|
|
226
|
+
else return csrRscRender(request, options);
|
|
234
227
|
}
|
|
235
228
|
export { createRender, matchRoute };
|
|
@@ -1,54 +1,67 @@
|
|
|
1
1
|
import { createMemoryStorage } from "@modern-js/runtime-utils/storer";
|
|
2
2
|
import { X_RENDER_CACHE } from "../../constants.mjs";
|
|
3
3
|
import { createTransformStream, getPathname } from "../../utils/index.mjs";
|
|
4
|
+
const preventsSharedCaching = (headers)=>/(?:^|,)\s*(?:private|no-store|no-cache)\s*(?:[=,]|$)/i.test(headers.get('cache-control') || '');
|
|
5
|
+
const isCacheableResponse = (response)=>200 === response.status && !preventsSharedCaching(response.headers) && !response.headers.has('set-cookie') && !response.headers.get('vary');
|
|
4
6
|
const removeTailSlash = (s)=>s.replace(/\/+$/, '');
|
|
5
7
|
const ZERO_RENDER_LEVEL = /"renderLevel":0/;
|
|
6
8
|
const NO_SSR_CACHE = /<meta\s+[^>]*name=["']no-ssr-cache["'][^>]*>/i;
|
|
7
9
|
async function processCache({ request, key, requestHandler, requestHandlerOptions, ttl, container, cacheStatus }) {
|
|
8
10
|
const response = await requestHandler(request, requestHandlerOptions);
|
|
9
11
|
const { onError } = requestHandlerOptions;
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
const deleteCache = async ()=>{
|
|
13
|
+
try {
|
|
14
|
+
await container.delete(key);
|
|
15
|
+
} catch {
|
|
16
|
+
(onError || console.error)('[render-cache] delete cache failed');
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
if (!isCacheableResponse(response) || !response.body) {
|
|
20
|
+
await deleteCache();
|
|
21
|
+
return response;
|
|
22
|
+
}
|
|
23
|
+
const headers = Object.fromEntries(response.headers);
|
|
22
24
|
const decoder = new TextDecoder();
|
|
23
25
|
if (response.body) {
|
|
24
26
|
const stream = createTransformStream();
|
|
25
27
|
const reader = response.body.getReader();
|
|
26
28
|
const writer = stream.writable.getWriter();
|
|
27
29
|
let html = '';
|
|
28
|
-
const push = ()=>reader.read().then(({ done, value })=>{
|
|
30
|
+
const push = ()=>reader.read().then(async ({ done, value })=>{
|
|
29
31
|
if (done) {
|
|
32
|
+
html += decoder.decode();
|
|
30
33
|
const match = ZERO_RENDER_LEVEL.test(html) || NO_SSR_CACHE.test(html);
|
|
31
|
-
if (match)
|
|
34
|
+
if (match) {
|
|
35
|
+
await deleteCache();
|
|
36
|
+
return writer.close();
|
|
37
|
+
}
|
|
32
38
|
const current = Date.now();
|
|
33
39
|
const cache = {
|
|
34
40
|
val: html,
|
|
35
|
-
cursor: current
|
|
41
|
+
cursor: current,
|
|
42
|
+
headers
|
|
36
43
|
};
|
|
37
44
|
container.set(key, JSON.stringify(cache), {
|
|
38
45
|
ttl
|
|
39
46
|
}).catch(()=>{
|
|
40
|
-
|
|
41
|
-
else console.error(`[render-cache] set cache failed, key: ${key}, value: ${JSON.stringify(cache)}`);
|
|
47
|
+
(onError || console.error)('[render-cache] set cache failed');
|
|
42
48
|
});
|
|
43
|
-
writer.close();
|
|
44
|
-
return;
|
|
49
|
+
return writer.close();
|
|
45
50
|
}
|
|
46
|
-
const content = decoder.decode(value
|
|
51
|
+
const content = decoder.decode(value, {
|
|
52
|
+
stream: true
|
|
53
|
+
});
|
|
47
54
|
html += content;
|
|
48
|
-
writer.write(value);
|
|
49
|
-
push();
|
|
55
|
+
await writer.write(value);
|
|
56
|
+
return push();
|
|
50
57
|
});
|
|
51
|
-
push()
|
|
58
|
+
push().catch(async (error)=>{
|
|
59
|
+
await Promise.allSettled([
|
|
60
|
+
writer.abort(error),
|
|
61
|
+
reader.cancel(error)
|
|
62
|
+
]);
|
|
63
|
+
(onError || console.error)('[render-cache] response stream failed');
|
|
64
|
+
});
|
|
52
65
|
cacheStatus && response.headers.set(X_RENDER_CACHE, cacheStatus);
|
|
53
66
|
return new Response(stream.readable, {
|
|
54
67
|
status: response.status,
|
|
@@ -63,9 +76,12 @@ function computedKey(req, cacheControl) {
|
|
|
63
76
|
const pathname = getPathname(req);
|
|
64
77
|
const { customKey } = cacheControl;
|
|
65
78
|
const defaultKey = '/' === pathname ? pathname : removeTailSlash(pathname);
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
if (customKey) if ('string' == typeof customKey) return customKey;
|
|
80
|
+
else return customKey(defaultKey);
|
|
81
|
+
else {
|
|
82
|
+
const url = new URL(req.url);
|
|
83
|
+
return `${url.origin}${defaultKey}${url.search}`;
|
|
84
|
+
}
|
|
69
85
|
}
|
|
70
86
|
function shouldUseCache(request) {
|
|
71
87
|
const url = new URL(request.url);
|
|
@@ -76,7 +92,7 @@ function shouldUseCache(request) {
|
|
|
76
92
|
}
|
|
77
93
|
function matchCacheControl(cacheOption, req) {
|
|
78
94
|
if (!cacheOption || !req) return;
|
|
79
|
-
{
|
|
95
|
+
else {
|
|
80
96
|
if (isCacheControl(cacheOption)) return cacheOption;
|
|
81
97
|
if (isCacheOptionProvider(cacheOption)) return cacheOption(req);
|
|
82
98
|
const url = req.url;
|
|
@@ -95,13 +111,15 @@ function matchCacheControl(cacheOption, req) {
|
|
|
95
111
|
async function getCacheResult(request, options) {
|
|
96
112
|
const { cacheControl, container = storage, requestHandler, requestHandlerOptions } = options;
|
|
97
113
|
const { onError } = requestHandlerOptions;
|
|
98
|
-
const
|
|
114
|
+
const hasCredentials = request.headers.has('cookie') || request.headers.has('authorization');
|
|
115
|
+
if ('GET' !== request.method || !shouldUseCache(request) || preventsSharedCaching(request.headers) || hasCredentials && !cacheControl.customKey) return requestHandler(request, requestHandlerOptions);
|
|
116
|
+
const key = `${CACHE_NAMESPACE}:v2:${computedKey(request, cacheControl)}`;
|
|
99
117
|
let value;
|
|
100
118
|
try {
|
|
101
119
|
value = await container.get(key);
|
|
102
120
|
} catch (_) {
|
|
103
|
-
if (onError) onError(
|
|
104
|
-
else console.error(
|
|
121
|
+
if (onError) onError('[render-cache] get cache failed');
|
|
122
|
+
else console.error('[render-cache] get cache failed');
|
|
105
123
|
value = void 0;
|
|
106
124
|
}
|
|
107
125
|
const { maxAge, staleWhileRevalidate } = cacheControl;
|
|
@@ -115,27 +133,27 @@ async function getCacheResult(request, options) {
|
|
|
115
133
|
container,
|
|
116
134
|
cacheStatus: 'miss'
|
|
117
135
|
});
|
|
118
|
-
{
|
|
136
|
+
else {
|
|
119
137
|
const cache = JSON.parse(value);
|
|
120
138
|
const interval = Date.now() - cache.cursor;
|
|
121
139
|
if (interval <= maxAge) {
|
|
122
140
|
const cacheStatus = 'hit';
|
|
123
141
|
return new Response(cache.val, {
|
|
124
142
|
headers: {
|
|
143
|
+
...cache.headers,
|
|
125
144
|
[X_RENDER_CACHE]: cacheStatus
|
|
126
145
|
}
|
|
127
146
|
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
{
|
|
147
|
+
} else {
|
|
148
|
+
if (!(interval <= staleWhileRevalidate + maxAge)) return processCache({
|
|
149
|
+
key,
|
|
150
|
+
request,
|
|
151
|
+
requestHandler,
|
|
152
|
+
requestHandlerOptions,
|
|
153
|
+
ttl,
|
|
154
|
+
container,
|
|
155
|
+
cacheStatus: 'expired'
|
|
156
|
+
});
|
|
139
157
|
processCache({
|
|
140
158
|
key,
|
|
141
159
|
request,
|
|
@@ -145,10 +163,13 @@ async function getCacheResult(request, options) {
|
|
|
145
163
|
container
|
|
146
164
|
}).then(async (response)=>{
|
|
147
165
|
await response.text();
|
|
166
|
+
}).catch(()=>{
|
|
167
|
+
(onError || console.error)('[render-cache] revalidation failed');
|
|
148
168
|
});
|
|
149
169
|
const cacheStatus = 'stale';
|
|
150
170
|
return new Response(cache.val, {
|
|
151
171
|
headers: {
|
|
172
|
+
...cache.headers,
|
|
152
173
|
[X_RENDER_CACHE]: cacheStatus
|
|
153
174
|
}
|
|
154
175
|
});
|