UNPKG

nuxt

Version:

Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.

125 lines (124 loc) 4.14 kB
import { hasProtocol, joinURL, withoutTrailingSlash } from "ufo"; import { parse } from "devalue"; import { useHead } from "@unhead/vue"; import { getCurrentInstance, onServerPrefetch } from "vue"; import { useNuxtApp, useRuntimeConfig } from "../nuxt.js"; import { useRoute } from "./router.js"; import { getAppManifest, getRouteRules } from "./manifest.js"; import { appManifest, payloadExtraction, renderJsonPayloads } from "#build/nuxt.config.mjs"; export async function loadPayload(url, opts = {}) { if (import.meta.server || !payloadExtraction) { return null; } const payloadURL = await _getPayloadURL(url, opts); const nuxtApp = useNuxtApp(); const cache = nuxtApp._payloadCache = nuxtApp._payloadCache || {}; if (payloadURL in cache) { return cache[payloadURL]; } cache[payloadURL] = isPrerendered(url).then((prerendered) => { if (!prerendered) { cache[payloadURL] = null; return null; } return _importPayload(payloadURL).then((payload) => { if (payload) { return payload; } delete cache[payloadURL]; return null; }); }); return cache[payloadURL]; } export function preloadPayload(url, opts = {}) { const nuxtApp = useNuxtApp(); const promise = _getPayloadURL(url, opts).then((payloadURL) => { nuxtApp.runWithContext(() => useHead({ link: [ { rel: "modulepreload", href: payloadURL } ] })); }); if (import.meta.server) { onServerPrefetch(() => promise); } return promise; } const filename = renderJsonPayloads ? "_payload.json" : "_payload.js"; async function _getPayloadURL(url, opts = {}) { const u = new URL(url, "http://localhost"); if (u.host !== "localhost" || hasProtocol(u.pathname, { acceptRelative: true })) { throw new Error("Payload URL must not include hostname: " + url); } const config = useRuntimeConfig(); const hash = opts.hash || (opts.fresh ? Date.now() : config.app.buildId); const cdnURL = config.app.cdnURL; const baseOrCdnURL = cdnURL && await isPrerendered(url) ? cdnURL : config.app.baseURL; return joinURL(baseOrCdnURL, u.pathname, filename + (hash ? `?${hash}` : "")); } async function _importPayload(payloadURL) { if (import.meta.server || !payloadExtraction) { return null; } const payloadPromise = renderJsonPayloads ? fetch(payloadURL).then((res) => res.text().then(parsePayload)) : import( /* webpackIgnore: true */ /* @vite-ignore */ payloadURL ).then((r) => r.default || r); try { return await payloadPromise; } catch (err) { console.warn("[nuxt] Cannot load payload ", payloadURL, err); } return null; } export async function isPrerendered(url = useRoute().path) { if (!appManifest) { return !!useNuxtApp().payload.prerenderedAt; } url = withoutTrailingSlash(url); const manifest = await getAppManifest(); if (manifest.prerendered.includes(url)) { return true; } const rules = await getRouteRules(url); return !!rules.prerender && !rules.redirect; } let payloadCache = null; export async function getNuxtClientPayload() { if (import.meta.server) { return null; } if (payloadCache) { return payloadCache; } const el = document.getElementById("__NUXT_DATA__"); if (!el) { return {}; } const inlineData = await parsePayload(el.textContent || ""); const externalData = el.dataset.src ? await _importPayload(el.dataset.src) : void 0; payloadCache = { ...inlineData, ...externalData, ...window.__NUXT__ }; return payloadCache; } export async function parsePayload(payload) { return await parse(payload, useNuxtApp()._payloadRevivers); } export function definePayloadReducer(name, reduce) { if (import.meta.server) { useNuxtApp().ssrContext._payloadReducers[name] = reduce; } } export function definePayloadReviver(name, revive) { if (import.meta.dev && getCurrentInstance()) { console.warn("[nuxt] [definePayloadReviver] This function must be called in a Nuxt plugin that is `unshift`ed to the beginning of the Nuxt plugins array."); } if (import.meta.client) { useNuxtApp()._payloadRevivers[name] = revive; } }