mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-24 22:55:13 +00:00
feat(nuxt): namespace __NUXT__
when using multi-app (#27263)
This commit is contained in:
parent
843ea55412
commit
b516badc10
@ -9,7 +9,7 @@ import { useRoute } from './router'
|
|||||||
import { getAppManifest, getRouteRules } from './manifest'
|
import { getAppManifest, getRouteRules } from './manifest'
|
||||||
|
|
||||||
// @ts-expect-error virtual import
|
// @ts-expect-error virtual import
|
||||||
import { appManifest, payloadExtraction, renderJsonPayloads } from '#build/nuxt.config.mjs'
|
import { appId, appManifest, multiApp, payloadExtraction, renderJsonPayloads } from '#build/nuxt.config.mjs'
|
||||||
|
|
||||||
interface LoadPayloadOptions {
|
interface LoadPayloadOptions {
|
||||||
fresh?: boolean
|
fresh?: boolean
|
||||||
@ -107,7 +107,7 @@ export async function getNuxtClientPayload () {
|
|||||||
return payloadCache
|
return payloadCache
|
||||||
}
|
}
|
||||||
|
|
||||||
const el = document.getElementById('__NUXT_DATA__')
|
const el = multiApp ? document.querySelector(`[data-nuxt-data="${appId}"]`) as HTMLElement : document.getElementById('__NUXT_DATA__')
|
||||||
if (!el) {
|
if (!el) {
|
||||||
return {} as Partial<NuxtPayload>
|
return {} as Partial<NuxtPayload>
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ export async function getNuxtClientPayload () {
|
|||||||
payloadCache = {
|
payloadCache = {
|
||||||
...inlineData,
|
...inlineData,
|
||||||
...externalData,
|
...externalData,
|
||||||
...window.__NUXT__,
|
...(multiApp ? window.__NUXT__?.[appId] : window.__NUXT__),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payloadCache!.config?.public) {
|
if (payloadCache!.config?.public) {
|
||||||
|
@ -15,7 +15,7 @@ import plugins from '#build/plugins'
|
|||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import RootComponent from '#build/root-component.mjs'
|
import RootComponent from '#build/root-component.mjs'
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { vueAppRootContainer } from '#build/nuxt.config.mjs'
|
import { appId, multiApp, vueAppRootContainer } from '#build/nuxt.config.mjs'
|
||||||
|
|
||||||
let entry: (ssrContext?: CreateOptions['ssrContext']) => Promise<App<Element>>
|
let entry: (ssrContext?: CreateOptions['ssrContext']) => Promise<App<Element>>
|
||||||
|
|
||||||
@ -50,9 +50,10 @@ if (import.meta.client) {
|
|||||||
|
|
||||||
entry = async function initApp () {
|
entry = async function initApp () {
|
||||||
if (vueAppPromise) { return vueAppPromise }
|
if (vueAppPromise) { return vueAppPromise }
|
||||||
|
|
||||||
const isSSR = Boolean(
|
const isSSR = Boolean(
|
||||||
window.__NUXT__?.serverRendered ||
|
(multiApp ? window.__NUXT__?.[appId] : window.__NUXT__)?.serverRendered ??
|
||||||
document.getElementById('__NUXT_DATA__')?.dataset.ssr === 'true',
|
(multiApp ? document.querySelector(`[data-nuxt-data="${appId}"]`) as HTMLElement : document.getElementById('__NUXT_DATA__'))?.dataset.ssr === 'true',
|
||||||
)
|
)
|
||||||
const vueApp = isSSR ? createSSRApp(RootComponent) : createApp(RootComponent)
|
const vueApp = isSSR ? createSSRApp(RootComponent) : createApp(RootComponent)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import type { RouteAnnouncer } from '../app/composables/route-announcer'
|
|||||||
import type { ViewTransition } from './plugins/view-transitions.client'
|
import type { ViewTransition } from './plugins/view-transitions.client'
|
||||||
|
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { appId } from '#build/nuxt.config.mjs'
|
import { appId, multiApp } from '#build/nuxt.config.mjs'
|
||||||
|
|
||||||
import type { NuxtAppLiterals } from '#app'
|
import type { NuxtAppLiterals } from '#app'
|
||||||
|
|
||||||
@ -310,19 +310,22 @@ export function createNuxtApp (options: CreateOptions) {
|
|||||||
nuxtApp.payload.serverRendered = true
|
nuxtApp.payload.serverRendered = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (import.meta.client) {
|
||||||
|
const __NUXT__ = multiApp ? window.__NUXT__?.[nuxtApp._id] : window.__NUXT__
|
||||||
// TODO: remove/refactor in https://github.com/nuxt/nuxt/issues/25336
|
// TODO: remove/refactor in https://github.com/nuxt/nuxt/issues/25336
|
||||||
if (import.meta.client && window.__NUXT__) {
|
if (__NUXT__) {
|
||||||
for (const key in window.__NUXT__) {
|
for (const key in __NUXT__) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'data':
|
case 'data':
|
||||||
case 'state':
|
case 'state':
|
||||||
case '_errors':
|
case '_errors':
|
||||||
// Preserve reactivity for non-rich payload support
|
// Preserve reactivity for non-rich payload support
|
||||||
Object.assign(nuxtApp.payload[key], window.__NUXT__[key])
|
Object.assign(nuxtApp.payload[key], __NUXT__[key])
|
||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
nuxtApp.payload[key] = window.__NUXT__[key]
|
nuxtApp.payload[key] = __NUXT__[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,8 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
const content = document.getElementById('__NUXT_LOGS__')?.textContent
|
const nuxtLogsElement = document.querySelector(`[data-nuxt-logs="${nuxtApp._name}"]`)
|
||||||
|
const content = nuxtLogsElement?.textContent
|
||||||
const logs = content ? parse(content, { ...devRevivers, ...nuxtApp._payloadRevivers }) as LogObject[] : []
|
const logs = content ? parse(content, { ...devRevivers, ...nuxtApp._payloadRevivers }) as LogObject[] : []
|
||||||
await nuxtApp.hooks.callHook('dev:ssr-logs', logs)
|
await nuxtApp.hooks.callHook('dev:ssr-logs', logs)
|
||||||
}
|
}
|
||||||
|
2
packages/nuxt/src/app/types/augments.d.ts
vendored
2
packages/nuxt/src/app/types/augments.d.ts
vendored
@ -26,7 +26,7 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
__NUXT__?: Record<string, any>
|
__NUXT__?: Record<string, any> | Record<string, Record<string, any>>
|
||||||
useNuxtApp?: typeof useNuxtApp
|
useNuxtApp?: typeof useNuxtApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ import type { NitroApp } from 'nitro/types'
|
|||||||
|
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { rootDir } from '#internal/dev-server-logs-options'
|
import { rootDir } from '#internal/dev-server-logs-options'
|
||||||
|
// @ts-expect-error virtual file
|
||||||
|
import { appId } from '#internal/nuxt.config.mjs'
|
||||||
|
|
||||||
const devReducers: Record<string, (data: any) => any> = {
|
const devReducers: Record<string, (data: any) => any> = {
|
||||||
VNode: data => isVNode(data) ? { type: data.type, props: data.props } : undefined,
|
VNode: data => isVNode(data) ? { type: data.type, props: data.props } : undefined,
|
||||||
@ -75,7 +77,7 @@ export default (nitroApp: NitroApp) => {
|
|||||||
const ctx = asyncContext.tryUse()
|
const ctx = asyncContext.tryUse()
|
||||||
if (!ctx) { return }
|
if (!ctx) { return }
|
||||||
try {
|
try {
|
||||||
htmlContext.bodyAppend.unshift(`<script type="application/json" id="__NUXT_LOGS__">${stringify(ctx.logs, { ...devReducers, ...ctx.event.context._payloadReducers })}</script>`)
|
htmlContext.bodyAppend.unshift(`<script type="application/json" data-nuxt-logs="${appId}">${stringify(ctx.logs, { ...devReducers, ...ctx.event.context._payloadReducers })}</script>`)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const shortError = e instanceof Error && 'toString' in e ? ` Received \`${e.toString()}\`.` : ''
|
const shortError = e instanceof Error && 'toString' in e ? ` Received \`${e.toString()}\`.` : ''
|
||||||
console.warn(`[nuxt] Failed to stringify dev server logs.${shortError} You can define your own reducer/reviver for rich types following the instructions in https://nuxt.com/docs/api/composables/use-nuxt-app#payload.`)
|
console.warn(`[nuxt] Failed to stringify dev server logs.${shortError} You can define your own reducer/reviver for rich types following the instructions in https://nuxt.com/docs/api/composables/use-nuxt-app#payload.`)
|
||||||
|
@ -31,7 +31,7 @@ import { renderSSRHeadOptions } from '#internal/unhead.config.mjs'
|
|||||||
|
|
||||||
import type { NuxtPayload, NuxtSSRContext } from '#app'
|
import type { NuxtPayload, NuxtSSRContext } from '#app'
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { appHead, appRootAttrs, appRootTag, appTeleportAttrs, appTeleportTag, componentIslands } from '#internal/nuxt.config.mjs'
|
import { appHead, appId, appRootAttrs, appRootTag, appTeleportAttrs, appTeleportTag, componentIslands, multiApp } from '#internal/nuxt.config.mjs'
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { buildAssetsURL, publicAssetsURL } from '#internal/nuxt/paths'
|
import { buildAssetsURL, publicAssetsURL } from '#internal/nuxt/paths'
|
||||||
|
|
||||||
@ -427,10 +427,10 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
head.push({
|
head.push({
|
||||||
script: _PAYLOAD_EXTRACTION
|
script: _PAYLOAD_EXTRACTION
|
||||||
? process.env.NUXT_JSON_PAYLOADS
|
? process.env.NUXT_JSON_PAYLOADS
|
||||||
? renderPayloadJsonScript({ id: '__NUXT_DATA__', ssrContext, data: splitPayload(ssrContext).initial, src: payloadURL })
|
? renderPayloadJsonScript({ ssrContext, data: splitPayload(ssrContext).initial, src: payloadURL })
|
||||||
: renderPayloadScript({ ssrContext, data: splitPayload(ssrContext).initial, src: payloadURL })
|
: renderPayloadScript({ ssrContext, data: splitPayload(ssrContext).initial, src: payloadURL })
|
||||||
: process.env.NUXT_JSON_PAYLOADS
|
: process.env.NUXT_JSON_PAYLOADS
|
||||||
? renderPayloadJsonScript({ id: '__NUXT_DATA__', ssrContext, data: ssrContext.payload })
|
? renderPayloadJsonScript({ ssrContext, data: ssrContext.payload })
|
||||||
: renderPayloadScript({ ssrContext, data: ssrContext.payload }),
|
: renderPayloadScript({ ssrContext, data: ssrContext.payload }),
|
||||||
}, {
|
}, {
|
||||||
...headEntryOptions,
|
...headEntryOptions,
|
||||||
@ -586,21 +586,27 @@ function renderPayloadResponse (ssrContext: NuxtSSRContext) {
|
|||||||
} satisfies RenderResponse
|
} satisfies RenderResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPayloadJsonScript (opts: { id: string, ssrContext: NuxtSSRContext, data?: any, src?: string }): Script[] {
|
function renderPayloadJsonScript (opts: { ssrContext: NuxtSSRContext, data?: any, src?: string }): Script[] {
|
||||||
const contents = opts.data ? stringify(opts.data, opts.ssrContext._payloadReducers) : ''
|
const contents = opts.data ? stringify(opts.data, opts.ssrContext._payloadReducers) : ''
|
||||||
const payload: Script = {
|
const payload: Script = {
|
||||||
'type': 'application/json',
|
'type': 'application/json',
|
||||||
'id': opts.id,
|
|
||||||
'innerHTML': contents,
|
'innerHTML': contents,
|
||||||
|
'data-nuxt-data': appId,
|
||||||
'data-ssr': !(process.env.NUXT_NO_SSR || opts.ssrContext.noSSR),
|
'data-ssr': !(process.env.NUXT_NO_SSR || opts.ssrContext.noSSR),
|
||||||
}
|
}
|
||||||
|
if (!multiApp) {
|
||||||
|
payload.id = '__NUXT_DATA__'
|
||||||
|
}
|
||||||
if (opts.src) {
|
if (opts.src) {
|
||||||
payload['data-src'] = opts.src
|
payload['data-src'] = opts.src
|
||||||
}
|
}
|
||||||
|
const config = uneval(opts.ssrContext.config)
|
||||||
return [
|
return [
|
||||||
payload,
|
payload,
|
||||||
{
|
{
|
||||||
innerHTML: `window.__NUXT__={};window.__NUXT__.config=${uneval(opts.ssrContext.config)}`,
|
innerHTML: multiApp
|
||||||
|
? `window.__NUXT__=window.__NUXT__||{};window.__NUXT__[${JSON.stringify(appId)}]={config:${config}}`
|
||||||
|
: `window.__NUXT__={};window.__NUXT__.config=${config}`,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -608,17 +614,22 @@ function renderPayloadJsonScript (opts: { id: string, ssrContext: NuxtSSRContext
|
|||||||
function renderPayloadScript (opts: { ssrContext: NuxtSSRContext, data?: any, src?: string }): Script[] {
|
function renderPayloadScript (opts: { ssrContext: NuxtSSRContext, data?: any, src?: string }): Script[] {
|
||||||
opts.data.config = opts.ssrContext.config
|
opts.data.config = opts.ssrContext.config
|
||||||
const _PAYLOAD_EXTRACTION = import.meta.prerender && process.env.NUXT_PAYLOAD_EXTRACTION && !opts.ssrContext.noSSR
|
const _PAYLOAD_EXTRACTION = import.meta.prerender && process.env.NUXT_PAYLOAD_EXTRACTION && !opts.ssrContext.noSSR
|
||||||
|
const nuxtData = devalue(opts.data)
|
||||||
if (_PAYLOAD_EXTRACTION) {
|
if (_PAYLOAD_EXTRACTION) {
|
||||||
|
const singleAppPayload = `import p from "${opts.src}";window.__NUXT__={...p,...(${nuxtData})}`
|
||||||
|
const multiAppPayload = `import p from "${opts.src}";window.__NUXT__=window.__NUXT__||{};window.__NUXT__[${JSON.stringify(appId)}]={...p,...(${nuxtData})}`
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: 'module',
|
type: 'module',
|
||||||
innerHTML: `import p from "${opts.src}";window.__NUXT__={...p,...(${devalue(opts.data)})}`,
|
innerHTML: multiApp ? multiAppPayload : singleAppPayload,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
const singleAppPayload = `window.__NUXT__=${nuxtData}`
|
||||||
|
const multiAppPayload = `window.__NUXT__=window.__NUXT__||{};window.__NUXT__[${JSON.stringify(appId)}]=${nuxtData}`
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
innerHTML: `window.__NUXT__=${devalue(opts.data)}`,
|
innerHTML: multiApp ? multiAppPayload : singleAppPayload,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -349,9 +349,16 @@ declare module 'nitropack/types' {
|
|||||||
|
|
||||||
export const clientConfigTemplate: NuxtTemplate = {
|
export const clientConfigTemplate: NuxtTemplate = {
|
||||||
filename: 'nitro.client.mjs',
|
filename: 'nitro.client.mjs',
|
||||||
getContents: () => `
|
getContents: ({ nuxt }) => {
|
||||||
export const useRuntimeConfig = () => window?.__NUXT__?.config || window?.useNuxtApp?.().payload?.config || {}
|
const appId = JSON.stringify(nuxt.options.appId)
|
||||||
`,
|
return [
|
||||||
|
'export const useRuntimeConfig = () => ',
|
||||||
|
(!nuxt.options.future.multiApp
|
||||||
|
? 'window?.__NUXT__?.config || window?.useNuxtApp?.().payload?.config'
|
||||||
|
: `window?.__NUXT__?.[${appId}]?.config || window?.useNuxtApp?.(${appId}).payload?.config`)
|
||||||
|
|| {},
|
||||||
|
].join('\n')
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const appConfigDeclarationTemplate: NuxtTemplate = {
|
export const appConfigDeclarationTemplate: NuxtTemplate = {
|
||||||
@ -496,6 +503,7 @@ export const nuxtConfigTemplate: NuxtTemplate = {
|
|||||||
`export const viewTransition = ${ctx.nuxt.options.experimental.viewTransition}`,
|
`export const viewTransition = ${ctx.nuxt.options.experimental.viewTransition}`,
|
||||||
`export const appId = ${JSON.stringify(ctx.nuxt.options.appId)}`,
|
`export const appId = ${JSON.stringify(ctx.nuxt.options.appId)}`,
|
||||||
`export const outdatedBuildInterval = ${ctx.nuxt.options.experimental.checkOutdatedBuildInterval}`,
|
`export const outdatedBuildInterval = ${ctx.nuxt.options.experimental.checkOutdatedBuildInterval}`,
|
||||||
|
`export const multiApp = ${!!ctx.nuxt.options.future.multiApp}`,
|
||||||
].join('\n\n')
|
].join('\n\n')
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,9 @@ export function parseData (html: string) {
|
|||||||
attrs: {},
|
attrs: {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { script, attrs = '' } = html.match(/<script type="application\/json" id="__NUXT_DATA__"(?<attrs>[^>]+)>(?<script>.*?)<\/script>/)?.groups || {}
|
|
||||||
|
const regexp = /<script type="application\/json" data-nuxt-data="[^"]+"(?<attrs>[^>]+)>(?<script>.*?)<\/script>/
|
||||||
|
const { script, attrs = '' } = html.match(regexp)?.groups || {}
|
||||||
const _attrs: Record<string, string> = {}
|
const _attrs: Record<string, string> = {}
|
||||||
for (const attr of attrs.matchAll(/( |^)(?<key>[\w-]+)="(?<value>[^"]+)"/g)) {
|
for (const attr of attrs.matchAll(/( |^)(?<key>[\w-]+)="(?<value>[^"]+)"/g)) {
|
||||||
_attrs[attr!.groups!.key!] = attr!.groups!.value!
|
_attrs[attr!.groups!.key!] = attr!.groups!.value!
|
||||||
|
Loading…
Reference in New Issue
Block a user