@modern-js/server-core
Version:
A Progressive React Framework for modern web development.
572 lines (571 loc) • 20.4 kB
JavaScript
import { _ as _async_to_generator } from "@swc/helpers/_/_async_to_generator";
import { _ as _define_property } from "@swc/helpers/_/_define_property";
import { _ as _instanceof } from "@swc/helpers/_/_instanceof";
import { _ as _object_spread } from "@swc/helpers/_/_object_spread";
import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props";
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array";
import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
import { cutNameByHyphen } from "@modern-js/utils/universal";
import { TrieRouter } from "hono/router/trie-router";
import { X_MODERNJS_RENDER } from "../../constants";
import { uniqueKeyByRoute } from "../../utils";
import { ErrorDigest, createErrorHtml, getPathname, getRuntimeEnv, parseHeaders, parseQuery, sortRoutes } from "../../utils";
import { csrRscRender } from "./csrRscRender";
import { dataHandler } from "./dataHandler";
import { renderRscHandler } from "./renderRscHandler";
import { serverActionHandler } from "./serverActionHandler";
import { ssrRender } from "./ssrRender";
var DYNAMIC_ROUTE_REG = /\/:./;
function getRouter(routes) {
var dynamicRoutes = [];
var normalRoutes = [];
routes.forEach(function(route2) {
if (DYNAMIC_ROUTE_REG.test(route2.urlPath)) {
dynamicRoutes.push(route2);
} else {
normalRoutes.push(route2);
}
});
var finalRoutes = _to_consumable_array(normalRoutes.sort(sortRoutes)).concat(_to_consumable_array(dynamicRoutes.sort(sortRoutes)));
var router = new TrieRouter();
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
try {
for (var _iterator = finalRoutes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var route = _step.value;
var originUrlPath = route.urlPath;
var urlPath = originUrlPath.endsWith("/") ? "".concat(originUrlPath, "*") : "".concat(originUrlPath, "/*");
router.add("*", urlPath, route);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return router;
}
function matchRoute(router, pathname, entryName) {
var matched = router.match("*", pathname);
if (entryName && matched[0].length > 1) {
var matches = matched[0];
var result = matches.find(function(param) {
var _param = _sliced_to_array(param, 1), route = _param[0];
return route.entryName === entryName;
});
return result || [];
} else {
var result1 = matched[0][0];
return result1 || [];
}
}
function getHeadersWithoutCookie(headers) {
var _headers = _object_spread_props(_object_spread({}, headers), {
cookie: void 0
});
delete _headers.cookie;
return _headers;
}
function createRender(_) {
return _createRender.apply(this, arguments);
}
function _createRender() {
_createRender = _async_to_generator(function(param) {
var routes, pwd, metaName, staticGenerate, cacheConfig, forceCSR, config, onFallback, router;
return _ts_generator(this, function(_state) {
routes = param.routes, pwd = param.pwd, metaName = param.metaName, staticGenerate = param.staticGenerate, cacheConfig = param.cacheConfig, forceCSR = param.forceCSR, config = param.config, onFallback = param.onFallback;
router = getRouter(routes);
return [
2,
function() {
var _ref = _async_to_generator(function(req, param2) {
var logger, reporter, metrics, monitors, nodeReq, templates, serverManifest, rscClientManifest, rscSSRManifest, rscServerManifest, locals, matchEntryName, matchPathname, loaderContext, forMatchpathname, _matchRoute, routeInfo, params, framework, fallbackHeader, fallbackReason, fallbackWrapper, html, renderMode, headerData, onError, onTiming, renderOptions, response, _tmp;
return _ts_generator(this, function(_state2) {
switch (_state2.label) {
case 0:
logger = param2.logger, reporter = param2.reporter, metrics = param2.metrics, monitors = param2.monitors, nodeReq = param2.nodeReq, templates = param2.templates, serverManifest = param2.serverManifest, rscClientManifest = param2.rscClientManifest, rscSSRManifest = param2.rscSSRManifest, rscServerManifest = param2.rscServerManifest, locals = param2.locals, matchEntryName = param2.matchEntryName, matchPathname = param2.matchPathname, loaderContext = param2.loaderContext;
forMatchpathname = matchPathname !== null && matchPathname !== void 0 ? matchPathname : getPathname(req);
_matchRoute = _sliced_to_array(matchRoute(router, forMatchpathname, matchEntryName), 2), routeInfo = _matchRoute[0], params = _matchRoute[1];
framework = cutNameByHyphen(metaName || "modern-js");
fallbackHeader = "x-".concat(framework, "-ssr-fallback");
fallbackReason = null;
fallbackWrapper = function() {
var _ref2 = _async_to_generator(function(reason, error) {
return _ts_generator(this, function(_state3) {
fallbackReason = reason;
return [
2,
onFallback === null || onFallback === void 0 ? void 0 : onFallback(reason, {
logger,
reporter,
metrics
}, error)
];
});
});
return function fallbackWrapper2(reason, error) {
return _ref2.apply(this, arguments);
};
}();
if (!routeInfo) {
return [
2,
new Response(createErrorHtml(404), {
status: 404,
headers: {
"content-type": "text/html; charset=UTF-8"
}
})
];
}
html = templates[uniqueKeyByRoute(routeInfo)];
if (!html) {
return [
2,
new Response(createErrorHtml(404), {
status: 404,
headers: {
"content-type": "text/html; charset=UTF-8"
}
})
];
}
return [
4,
getRenderMode(req, fallbackHeader, routeInfo.isSSR, forceCSR, nodeReq, fallbackWrapper)
];
case 1:
renderMode = _state2.sent();
headerData = parseHeaders(req);
onError = function(e, key) {
monitors === null || monitors === void 0 ? void 0 : monitors.error("SSR Error - ".concat(key || (_instanceof(e, Error) ? e.name : e), ", error = %s, req.url = %s, req.headers = %o"), _instanceof(e, Error) ? e.stack || e.message : e, forMatchpathname, getHeadersWithoutCookie(headerData));
};
onTiming = function(name, dur) {
monitors === null || monitors === void 0 ? void 0 : monitors.timing(name, dur, "SSR");
};
renderOptions = {
pwd,
html,
routeInfo,
staticGenerate: staticGenerate || false,
config,
nodeReq,
cacheConfig,
reporter,
serverRoutes: routes,
params,
logger,
metrics,
monitors,
locals,
rscClientManifest,
rscSSRManifest,
rscServerManifest,
serverManifest,
loaderContext: loaderContext || /* @__PURE__ */ new Map(),
onError,
onTiming
};
if (fallbackReason) {
renderOptions.html = injectFallbackReasonToHtml({
html: renderOptions.html,
reason: fallbackReason,
framework
});
}
switch (renderMode) {
case "data":
return [
3,
2
];
case "rsc-tree":
return [
3,
6
];
case "rsc-action":
return [
3,
8
];
case "ssr":
return [
3,
10
];
case "csr":
return [
3,
10
];
}
return [
3,
12
];
case 2:
return [
4,
dataHandler(req, renderOptions)
];
case 3:
_tmp = _state2.sent();
if (_tmp)
return [
3,
5
];
return [
4,
renderHandler(req, renderOptions, "ssr", fallbackWrapper, framework)
];
case 4:
_tmp = _state2.sent();
_state2.label = 5;
case 5:
response = _tmp;
return [
3,
13
];
case 6:
return [
4,
renderRscHandler(req, renderOptions)
];
case 7:
response = _state2.sent();
return [
3,
13
];
case 8:
return [
4,
serverActionHandler(req, renderOptions)
];
case 9:
response = _state2.sent();
return [
3,
13
];
case 10:
return [
4,
renderHandler(req, renderOptions, renderMode, fallbackWrapper, framework)
];
case 11:
response = _state2.sent();
return [
3,
13
];
case 12:
throw new Error("Unknown render mode: ".concat(renderMode));
case 13:
if (fallbackReason) {
response.headers.set(fallbackHeader, "1;reason=".concat(fallbackReason));
}
return [
2,
response
];
}
});
});
return function(req, _) {
return _ref.apply(this, arguments);
};
}()
];
});
});
return _createRender.apply(this, arguments);
}
function renderHandler(request, options, mode, fallbackWrapper, framework) {
return _renderHandler.apply(this, arguments);
}
function _renderHandler() {
_renderHandler = _async_to_generator(function(request, options, mode, fallbackWrapper, framework) {
var _options_config_server, response, serverManifest, ssrByRouteIds, runtimeEnv, nestedRoutesJson, routes, urlPath, pathToFileURL, matchRoutes, url, matchedRoutes, _lastMatch_route, lastMatch, e, routeInfo;
function applyExtendHeaders(r, route) {
Object.entries(route.responseHeaders || {}).forEach(function(param) {
var _param = _sliced_to_array(param, 2), k = _param[0], v = _param[1];
r.headers.set(k, v);
});
}
return _ts_generator(this, function(_state) {
switch (_state.label) {
case 0:
response = null;
serverManifest = options.serverManifest;
ssrByRouteIds = (_options_config_server = options.config.server) === null || _options_config_server === void 0 ? void 0 : _options_config_server.ssrByRouteIds;
runtimeEnv = getRuntimeEnv();
if (!(serverManifest.nestedRoutesJson && ssrByRouteIds && (ssrByRouteIds === null || ssrByRouteIds === void 0 ? void 0 : ssrByRouteIds.length) > 0 && runtimeEnv === "node"))
return [
3,
6
];
nestedRoutesJson = serverManifest.nestedRoutesJson;
routes = nestedRoutesJson === null || nestedRoutesJson === void 0 ? void 0 : nestedRoutesJson[options.routeInfo.entryName];
if (!routes)
return [
3,
6
];
urlPath = "node:url";
return [
4,
import(urlPath)
];
case 1:
pathToFileURL = _state.sent().pathToFileURL;
return [
4,
import(pathToFileURL(require.resolve("@modern-js/runtime-utils/remix-router")).href)
];
case 2:
matchRoutes = _state.sent().matchRoutes;
url = new URL(request.url);
matchedRoutes = matchRoutes(routes, url.pathname, options.routeInfo.urlPath);
if (!!matchedRoutes)
return [
3,
4
];
return [
4,
csrRender(request, options)
];
case 3:
response = _state.sent();
return [
3,
6
];
case 4:
lastMatch = matchedRoutes[matchedRoutes.length - 1];
if (!(!(lastMatch === null || lastMatch === void 0 ? void 0 : (_lastMatch_route = lastMatch.route) === null || _lastMatch_route === void 0 ? void 0 : _lastMatch_route.id) || !ssrByRouteIds.includes(lastMatch.route.id)))
return [
3,
6
];
return [
4,
csrRender(request, options)
];
case 5:
response = _state.sent();
_state.label = 6;
case 6:
if (!(mode === "ssr" && !response))
return [
3,
13
];
_state.label = 7;
case 7:
_state.trys.push([
7,
9,
,
12
]);
return [
4,
ssrRender(request, options)
];
case 8:
response = _state.sent();
return [
3,
12
];
case 9:
e = _state.sent();
options.onError(e, ErrorDigest.ERENDER);
return [
4,
fallbackWrapper("error", e)
];
case 10:
_state.sent();
return [
4,
csrRender(request, _object_spread_props(_object_spread({}, options), {
html: injectFallbackReasonToHtml({
html: options.html,
reason: "error",
framework
})
}))
];
case 11:
response = _state.sent();
return [
3,
12
];
case 12:
return [
3,
15
];
case 13:
return [
4,
csrRender(request, options)
];
case 14:
response = _state.sent();
_state.label = 15;
case 15:
routeInfo = options.routeInfo;
applyExtendHeaders(response, routeInfo);
return [
2,
response
];
}
});
});
return _renderHandler.apply(this, arguments);
}
function getRenderMode(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFallback) {
return _getRenderMode.apply(this, arguments);
}
function _getRenderMode() {
_getRenderMode = _async_to_generator(function(req, fallbackHeader, isSSR, forceCSR, nodeReq, onFallback) {
var query, fallbackHeaderValue, _fallbackHeaderValue_split_, reason;
return _ts_generator(this, function(_state) {
switch (_state.label) {
case 0:
query = parseQuery(req);
if (req.headers.get("x-rsc-action")) {
return [
2,
"rsc-action"
];
}
if (req.headers.get("x-rsc-tree")) {
return [
2,
"rsc-tree"
];
}
if (!isSSR)
return [
3,
6
];
if (query.__loader) {
return [
2,
"data"
];
}
fallbackHeaderValue = req.headers.get(fallbackHeader) || (nodeReq === null || nodeReq === void 0 ? void 0 : nodeReq.headers[fallbackHeader]);
if (!(forceCSR && (query.csr || fallbackHeaderValue)))
return [
3,
5
];
if (!query.csr)
return [
3,
2
];
return [
4,
onFallback === null || onFallback === void 0 ? void 0 : onFallback("query")
];
case 1:
_state.sent();
return [
3,
4
];
case 2:
reason = fallbackHeaderValue === null || fallbackHeaderValue === void 0 ? void 0 : (_fallbackHeaderValue_split_ = fallbackHeaderValue.split(";")[1]) === null || _fallbackHeaderValue_split_ === void 0 ? void 0 : _fallbackHeaderValue_split_.split("=")[1];
return [
4,
onFallback === null || onFallback === void 0 ? void 0 : onFallback(reason ? "header,".concat(reason) : "header")
];
case 3:
_state.sent();
_state.label = 4;
case 4:
return [
2,
"csr"
];
case 5:
return [
2,
"ssr"
];
case 6:
return [
2,
"csr"
];
case 7:
return [
2
];
}
});
});
return _getRenderMode.apply(this, arguments);
}
function injectFallbackReasonToHtml(param) {
var html = param.html, reason = param.reason, framework = param.framework;
var tag = '<script id="__'.concat(framework, '_ssr_fallback_reason__" type="application/json">').concat(JSON.stringify({
reason
}), "</script>");
return html.replace(/<\/head>/, "".concat(tag, "</head>"));
}
function csrRender(request, options) {
return _csrRender.apply(this, arguments);
}
function _csrRender() {
_csrRender = _async_to_generator(function(request, options) {
var html, rscClientManifest;
return _ts_generator(this, function(_state) {
html = options.html, rscClientManifest = options.rscClientManifest;
if (!rscClientManifest || process.env.MODERN_DISABLE_INJECT_RSC_DATA) {
return [
2,
new Response(html, {
status: 200,
headers: new Headers(_define_property({
"content-type": "text/html; charset=UTF-8"
}, X_MODERNJS_RENDER, "client"))
})
];
} else {
return [
2,
csrRscRender(request, options)
];
}
return [
2
];
});
});
return _csrRender.apply(this, arguments);
}
export {
createRender
};