UNPKG

@modern-js/server-core

Version:

A Progressive React Framework for modern web development.

572 lines (571 loc) • 20.4 kB
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 };