@bleedingdev/modern-js-server-core 3.9.0-ultramodern.4 → 3.9.0-ultramodern.5
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/index.js +4 -0
- package/dist/cjs/adapters/node/plugins/static.js +107 -29
- package/dist/cjs/index.js +10 -34
- package/dist/cjs/plugins/compat/index.js +1 -0
- package/dist/cjs/serverBase.js +58 -17
- package/dist/cjs/utils/error.js +0 -10
- package/dist/esm/adapters/node/index.mjs +1 -0
- package/dist/esm/adapters/node/plugins/static.mjs +107 -32
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/plugins/compat/index.mjs +1 -0
- package/dist/esm/serverBase.mjs +58 -17
- package/dist/esm/utils/error.mjs +0 -1
- 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/index.mjs +1 -1
- package/dist/esm-node/plugins/compat/index.mjs +1 -0
- package/dist/esm-node/serverBase.mjs +58 -17
- package/dist/esm-node/utils/error.mjs +0 -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/utils/error.d.ts +0 -2
- package/package.json +5 -6
- 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/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/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
|
@@ -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
|
+
{
|
|
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/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(),
|
package/dist/esm/serverBase.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { server as server_server } from "@modern-js/plugin/server";
|
|
2
|
+
import { logger } from "@modern-js/utils";
|
|
2
3
|
import { Hono } from "hono";
|
|
3
4
|
import { run } from "./context.mjs";
|
|
4
5
|
import { handleSetupResult } from "./plugins/compat/hooks.mjs";
|
|
@@ -17,22 +18,54 @@ function _class_private_method_init(obj, privateSet) {
|
|
|
17
18
|
var _applyMiddlewares = /*#__PURE__*/ new WeakSet();
|
|
18
19
|
class ServerBase {
|
|
19
20
|
async init() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
try {
|
|
22
|
+
const { serverConfig, config: cliConfig } = this.serverOptions;
|
|
23
|
+
const mergedConfig = loadConfig({
|
|
24
|
+
cliConfig,
|
|
25
|
+
serverConfig: serverConfig || {}
|
|
26
|
+
});
|
|
27
|
+
const { serverContext } = await server_server.run({
|
|
28
|
+
plugins: this.plugins,
|
|
29
|
+
options: this.serverOptions,
|
|
30
|
+
config: mergedConfig,
|
|
31
|
+
handleSetupResult: handleSetupResult
|
|
32
|
+
});
|
|
33
|
+
serverContext.serverBase = this;
|
|
34
|
+
this.serverContext = serverContext;
|
|
35
|
+
await serverContext.hooks.onPrepare.call();
|
|
36
|
+
_class_private_method_get(this, _applyMiddlewares, applyMiddlewares).call(this);
|
|
37
|
+
return this;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
await this.dispose().catch((disposeError)=>{
|
|
40
|
+
logger.error(disposeError);
|
|
41
|
+
});
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
onDispose(disposer) {
|
|
46
|
+
if (this.disposePromise) throw new Error('Cannot register a disposer on a retired server.');
|
|
47
|
+
this.disposers.add(disposer);
|
|
48
|
+
return ()=>{
|
|
49
|
+
this.disposers.delete(disposer);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
dispose() {
|
|
53
|
+
if (!this.disposePromise) {
|
|
54
|
+
const disposers = [
|
|
55
|
+
...this.disposers
|
|
56
|
+
].reverse();
|
|
57
|
+
this.disposers.clear();
|
|
58
|
+
this.disposePromise = Promise.resolve().then(async ()=>{
|
|
59
|
+
const errors = [];
|
|
60
|
+
for (const disposer of disposers)try {
|
|
61
|
+
await disposer();
|
|
62
|
+
} catch (error) {
|
|
63
|
+
errors.push(error);
|
|
64
|
+
}
|
|
65
|
+
if (errors.length > 0) throw new AggregateError(errors, 'Failed to dispose server.');
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return this.disposePromise;
|
|
36
69
|
}
|
|
37
70
|
addPlugins(plugins) {
|
|
38
71
|
this.plugins.push(...plugins);
|
|
@@ -78,7 +111,15 @@ class ServerBase {
|
|
|
78
111
|
}
|
|
79
112
|
constructor(options){
|
|
80
113
|
_class_private_method_init(this, _applyMiddlewares);
|
|
81
|
-
this.plugins = [
|
|
114
|
+
this.plugins = [
|
|
115
|
+
{
|
|
116
|
+
name: '@modern-js/server-lifecycle',
|
|
117
|
+
_registryApi: ()=>({
|
|
118
|
+
onDispose: (disposer)=>this.onDispose(disposer)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
this.disposers = new Set();
|
|
82
123
|
this.serverContext = null;
|
|
83
124
|
this.serverOptions = options;
|
|
84
125
|
this.app = new Hono();
|
package/dist/esm/utils/error.mjs
CHANGED
|
@@ -50,5 +50,4 @@ function onError(digest, error, monitors, req) {
|
|
|
50
50
|
else if (req) console.error(`Server Error - ${digest}, error = ${error instanceof Error ? error.stack || error.message : error}, req.url = ${req.url}, req.headers = ${JSON.stringify(headerData)}`);
|
|
51
51
|
else console.error(`Server Error - ${digest}, error = ${error instanceof Error ? error.stack || error.message : error} `);
|
|
52
52
|
}
|
|
53
|
-
export { createSafeFailureHttpResult, createSafeJsonFailureResponse, getSafeFailureStatus } from "@modern-js/runtime-extensions/safe-failure";
|
|
54
53
|
export { createErrorHtml, error_ErrorDigest as ErrorDigest, onError };
|
|
@@ -3,3 +3,4 @@ export { loadCacheConfig, loadServerCliConfig, loadServerEnv, loadServerPlugins,
|
|
|
3
3
|
export { connectMid2HonoMid, connectMockMid2HonoMid, httpCallBack2HonoMid } from "./hono.mjs";
|
|
4
4
|
export { createNodeServer, createWebRequest, sendResponse } from "./node.mjs";
|
|
5
5
|
export { getHtmlTemplates, getServerManifest, injectNodeSeverPlugin, injectResourcePlugin, injectRscManifestPlugin, serverStaticPlugin } from "./plugins/index.mjs";
|
|
6
|
+
export { serveStaticAsset } from "./plugins/static.mjs";
|
|
@@ -1,9 +1,56 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import
|
|
2
|
+
import { fileReader } from "@modern-js/runtime-utils/fileReader";
|
|
3
|
+
import { fs } from "@modern-js/utils";
|
|
4
|
+
import { getMimeType } from "hono/utils/mime";
|
|
5
|
+
import path from "path";
|
|
3
6
|
import { sortRoutes } from "../../../utils/index.mjs";
|
|
4
7
|
import { getPublicDirPatterns } from "../../../utils/publicDir.mjs";
|
|
5
|
-
|
|
6
|
-
const
|
|
8
|
+
const isPathInside = (target, root)=>{
|
|
9
|
+
const relative = path.relative(path.resolve(root), path.resolve(target));
|
|
10
|
+
return '' === relative || !relative.startsWith(`..${path.sep}`) && '..' !== relative && !path.isAbsolute(relative);
|
|
11
|
+
};
|
|
12
|
+
async function serveStaticAsset(context, asset, respond) {
|
|
13
|
+
let { filename } = asset;
|
|
14
|
+
const { kind } = asset;
|
|
15
|
+
if (asset.root && !isPathInside(filename, asset.root)) return null;
|
|
16
|
+
if (asset.realpath) try {
|
|
17
|
+
const [realFilename, realRoot, stat] = await Promise.all([
|
|
18
|
+
fs.realpath(filename),
|
|
19
|
+
asset.root ? fs.realpath(asset.root) : Promise.resolve(void 0),
|
|
20
|
+
fs.stat(filename)
|
|
21
|
+
]);
|
|
22
|
+
if (!stat.isFile() || realRoot && !isPathInside(realFilename, realRoot)) return null;
|
|
23
|
+
filename = realFilename;
|
|
24
|
+
asset = {
|
|
25
|
+
...asset,
|
|
26
|
+
filename,
|
|
27
|
+
root: realRoot
|
|
28
|
+
};
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if ('static' === kind && !await fs.pathExists(filename)) return null;
|
|
33
|
+
if (respond) return respond(asset, (representation)=>serveStaticAsset(context, {
|
|
34
|
+
...asset,
|
|
35
|
+
...representation,
|
|
36
|
+
filename: representation?.filename ?? asset.filename,
|
|
37
|
+
mimeFilename: asset.mimeFilename ?? filename
|
|
38
|
+
}));
|
|
39
|
+
const mimeType = getMimeType(asset.mimeFilename ?? filename);
|
|
40
|
+
if ('static' === kind && mimeType) context.header('Content-Type', mimeType);
|
|
41
|
+
const size = 'static' === kind ? (await fs.lstat(filename)).size : void 0;
|
|
42
|
+
const data = 'static' === kind ? await fileReader.readFileFromSystem(filename, 'buffer') : await fileReader.readFile(filename, 'buffer');
|
|
43
|
+
if ('static' === kind && (asset.contentLength ?? true)) context.header('Content-Length', String(true === asset.contentLength && data ? data.byteLength : size));
|
|
44
|
+
if (null === data) return null;
|
|
45
|
+
if ('public' === kind && mimeType) context.header('Content-Type', mimeType);
|
|
46
|
+
Object.entries(asset.responseHeaders || {}).forEach(([key, value])=>{
|
|
47
|
+
context.header(key, value);
|
|
48
|
+
});
|
|
49
|
+
if ('public' === kind && asset.contentLength) context.header('Content-Length', String(data.byteLength));
|
|
50
|
+
const body = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
51
|
+
return context.body(body, 200);
|
|
52
|
+
}
|
|
53
|
+
const serverStaticPlugin = (options = {})=>({
|
|
7
54
|
name: '@modern-js/plugin-server-static',
|
|
8
55
|
setup (api) {
|
|
9
56
|
api.onPrepare(()=>{
|
|
@@ -14,7 +61,9 @@ const serverStaticPlugin = ()=>({
|
|
|
14
61
|
routes,
|
|
15
62
|
output: config.output || {},
|
|
16
63
|
html: config.html || {},
|
|
17
|
-
server: config.server || {}
|
|
64
|
+
server: config.server || {},
|
|
65
|
+
...api.getServerContext().staticAssetResponders,
|
|
66
|
+
...options
|
|
18
67
|
});
|
|
19
68
|
middlewares.push({
|
|
20
69
|
name: 'server-static',
|
|
@@ -23,16 +72,33 @@ const serverStaticPlugin = ()=>({
|
|
|
23
72
|
});
|
|
24
73
|
}
|
|
25
74
|
});
|
|
26
|
-
function createPublicMiddleware({ pwd, routes }) {
|
|
75
|
+
function createPublicMiddleware({ pwd, routes, pathPrefix = '/', respondAsset, respondPublicFallback }) {
|
|
27
76
|
return async (c, next)=>{
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
77
|
+
const respondPublic = async ()=>{
|
|
78
|
+
const route = matchPublicRoute(c.req, routes);
|
|
79
|
+
if (!route) return null;
|
|
80
|
+
const asset = {
|
|
81
|
+
filename: path.join(pwd, route.entryPath),
|
|
82
|
+
kind: 'public',
|
|
83
|
+
responseHeaders: route.responseHeaders
|
|
84
|
+
};
|
|
85
|
+
const serve = (representation)=>serveStaticAsset(c, {
|
|
86
|
+
...asset,
|
|
87
|
+
...representation,
|
|
88
|
+
filename: representation?.filename ?? asset.filename,
|
|
89
|
+
mimeFilename: asset.filename
|
|
90
|
+
});
|
|
91
|
+
const response = respondAsset ? await respondAsset(c, asset, serve, {
|
|
92
|
+
root: pwd,
|
|
93
|
+
pathPrefix
|
|
94
|
+
}) : void 0;
|
|
95
|
+
return void 0 === response ? serve() : response;
|
|
96
|
+
};
|
|
97
|
+
const response = respondPublicFallback ? await respondPublicFallback(c, respondPublic, {
|
|
98
|
+
root: pwd,
|
|
99
|
+
pathPrefix
|
|
100
|
+
}) : await respondPublic();
|
|
101
|
+
return response ?? next();
|
|
36
102
|
};
|
|
37
103
|
}
|
|
38
104
|
function matchPublicRoute(req, routes) {
|
|
@@ -77,29 +143,38 @@ function createStaticMiddleware(options) {
|
|
|
77
143
|
...staticReg,
|
|
78
144
|
...iconReg
|
|
79
145
|
].join('|')})`);
|
|
80
|
-
const publicMiddleware = createPublicMiddleware({
|
|
81
|
-
pwd,
|
|
82
|
-
routes: routes || []
|
|
83
|
-
});
|
|
84
|
-
const moduleFederationStaticServing = createModuleFederationStaticServing({
|
|
85
|
-
pwd,
|
|
86
|
-
pathPrefix
|
|
87
|
-
});
|
|
88
146
|
return async (c, next)=>{
|
|
89
147
|
const pageRoute = c.get('route');
|
|
90
148
|
const pathname = c.req.path;
|
|
91
|
-
if (pageRoute && '' ===
|
|
149
|
+
if (pageRoute && '' === path.extname(pathname)) return next();
|
|
92
150
|
const hit = staticPathRegExp.test(pathname);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
151
|
+
if (!hit) return createPublicMiddleware({
|
|
152
|
+
pwd,
|
|
153
|
+
routes: routes || [],
|
|
154
|
+
pathPrefix,
|
|
155
|
+
respondAsset: options.respondAsset,
|
|
156
|
+
respondPublicFallback: options.respondPublicFallback
|
|
157
|
+
})(c, next);
|
|
158
|
+
{
|
|
159
|
+
const filepath = path.join(pwd, pathname.replace(pathPrefix, ()=>''));
|
|
160
|
+
if (!isPathInside(filepath, pwd)) return next();
|
|
161
|
+
if (!await fs.pathExists(filepath)) return next();
|
|
162
|
+
const asset = {
|
|
163
|
+
filename: filepath,
|
|
164
|
+
kind: 'static'
|
|
165
|
+
};
|
|
166
|
+
const serve = (representation)=>serveStaticAsset(c, {
|
|
167
|
+
...asset,
|
|
168
|
+
...representation,
|
|
169
|
+
filename: representation?.filename ?? asset.filename,
|
|
170
|
+
mimeFilename: filepath
|
|
171
|
+
});
|
|
172
|
+
const response = options.respondAsset ? await options.respondAsset(c, asset, serve, {
|
|
173
|
+
root: pwd,
|
|
174
|
+
pathPrefix
|
|
175
|
+
}) : void 0;
|
|
176
|
+
return (void 0 === response ? await serve() : response) ?? next();
|
|
99
177
|
}
|
|
100
|
-
const moduleFederationResponse = await moduleFederationStaticServing.serveModuleFederationAsset(c, staticServingRequest);
|
|
101
|
-
if (null !== moduleFederationResponse) return moduleFederationResponse;
|
|
102
|
-
return publicMiddleware(c, next);
|
|
103
178
|
};
|
|
104
179
|
}
|
|
105
180
|
const prepareFavicons = (favicon)=>{
|
|
@@ -107,4 +182,4 @@ const prepareFavicons = (favicon)=>{
|
|
|
107
182
|
if (favicon && 'string' == typeof favicon) faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
|
|
108
183
|
return faviconNames;
|
|
109
184
|
};
|
|
110
|
-
export { createPublicMiddleware, createStaticMiddleware, serverStaticPlugin };
|
|
185
|
+
export { createPublicMiddleware, createStaticMiddleware, serveStaticAsset, serverStaticPlugin };
|
package/dist/esm-node/index.mjs
CHANGED
|
@@ -9,5 +9,5 @@ export { AGGRED_DIR } from "./constants.mjs";
|
|
|
9
9
|
export { run, useHonoContext } from "./context.mjs";
|
|
10
10
|
export { getLoaderCtx } from "./helper.mjs";
|
|
11
11
|
export { createServerBase } from "./serverBase.mjs";
|
|
12
|
-
export { ErrorDigest, createErrorHtml,
|
|
12
|
+
export { ErrorDigest, createErrorHtml, onError } from "./utils/index.mjs";
|
|
13
13
|
export { getPublicDirConfig, getPublicDirPatterns, getPublicDirRoutePrefixes, normalizePublicDir, normalizePublicDirPath, resolvePublicDirPaths } from "./utils/publicDir.mjs";
|
|
@@ -4,6 +4,7 @@ import { getHookRunners, handleSetupResult } from "./hooks.mjs";
|
|
|
4
4
|
const compatPlugin = ()=>({
|
|
5
5
|
name: '@modern-js/server-compat',
|
|
6
6
|
registryHooks: {
|
|
7
|
+
handleError: createAsyncPipelineHook(),
|
|
7
8
|
prepareWebServer: createAsyncPipelineHook(),
|
|
8
9
|
prepareApiServer: createAsyncPipelineHook(),
|
|
9
10
|
afterMatch: createAsyncPipelineHook(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { server as server_server } from "@modern-js/plugin/server";
|
|
3
|
+
import { logger } from "@modern-js/utils";
|
|
3
4
|
import { Hono } from "hono";
|
|
4
5
|
import { run } from "./context.mjs";
|
|
5
6
|
import { handleSetupResult } from "./plugins/compat/hooks.mjs";
|
|
@@ -18,22 +19,54 @@ function _class_private_method_init(obj, privateSet) {
|
|
|
18
19
|
var _applyMiddlewares = /*#__PURE__*/ new WeakSet();
|
|
19
20
|
class ServerBase {
|
|
20
21
|
async init() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
try {
|
|
23
|
+
const { serverConfig, config: cliConfig } = this.serverOptions;
|
|
24
|
+
const mergedConfig = loadConfig({
|
|
25
|
+
cliConfig,
|
|
26
|
+
serverConfig: serverConfig || {}
|
|
27
|
+
});
|
|
28
|
+
const { serverContext } = await server_server.run({
|
|
29
|
+
plugins: this.plugins,
|
|
30
|
+
options: this.serverOptions,
|
|
31
|
+
config: mergedConfig,
|
|
32
|
+
handleSetupResult: handleSetupResult
|
|
33
|
+
});
|
|
34
|
+
serverContext.serverBase = this;
|
|
35
|
+
this.serverContext = serverContext;
|
|
36
|
+
await serverContext.hooks.onPrepare.call();
|
|
37
|
+
_class_private_method_get(this, _applyMiddlewares, applyMiddlewares).call(this);
|
|
38
|
+
return this;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
await this.dispose().catch((disposeError)=>{
|
|
41
|
+
logger.error(disposeError);
|
|
42
|
+
});
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
onDispose(disposer) {
|
|
47
|
+
if (this.disposePromise) throw new Error('Cannot register a disposer on a retired server.');
|
|
48
|
+
this.disposers.add(disposer);
|
|
49
|
+
return ()=>{
|
|
50
|
+
this.disposers.delete(disposer);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
dispose() {
|
|
54
|
+
if (!this.disposePromise) {
|
|
55
|
+
const disposers = [
|
|
56
|
+
...this.disposers
|
|
57
|
+
].reverse();
|
|
58
|
+
this.disposers.clear();
|
|
59
|
+
this.disposePromise = Promise.resolve().then(async ()=>{
|
|
60
|
+
const errors = [];
|
|
61
|
+
for (const disposer of disposers)try {
|
|
62
|
+
await disposer();
|
|
63
|
+
} catch (error) {
|
|
64
|
+
errors.push(error);
|
|
65
|
+
}
|
|
66
|
+
if (errors.length > 0) throw new AggregateError(errors, 'Failed to dispose server.');
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return this.disposePromise;
|
|
37
70
|
}
|
|
38
71
|
addPlugins(plugins) {
|
|
39
72
|
this.plugins.push(...plugins);
|
|
@@ -79,7 +112,15 @@ class ServerBase {
|
|
|
79
112
|
}
|
|
80
113
|
constructor(options){
|
|
81
114
|
_class_private_method_init(this, _applyMiddlewares);
|
|
82
|
-
this.plugins = [
|
|
115
|
+
this.plugins = [
|
|
116
|
+
{
|
|
117
|
+
name: '@modern-js/server-lifecycle',
|
|
118
|
+
_registryApi: ()=>({
|
|
119
|
+
onDispose: (disposer)=>this.onDispose(disposer)
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
];
|
|
123
|
+
this.disposers = new Set();
|
|
83
124
|
this.serverContext = null;
|
|
84
125
|
this.serverOptions = options;
|
|
85
126
|
this.app = new Hono();
|
|
@@ -51,5 +51,4 @@ function onError(digest, error, monitors, req) {
|
|
|
51
51
|
else if (req) console.error(`Server Error - ${digest}, error = ${error instanceof Error ? error.stack || error.message : error}, req.url = ${req.url}, req.headers = ${JSON.stringify(headerData)}`);
|
|
52
52
|
else console.error(`Server Error - ${digest}, error = ${error instanceof Error ? error.stack || error.message : error} `);
|
|
53
53
|
}
|
|
54
|
-
export { createSafeFailureHttpResult, createSafeJsonFailureResponse, getSafeFailureStatus } from "@modern-js/runtime-extensions/safe-failure";
|
|
55
54
|
export { createErrorHtml, error_ErrorDigest as ErrorDigest, onError };
|
|
@@ -3,3 +3,5 @@ export type { ServerNodeContext, ServerNodeMiddleware } from './hono.js';
|
|
|
3
3
|
export { connectMid2HonoMid, connectMockMid2HonoMid, httpCallBack2HonoMid, } from './hono.js';
|
|
4
4
|
export { createNodeServer, createWebRequest, sendResponse, } from './node.js';
|
|
5
5
|
export { getHtmlTemplates, getServerManifest, injectNodeSeverPlugin, injectResourcePlugin, injectRscManifestPlugin, serverStaticPlugin, } from './plugins/index.js';
|
|
6
|
+
export type { ServerStaticPluginOptions, ServeStaticAsset, StaticAsset, StaticAssetRequest, StaticAssetResponder, StaticPublicFallbackResponder, } from './plugins/static.js';
|
|
7
|
+
export { serveStaticAsset } from './plugins/static.js';
|