renderer.mjs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. import process from 'node:process';globalThis._importMeta_=globalThis._importMeta_||{url:"file:///_entry.js",env:process.env};import { getRequestDependencies, getPreloadLinks, getPrefetchLinks, createRenderer } from 'vue-bundle-renderer/runtime';
  2. import { u as useRuntimeConfig, g as eventHandler, k as setResponseHeader, l as send, m as getResponseStatus, n as setResponseStatus, o as setResponseHeaders, q as useNitroApp, r as joinRelativeURL, v as getQuery, e as createError, x as getRouteRules, y as getResponseStatusText } from './index.mjs';
  3. import { stringify, uneval } from 'devalue';
  4. import { renderToString } from 'vue/server-renderer';
  5. import { propsToString, renderSSRHead } from '@unhead/ssr';
  6. import { createServerHead as createServerHead$1, CapoPlugin } from 'unhead';
  7. import { version, unref } from 'vue';
  8. import { defineHeadPlugin } from '@unhead/shared';
  9. function defineRenderHandler(handler) {
  10. const runtimeConfig = useRuntimeConfig();
  11. return eventHandler(async (event) => {
  12. if (event.path === `${runtimeConfig.app.baseURL}favicon.ico`) {
  13. setResponseHeader(event, "Content-Type", "image/x-icon");
  14. return send(
  15. event,
  16. "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
  17. );
  18. }
  19. const response = await handler(event);
  20. if (!response) {
  21. const _currentStatus = getResponseStatus(event);
  22. setResponseStatus(event, _currentStatus === 200 ? 500 : _currentStatus);
  23. return send(
  24. event,
  25. "No response returned from render handler: " + event.path
  26. );
  27. }
  28. const nitroApp = useNitroApp();
  29. await nitroApp.hooks.callHook("render:response", response, { event });
  30. if (response.headers) {
  31. setResponseHeaders(event, response.headers);
  32. }
  33. if (response.statusCode || response.statusMessage) {
  34. setResponseStatus(event, response.statusCode, response.statusMessage);
  35. }
  36. return response.body;
  37. });
  38. }
  39. const Vue3 = version[0] === "3";
  40. function resolveUnref(r) {
  41. return typeof r === "function" ? r() : unref(r);
  42. }
  43. function resolveUnrefHeadInput(ref) {
  44. if (ref instanceof Promise || ref instanceof Date || ref instanceof RegExp)
  45. return ref;
  46. const root = resolveUnref(ref);
  47. if (!ref || !root)
  48. return root;
  49. if (Array.isArray(root))
  50. return root.map((r) => resolveUnrefHeadInput(r));
  51. if (typeof root === "object") {
  52. const resolved = {};
  53. for (const k in root) {
  54. if (!Object.prototype.hasOwnProperty.call(root, k)) {
  55. continue;
  56. }
  57. if (k === "titleTemplate" || k[0] === "o" && k[1] === "n") {
  58. resolved[k] = unref(root[k]);
  59. continue;
  60. }
  61. resolved[k] = resolveUnrefHeadInput(root[k]);
  62. }
  63. return resolved;
  64. }
  65. return root;
  66. }
  67. const VueReactivityPlugin = defineHeadPlugin({
  68. hooks: {
  69. "entries:resolve": (ctx) => {
  70. for (const entry of ctx.entries)
  71. entry.resolvedInput = resolveUnrefHeadInput(entry.input);
  72. }
  73. }
  74. });
  75. const headSymbol = "usehead";
  76. function vueInstall(head) {
  77. const plugin = {
  78. install(app) {
  79. if (Vue3) {
  80. app.config.globalProperties.$unhead = head;
  81. app.config.globalProperties.$head = head;
  82. app.provide(headSymbol, head);
  83. }
  84. }
  85. };
  86. return plugin.install;
  87. }
  88. function createServerHead(options = {}) {
  89. const head = createServerHead$1(options);
  90. head.use(VueReactivityPlugin);
  91. head.install = vueInstall(head);
  92. return head;
  93. }
  94. const unheadPlugins = true ? [CapoPlugin({ track: true })] : [];
  95. const renderSSRHeadOptions = {"omitLineBreaks":false};
  96. const appHead = {"meta":[{"name":"viewport","content":"width=device-width, initial-scale=1"},{"charset":"utf-8"}],"link":[],"style":[],"script":[],"noscript":[]};
  97. const appRootTag = "div";
  98. const appRootAttrs = {"id":"__nuxt"};
  99. const appTeleportTag = "div";
  100. const appTeleportAttrs = {"id":"teleports"};
  101. const componentIslands = false;
  102. const appId = "nuxt-app";
  103. function baseURL() {
  104. return useRuntimeConfig().app.baseURL;
  105. }
  106. function buildAssetsDir() {
  107. return useRuntimeConfig().app.buildAssetsDir;
  108. }
  109. function buildAssetsURL(...path) {
  110. return joinRelativeURL(publicAssetsURL(), buildAssetsDir(), ...path);
  111. }
  112. function publicAssetsURL(...path) {
  113. const app = useRuntimeConfig().app;
  114. const publicBase = app.cdnURL || app.baseURL;
  115. return path.length ? joinRelativeURL(publicBase, ...path) : publicBase;
  116. }
  117. globalThis.__buildAssetsURL = buildAssetsURL;
  118. globalThis.__publicAssetsURL = publicAssetsURL;
  119. const getClientManifest = () => import('../build/client.manifest.mjs').then((r) => r.default || r).then((r) => typeof r === "function" ? r() : r);
  120. const getEntryIds = () => getClientManifest().then((r) => Object.values(r).filter(
  121. (r2) => (
  122. // @ts-expect-error internal key set by CSS inlining configuration
  123. r2._globalCSS
  124. )
  125. ).map((r2) => r2.src));
  126. const getServerEntry = () => import('../build/server.mjs').then((r) => r.default || r);
  127. const getSSRStyles = lazyCachedFunction(() => import('../build/styles.mjs').then((r) => r.default || r));
  128. const getSSRRenderer = lazyCachedFunction(async () => {
  129. const manifest = await getClientManifest();
  130. if (!manifest) {
  131. throw new Error("client.manifest is not available");
  132. }
  133. const createSSRApp = await getServerEntry();
  134. if (!createSSRApp) {
  135. throw new Error("Server bundle is not available");
  136. }
  137. const options = {
  138. manifest,
  139. renderToString: renderToString$1,
  140. buildAssetsURL
  141. };
  142. const renderer = createRenderer(createSSRApp, options);
  143. async function renderToString$1(input, context) {
  144. const html = await renderToString(input, context);
  145. return APP_ROOT_OPEN_TAG + html + APP_ROOT_CLOSE_TAG;
  146. }
  147. return renderer;
  148. });
  149. const getSPARenderer = lazyCachedFunction(async () => {
  150. const manifest = await getClientManifest();
  151. const spaTemplate = await import('../virtual/_virtual_spa-template.mjs').then((r) => r.template).catch(() => "").then((r) => APP_ROOT_OPEN_TAG + r + APP_ROOT_CLOSE_TAG);
  152. const options = {
  153. manifest,
  154. renderToString: () => spaTemplate,
  155. buildAssetsURL
  156. };
  157. const renderer = createRenderer(() => () => {
  158. }, options);
  159. const result = await renderer.renderToString({});
  160. const renderToString = (ssrContext) => {
  161. const config = useRuntimeConfig(ssrContext.event);
  162. ssrContext.modules = ssrContext.modules || /* @__PURE__ */ new Set();
  163. ssrContext.payload.serverRendered = false;
  164. ssrContext.config = {
  165. public: config.public,
  166. app: config.app
  167. };
  168. return Promise.resolve(result);
  169. };
  170. return {
  171. rendererContext: renderer.rendererContext,
  172. renderToString
  173. };
  174. });
  175. const HAS_APP_TELEPORTS = !!(appTeleportAttrs.id);
  176. const APP_TELEPORT_OPEN_TAG = HAS_APP_TELEPORTS ? `<${appTeleportTag}${propsToString(appTeleportAttrs)}>` : "";
  177. const APP_TELEPORT_CLOSE_TAG = HAS_APP_TELEPORTS ? `</${appTeleportTag}>` : "";
  178. const APP_ROOT_OPEN_TAG = `<${appRootTag}${propsToString(appRootAttrs)}>`;
  179. const APP_ROOT_CLOSE_TAG = `</${appRootTag}>`;
  180. const PAYLOAD_URL_RE = /\/_payload.json(\?.*)?$/ ;
  181. const renderer = defineRenderHandler(async (event) => {
  182. const nitroApp = useNitroApp();
  183. const ssrError = event.path.startsWith("/__nuxt_error") ? getQuery(event) : null;
  184. if (ssrError && ssrError.statusCode) {
  185. ssrError.statusCode = Number.parseInt(ssrError.statusCode);
  186. }
  187. if (ssrError && !("__unenv__" in event.node.req)) {
  188. throw createError({
  189. statusCode: 404,
  190. statusMessage: "Page Not Found: /__nuxt_error"
  191. });
  192. }
  193. const isRenderingIsland = componentIslands;
  194. const islandContext = void 0;
  195. let url = ssrError?.url || islandContext?.url || event.path;
  196. const isRenderingPayload = PAYLOAD_URL_RE.test(url) && !isRenderingIsland;
  197. if (isRenderingPayload) {
  198. url = url.substring(0, url.lastIndexOf("/")) || "/";
  199. event._path = url;
  200. event.node.req.url = url;
  201. }
  202. const routeOptions = getRouteRules(event);
  203. const head = createServerHead({
  204. plugins: unheadPlugins
  205. });
  206. const headEntryOptions = { mode: "server" };
  207. {
  208. head.push(appHead, headEntryOptions);
  209. }
  210. const ssrContext = {
  211. url,
  212. event,
  213. runtimeConfig: useRuntimeConfig(event),
  214. noSSR: event.context.nuxt?.noSSR || routeOptions.ssr === false && !isRenderingIsland || (false),
  215. head,
  216. error: !!ssrError,
  217. nuxt: void 0,
  218. /* NuxtApp */
  219. payload: ssrError ? { error: ssrError } : {},
  220. _payloadReducers: /* @__PURE__ */ Object.create(null),
  221. modules: /* @__PURE__ */ new Set(),
  222. islandContext
  223. };
  224. const renderer = ssrContext.noSSR ? await getSPARenderer() : await getSSRRenderer();
  225. {
  226. for (const id of await getEntryIds()) {
  227. ssrContext.modules.add(id);
  228. }
  229. }
  230. const _rendered = await renderer.renderToString(ssrContext).catch(async (error) => {
  231. if (ssrContext._renderResponse && error.message === "skipping render") {
  232. return {};
  233. }
  234. const _err = !ssrError && ssrContext.payload?.error || error;
  235. await ssrContext.nuxt?.hooks.callHook("app:error", _err);
  236. throw _err;
  237. });
  238. await ssrContext.nuxt?.hooks.callHook("app:rendered", { ssrContext, renderResult: _rendered });
  239. if (ssrContext._renderResponse) {
  240. return ssrContext._renderResponse;
  241. }
  242. if (ssrContext.payload?.error && !ssrError) {
  243. throw ssrContext.payload.error;
  244. }
  245. if (isRenderingPayload) {
  246. const response2 = renderPayloadResponse(ssrContext);
  247. return response2;
  248. }
  249. const inlinedStyles = await renderInlineStyles(ssrContext.modules ?? []) ;
  250. const NO_SCRIPTS = routeOptions.experimentalNoScripts;
  251. const { styles, scripts } = getRequestDependencies(ssrContext, renderer.rendererContext);
  252. if (inlinedStyles.length) {
  253. head.push({ style: inlinedStyles });
  254. }
  255. {
  256. const link = [];
  257. for (const style in styles) {
  258. const resource = styles[style];
  259. {
  260. link.push({ rel: "stylesheet", href: renderer.rendererContext.buildAssetsURL(resource.file) });
  261. }
  262. }
  263. if (link.length) {
  264. head.push({ link }, headEntryOptions);
  265. }
  266. }
  267. if (!NO_SCRIPTS && !isRenderingIsland) {
  268. head.push({
  269. link: getPreloadLinks(ssrContext, renderer.rendererContext)
  270. }, headEntryOptions);
  271. head.push({
  272. link: getPrefetchLinks(ssrContext, renderer.rendererContext)
  273. }, headEntryOptions);
  274. head.push({
  275. script: renderPayloadJsonScript({ ssrContext, data: ssrContext.payload })
  276. }, {
  277. ...headEntryOptions,
  278. // this should come before another end of body scripts
  279. tagPosition: "bodyClose",
  280. tagPriority: "high"
  281. });
  282. }
  283. if (!routeOptions.experimentalNoScripts && !isRenderingIsland) {
  284. head.push({
  285. script: Object.values(scripts).map((resource) => ({
  286. type: resource.module ? "module" : null,
  287. src: renderer.rendererContext.buildAssetsURL(resource.file),
  288. defer: resource.module ? null : true,
  289. // if we are rendering script tag payloads that import an async payload
  290. // we need to ensure this resolves before executing the Nuxt entry
  291. tagPosition: "head",
  292. crossorigin: ""
  293. }))
  294. }, headEntryOptions);
  295. }
  296. const { headTags, bodyTags, bodyTagsOpen, htmlAttrs, bodyAttrs } = await renderSSRHead(head, renderSSRHeadOptions);
  297. const htmlContext = {
  298. island: isRenderingIsland,
  299. htmlAttrs: htmlAttrs ? [htmlAttrs] : [],
  300. head: normalizeChunks([headTags]),
  301. bodyAttrs: bodyAttrs ? [bodyAttrs] : [],
  302. bodyPrepend: normalizeChunks([bodyTagsOpen, ssrContext.teleports?.body]),
  303. body: [
  304. _rendered.html,
  305. APP_TELEPORT_OPEN_TAG + (HAS_APP_TELEPORTS ? joinTags([ssrContext.teleports?.[`#${appTeleportAttrs.id}`]]) : "") + APP_TELEPORT_CLOSE_TAG
  306. ],
  307. bodyAppend: [bodyTags]
  308. };
  309. await nitroApp.hooks.callHook("render:html", htmlContext, { event });
  310. const response = {
  311. body: renderHTMLDocument(htmlContext),
  312. statusCode: getResponseStatus(event),
  313. statusMessage: getResponseStatusText(event),
  314. headers: {
  315. "content-type": "text/html;charset=utf-8",
  316. "x-powered-by": "Nuxt"
  317. }
  318. };
  319. return response;
  320. });
  321. function lazyCachedFunction(fn) {
  322. let res = null;
  323. return () => {
  324. if (res === null) {
  325. res = fn().catch((err) => {
  326. res = null;
  327. throw err;
  328. });
  329. }
  330. return res;
  331. };
  332. }
  333. function normalizeChunks(chunks) {
  334. return chunks.filter(Boolean).map((i) => i.trim());
  335. }
  336. function joinTags(tags) {
  337. return tags.join("");
  338. }
  339. function joinAttrs(chunks) {
  340. if (chunks.length === 0) {
  341. return "";
  342. }
  343. return " " + chunks.join(" ");
  344. }
  345. function renderHTMLDocument(html) {
  346. return `<!DOCTYPE html><html${joinAttrs(html.htmlAttrs)}><head>${joinTags(html.head)}</head><body${joinAttrs(html.bodyAttrs)}>${joinTags(html.bodyPrepend)}${joinTags(html.body)}${joinTags(html.bodyAppend)}</body></html>`;
  347. }
  348. async function renderInlineStyles(usedModules) {
  349. const styleMap = await getSSRStyles();
  350. const inlinedStyles = /* @__PURE__ */ new Set();
  351. for (const mod of usedModules) {
  352. if (mod in styleMap) {
  353. for (const style of await styleMap[mod]()) {
  354. inlinedStyles.add(style);
  355. }
  356. }
  357. }
  358. return Array.from(inlinedStyles).map((style) => ({ innerHTML: style }));
  359. }
  360. function renderPayloadResponse(ssrContext) {
  361. return {
  362. body: stringify(splitPayload(ssrContext).payload, ssrContext._payloadReducers) ,
  363. statusCode: getResponseStatus(ssrContext.event),
  364. statusMessage: getResponseStatusText(ssrContext.event),
  365. headers: {
  366. "content-type": "application/json;charset=utf-8" ,
  367. "x-powered-by": "Nuxt"
  368. }
  369. };
  370. }
  371. function renderPayloadJsonScript(opts) {
  372. const contents = opts.data ? stringify(opts.data, opts.ssrContext._payloadReducers) : "";
  373. const payload = {
  374. "type": "application/json",
  375. "innerHTML": contents,
  376. "data-nuxt-data": appId,
  377. "data-ssr": !(opts.ssrContext.noSSR)
  378. };
  379. {
  380. payload.id = "__NUXT_DATA__";
  381. }
  382. if (opts.src) {
  383. payload["data-src"] = opts.src;
  384. }
  385. const config = uneval(opts.ssrContext.config);
  386. return [
  387. payload,
  388. {
  389. innerHTML: `window.__NUXT__={};window.__NUXT__.config=${config}`
  390. }
  391. ];
  392. }
  393. function splitPayload(ssrContext) {
  394. const { data, prerenderedAt, ...initial } = ssrContext.payload;
  395. return {
  396. initial: { ...initial, prerenderedAt },
  397. payload: { data, prerenderedAt }
  398. };
  399. }
  400. const renderer$1 = /*#__PURE__*/Object.freeze({
  401. __proto__: null,
  402. default: renderer
  403. });
  404. export { baseURL as a, buildAssetsURL as b, renderer$1 as r };
  405. //# sourceMappingURL=renderer.mjs.map