mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-28 00:22:05 +00:00
wip
This commit is contained in:
parent
4dcc48f4e6
commit
6f3406e640
@ -12,7 +12,7 @@ import { join } from 'pathe'
|
|||||||
// eslint-disable-next-line import/no-restricted-paths
|
// eslint-disable-next-line import/no-restricted-paths
|
||||||
import type { NuxtIslandResponse } from '../../core/runtime/nitro/renderer'
|
import type { NuxtIslandResponse } from '../../core/runtime/nitro/renderer'
|
||||||
import { useNuxtApp, useRuntimeConfig } from '../nuxt'
|
import { useNuxtApp, useRuntimeConfig } from '../nuxt'
|
||||||
import { prerenderRoutes, useRequestEvent } from '../composables/ssr'
|
import { useRequestEvent } from '../composables/ssr'
|
||||||
import { getFragmentHTML, getSlotProps } from './utils'
|
import { getFragmentHTML, getSlotProps } from './utils'
|
||||||
|
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
@ -25,9 +25,9 @@ const SLOTNAME_RE = /nuxt-ssr-slot-name="([^"]*)"/g
|
|||||||
const SLOT_FALLBACK_RE = /<div nuxt-slot-fallback-start="([^"]*)"[^>]*><\/div>(((?!<div nuxt-slot-fallback-end[^>]*>)[\s\S])*)<div nuxt-slot-fallback-end[^>]*><\/div>/g
|
const SLOT_FALLBACK_RE = /<div nuxt-slot-fallback-start="([^"]*)"[^>]*><\/div>(((?!<div nuxt-slot-fallback-end[^>]*>)[\s\S])*)<div nuxt-slot-fallback-end[^>]*><\/div>/g
|
||||||
|
|
||||||
let id = 0
|
let id = 0
|
||||||
const getId = import.meta.client ? () => (id++).toString() : randomUUID
|
const getId = () => (id++).toString()
|
||||||
|
|
||||||
const components = import.meta.client ? new Map<string, Component>() : undefined
|
const components = new Map<string, Component>()
|
||||||
|
|
||||||
async function loadComponents (source = '/', paths: Record<string, string>) {
|
async function loadComponents (source = '/', paths: Record<string, string>) {
|
||||||
const promises = []
|
const promises = []
|
||||||
@ -86,10 +86,9 @@ export default defineComponent({
|
|||||||
const filteredProps = computed(() => props.props ? Object.fromEntries(Object.entries(props.props).filter(([key]) => !key.startsWith('data-v-'))) : {})
|
const filteredProps = computed(() => props.props ? Object.fromEntries(Object.entries(props.props).filter(([key]) => !key.startsWith('data-v-'))) : {})
|
||||||
const hashId = computed(() => hash([props.name, filteredProps.value, props.context, props.source]))
|
const hashId = computed(() => hash([props.name, filteredProps.value, props.context, props.source]))
|
||||||
const instance = getCurrentInstance()!
|
const instance = getCurrentInstance()!
|
||||||
const event = useRequestEvent()
|
|
||||||
|
|
||||||
// TODO: remove use of `$fetch.raw` when nitro 503 issues on windows dev server are resolved
|
// TODO: remove use of `$fetch.raw` when nitro 503 issues on windows dev server are resolved
|
||||||
const eventFetch = import.meta.server ? event.fetch : import.meta.dev ? $fetch.raw : globalThis.fetch
|
const eventFetch = import.meta.dev ? $fetch.raw : globalThis.fetch
|
||||||
const mounted = ref(false)
|
const mounted = ref(false)
|
||||||
onMounted(() => { mounted.value = true })
|
onMounted(() => { mounted.value = true })
|
||||||
|
|
||||||
@ -97,9 +96,7 @@ export default defineComponent({
|
|||||||
nuxtApp.payload.data[key] = {
|
nuxtApp.payload.data[key] = {
|
||||||
__nuxt_island: {
|
__nuxt_island: {
|
||||||
key,
|
key,
|
||||||
...(import.meta.server && import.meta.prerender)
|
params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } ,
|
||||||
? {}
|
|
||||||
: { params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } },
|
|
||||||
result: {
|
result: {
|
||||||
chunks: result.chunks,
|
chunks: result.chunks,
|
||||||
props: result.props,
|
props: result.props,
|
||||||
@ -120,11 +117,7 @@ export default defineComponent({
|
|||||||
teleports: rawPayload.teleports
|
teleports: rawPayload.teleports
|
||||||
}
|
}
|
||||||
|
|
||||||
const ssrHTML = ref<string>('')
|
const ssrHTML = ref<string>(getFragmentHTML(instance.vnode?.el ?? null, true)?.join('') || '')
|
||||||
|
|
||||||
if (import.meta.client) {
|
|
||||||
ssrHTML.value = getFragmentHTML(instance.vnode?.el ?? null, true)?.join('') || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
const slotProps = computed(() => getSlotProps(ssrHTML.value))
|
const slotProps = computed(() => getSlotProps(ssrHTML.value))
|
||||||
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? getId())
|
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? getId())
|
||||||
@ -134,7 +127,7 @@ export default defineComponent({
|
|||||||
const currentSlots = Object.keys(slots)
|
const currentSlots = Object.keys(slots)
|
||||||
let html = ssrHTML.value
|
let html = ssrHTML.value
|
||||||
|
|
||||||
if (import.meta.client && !canLoadClientComponent.value) {
|
if (!canLoadClientComponent.value) {
|
||||||
for (const [key, value] of Object.entries(nonReactivePayload.teleports || {})) {
|
for (const [key, value] of Object.entries(nonReactivePayload.teleports || {})) {
|
||||||
html = html.replace(new RegExp(`<div [^>]*nuxt-ssr-client="${key}"[^>]*>`), (full) => {
|
html = html.replace(new RegExp(`<div [^>]*nuxt-ssr-client="${key}"[^>]*>`), (full) => {
|
||||||
return full + value
|
return full + value
|
||||||
@ -165,24 +158,14 @@ export default defineComponent({
|
|||||||
|
|
||||||
const url = remoteComponentIslands && props.source ? new URL(`/__nuxt_island/${key}.json`, props.source).href : `/__nuxt_island/${key}.json`
|
const url = remoteComponentIslands && props.source ? new URL(`/__nuxt_island/${key}.json`, props.source).href : `/__nuxt_island/${key}.json`
|
||||||
|
|
||||||
if (import.meta.server && import.meta.prerender) {
|
|
||||||
// Hint to Nitro to prerender the island component
|
|
||||||
nuxtApp.runWithContext(() => prerenderRoutes(url))
|
|
||||||
}
|
|
||||||
// TODO: Validate response
|
// TODO: Validate response
|
||||||
// $fetch handles the app.baseURL in dev
|
// $fetch handles the app.baseURL in dev
|
||||||
const r = await eventFetch(withQuery(((import.meta.dev && import.meta.client) || props.source) ? url : joinURL(config.app.baseURL ?? '', url), {
|
const r = await eventFetch(withQuery((import.meta.dev || props.source) ? url : joinURL(config.app.baseURL ?? '', url), {
|
||||||
...props.context,
|
...props.context,
|
||||||
props: props.props ? JSON.stringify(props.props) : undefined
|
props: props.props ? JSON.stringify(props.props) : undefined
|
||||||
}))
|
}))
|
||||||
const result = import.meta.server || !import.meta.dev ? await r.json() : (r as FetchResponse<NuxtIslandResponse>)._data
|
const result = import.meta.dev ? (r as FetchResponse<NuxtIslandResponse>)._data : await r.json()
|
||||||
// TODO: support passing on more headers
|
|
||||||
if (import.meta.server && import.meta.prerender) {
|
|
||||||
const hints = r.headers.get('x-nitro-prerender')
|
|
||||||
if (hints) {
|
|
||||||
appendResponseHeader(event, 'x-nitro-prerender', hints)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setPayload(key, result)
|
setPayload(key, result)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -204,7 +187,7 @@ export default defineComponent({
|
|||||||
key.value++
|
key.value++
|
||||||
error.value = null
|
error.value = null
|
||||||
|
|
||||||
if (selectiveClient && import.meta.client) {
|
if (selectiveClient) {
|
||||||
if (canLoadClientComponent.value && res.chunks) {
|
if (canLoadClientComponent.value && res.chunks) {
|
||||||
await loadComponents(props.source, res.chunks)
|
await loadComponents(props.source, res.chunks)
|
||||||
}
|
}
|
||||||
@ -213,10 +196,9 @@ export default defineComponent({
|
|||||||
nonReactivePayload.teleports = res.teleports
|
nonReactivePayload.teleports = res.teleports
|
||||||
nonReactivePayload.chunks = res.chunks
|
nonReactivePayload.chunks = res.chunks
|
||||||
|
|
||||||
if (import.meta.client) {
|
|
||||||
// must await next tick for Teleport to work correctly with static node re-rendering
|
// must await next tick for Teleport to work correctly with static node re-rendering
|
||||||
await nextTick()
|
await nextTick()
|
||||||
}
|
|
||||||
setUid()
|
setUid()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error.value = e
|
error.value = e
|
||||||
@ -233,13 +215,11 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (import.meta.client) {
|
|
||||||
watch(props, debounce(() => fetchComponent(), 100))
|
watch(props, debounce(() => fetchComponent(), 100))
|
||||||
}
|
|
||||||
|
|
||||||
if (import.meta.client && !nuxtApp.isHydrating && props.lazy) {
|
if (!nuxtApp.isHydrating && props.lazy) {
|
||||||
fetchComponent()
|
fetchComponent()
|
||||||
} else if (import.meta.server || !nuxtApp.isHydrating || !nuxtApp.payload.serverRendered) {
|
} else if (!nuxtApp.isHydrating || !nuxtApp.payload.serverRendered) {
|
||||||
await fetchComponent()
|
await fetchComponent()
|
||||||
} else if (selectiveClient && canLoadClientComponent.value && nonReactivePayload.chunks) {
|
} else if (selectiveClient && canLoadClientComponent.value && nonReactivePayload.chunks) {
|
||||||
await loadComponents(props.source, nonReactivePayload.chunks)
|
await loadComponents(props.source, nonReactivePayload.chunks)
|
||||||
@ -253,22 +233,15 @@ export default defineComponent({
|
|||||||
key: key.value
|
key: key.value
|
||||||
}, [h(createStaticVNode(html.value || '<div></div>', 1))])]
|
}, [h(createStaticVNode(html.value || '<div></div>', 1))])]
|
||||||
|
|
||||||
if (uid.value && (mounted.value || nuxtApp.isHydrating || import.meta.server) && html.value) {
|
if (uid.value && (mounted.value || nuxtApp.isHydrating) && html.value) {
|
||||||
for (const slot in slots) {
|
for (const slot in slots) {
|
||||||
if (availableSlots.value.includes(slot)) {
|
if (availableSlots.value.includes(slot)) {
|
||||||
nodes.push(createVNode(Teleport, { to: import.meta.client ? `[nuxt-ssr-component-uid='${uid.value}'] [nuxt-ssr-slot-name='${slot}']` : `uid=${uid.value};slot=${slot}` }, {
|
nodes.push(createVNode(Teleport, { to: `[nuxt-ssr-component-uid='${uid.value}'] [nuxt-ssr-slot-name='${slot}']` }, {
|
||||||
default: () => (slotProps.value[slot] ?? [undefined]).map((data: any) => slots[slot]?.(data))
|
default: () => (slotProps.value[slot] ?? [undefined]).map((data: any) => slots[slot]?.(data))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (import.meta.server) {
|
if (selectiveClient && canLoadClientComponent.value) {
|
||||||
for (const [id, html] of Object.entries(nonReactivePayload.teleports ?? {})) {
|
|
||||||
nodes.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, {
|
|
||||||
default: () => [createStaticVNode(html, 1)]
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (selectiveClient && import.meta.client && canLoadClientComponent.value) {
|
|
||||||
for (const [id, props] of Object.entries(nonReactivePayload.props ?? {})) {
|
for (const [id, props] of Object.entries(nonReactivePayload.props ?? {})) {
|
||||||
const component = components!.get(id.split('-')[0])!
|
const component = components!.get(id.split('-')[0])!
|
||||||
const vnode = createVNode(Teleport, { to: `[nuxt-ssr-component-uid='${uid.value}'] [nuxt-ssr-client="${id}"]` }, {
|
const vnode = createVNode(Teleport, { to: `[nuxt-ssr-component-uid='${uid.value}'] [nuxt-ssr-client="${id}"]` }, {
|
169
packages/nuxt/src/app/components/nuxt-island.server.ts
Normal file
169
packages/nuxt/src/app/components/nuxt-island.server.ts
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import { Fragment, Teleport, computed, createStaticVNode, createVNode, defineComponent, h, ref, } from 'vue'
|
||||||
|
import { hash } from 'ohash'
|
||||||
|
import { appendResponseHeader } from 'h3'
|
||||||
|
import { useHead } from '@unhead/vue'
|
||||||
|
import { randomUUID } from 'uncrypto'
|
||||||
|
import { joinURL, withQuery } from 'ufo'
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-restricted-paths
|
||||||
|
import type { NuxtIslandResponse } from '../../core/runtime/nitro/renderer'
|
||||||
|
import { useNuxtApp, useRuntimeConfig } from '../nuxt'
|
||||||
|
import { prerenderRoutes, useRequestEvent } from '../composables/ssr'
|
||||||
|
import { getSlotProps } from './utils'
|
||||||
|
|
||||||
|
// @ts-expect-error virtual file
|
||||||
|
import { remoteComponentIslands, selectiveClient } from '#build/nuxt.config.mjs'
|
||||||
|
|
||||||
|
const pKey = '_islandPromises'
|
||||||
|
const SSR_UID_RE = /nuxt-ssr-component-uid="([^"]*)"/
|
||||||
|
const UID_ATTR = /nuxt-ssr-component-uid(="([^"]*)")?/
|
||||||
|
const SLOTNAME_RE = /nuxt-ssr-slot-name="([^"]*)"/g
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'NuxtIsland',
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
lazy: Boolean,
|
||||||
|
props: {
|
||||||
|
type: Object,
|
||||||
|
default: () => undefined
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
source: {
|
||||||
|
type: String,
|
||||||
|
default: () => undefined
|
||||||
|
},
|
||||||
|
dangerouslyLoadClientComponents: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async setup(props, { slots }) {
|
||||||
|
const error = ref<unknown>(null)
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
const filteredProps = computed(() => props.props ? Object.fromEntries(Object.entries(props.props).filter(([key]) => !key.startsWith('data-v-'))) : {})
|
||||||
|
const hashId = computed(() => hash([props.name, filteredProps.value, props.context, props.source]))
|
||||||
|
const event = useRequestEvent()
|
||||||
|
|
||||||
|
|
||||||
|
function setPayload(key: string, result: NuxtIslandResponse) {
|
||||||
|
nuxtApp.payload.data[key] = {
|
||||||
|
__nuxt_island: {
|
||||||
|
key,
|
||||||
|
...(import.meta.prerender)
|
||||||
|
? {}
|
||||||
|
: { params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } },
|
||||||
|
result: {
|
||||||
|
chunks: result.chunks,
|
||||||
|
props: result.props,
|
||||||
|
teleports: result.teleports
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const nonReactivePayload: Pick<NuxtIslandResponse, 'chunks' | 'props' | 'teleports'> = {
|
||||||
|
chunks: {},
|
||||||
|
props: {},
|
||||||
|
teleports: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ssrHTML = ref<string>('')
|
||||||
|
|
||||||
|
const slotProps = computed(() => getSlotProps(ssrHTML.value))
|
||||||
|
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? randomUUID())
|
||||||
|
const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1]))
|
||||||
|
|
||||||
|
function setUid() {
|
||||||
|
uid.value = ssrHTML.value.match(SSR_UID_RE)?.[1] ?? randomUUID() as string
|
||||||
|
}
|
||||||
|
|
||||||
|
const cHead = ref<Record<'link' | 'style', Array<Record<string, string>>>>({ link: [], style: [] })
|
||||||
|
useHead(cHead)
|
||||||
|
|
||||||
|
async function _fetchComponent() {
|
||||||
|
const key = `${props.name}_${hashId.value}`
|
||||||
|
|
||||||
|
if (nuxtApp.payload.data[key]?.html) { return nuxtApp.payload.data[key] }
|
||||||
|
|
||||||
|
const url = remoteComponentIslands && props.source ? new URL(`/__nuxt_island/${key}.json`, props.source).href : `/__nuxt_island/${key}.json`
|
||||||
|
|
||||||
|
if (import.meta.prerender) {
|
||||||
|
// Hint to Nitro to prerender the island component
|
||||||
|
nuxtApp.runWithContext(() => prerenderRoutes(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Validate response
|
||||||
|
const r = await event.fetch(withQuery((props.source) ? url : joinURL(config.app.baseURL ?? '', url), {
|
||||||
|
...props.context,
|
||||||
|
props: props.props ? JSON.stringify(props.props) : undefined
|
||||||
|
}))
|
||||||
|
const result = await r.json()
|
||||||
|
// TODO: support passing on more headers
|
||||||
|
if (import.meta.prerender) {
|
||||||
|
const hints = r.headers.get('x-nitro-prerender')
|
||||||
|
if (hints) {
|
||||||
|
appendResponseHeader(event, 'x-nitro-prerender', hints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setPayload(key, result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchComponent(force = false) {
|
||||||
|
nuxtApp[pKey] = nuxtApp[pKey] || {}
|
||||||
|
if (!nuxtApp[pKey][uid.value]) {
|
||||||
|
nuxtApp[pKey][uid.value] = _fetchComponent().finally(() => {
|
||||||
|
delete nuxtApp[pKey]![uid.value]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res: NuxtIslandResponse = await nuxtApp[pKey][uid.value]
|
||||||
|
cHead.value.link = res.head.link
|
||||||
|
cHead.value.style = res.head.style
|
||||||
|
ssrHTML.value = res.html.replace(UID_ATTR, () => {
|
||||||
|
return `nuxt-ssr-component-uid="${randomUUID()}"`
|
||||||
|
})
|
||||||
|
nonReactivePayload.teleports = res.teleports
|
||||||
|
nonReactivePayload.chunks = res.chunks
|
||||||
|
|
||||||
|
setUid()
|
||||||
|
} catch (e) {
|
||||||
|
error.value = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await fetchComponent()
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (!ssrHTML.value || error.value) {
|
||||||
|
return [slots.fallback?.({ error: error.value }) ?? createVNode('div')]
|
||||||
|
}
|
||||||
|
const nodes = [createVNode(Fragment, {}, [h(createStaticVNode(ssrHTML.value || '<div></div>', 1))])]
|
||||||
|
|
||||||
|
// render slots and teleports
|
||||||
|
if (uid.value && ssrHTML.value) {
|
||||||
|
for (const slot in slots) {
|
||||||
|
if (availableSlots.value.includes(slot)) {
|
||||||
|
nodes.push(createVNode(Teleport, { to: `uid=${uid.value};slot=${slot}` }, {
|
||||||
|
default: () => (slotProps.value[slot] ?? [undefined]).map((data: any) => slots[slot]?.(data))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const [id, html] of Object.entries(nonReactivePayload.teleports ?? {})) {
|
||||||
|
nodes.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, {
|
||||||
|
default: () => [createStaticVNode(html, 1)]
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
@ -57,8 +57,9 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
|
|||||||
const isServerOnly = !component._raw && component.mode === 'server' &&
|
const isServerOnly = !component._raw && component.mode === 'server' &&
|
||||||
!components.some(c => c.pascalName === component.pascalName && c.mode === 'client')
|
!components.some(c => c.pascalName === component.pascalName && c.mode === 'client')
|
||||||
if (isServerOnly) {
|
if (isServerOnly) {
|
||||||
|
imports.add(genImport(`#app/components/nuxt-island.${options.mode}`, 'NuxtIsland'))
|
||||||
imports.add(genImport(serverComponentRuntime, [{ name: 'createServerComponent' }]))
|
imports.add(genImport(serverComponentRuntime, [{ name: 'createServerComponent' }]))
|
||||||
imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(name)})`)
|
imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(name)}, NuxtIsland)`)
|
||||||
if (!options.experimentalComponentIslands) {
|
if (!options.experimentalComponentIslands) {
|
||||||
logger.warn(`Standalone server components (\`${name}\`) are not yet supported without enabling \`experimental.componentIslands\`.`)
|
logger.warn(`Standalone server components (\`${name}\`) are not yet supported without enabling \`experimental.componentIslands\`.`)
|
||||||
}
|
}
|
||||||
|
@ -130,11 +130,11 @@ export default defineNuxtModule<ComponentsOptions>({
|
|||||||
const unpluginServer = createTransformPlugin(nuxt, getComponents, 'server')
|
const unpluginServer = createTransformPlugin(nuxt, getComponents, 'server')
|
||||||
const unpluginClient = createTransformPlugin(nuxt, getComponents, 'client')
|
const unpluginClient = createTransformPlugin(nuxt, getComponents, 'client')
|
||||||
|
|
||||||
addVitePlugin(() => unpluginServer.vite(), { server: true, client: false })
|
addVitePlugin(() => unpluginServer.vite({ bundle: 'server'}), { server: true, client: false })
|
||||||
addVitePlugin(() => unpluginClient.vite(), { server: false, client: true })
|
addVitePlugin(() => unpluginClient.vite({ bundle: 'client'}), { server: false, client: true })
|
||||||
|
|
||||||
addWebpackPlugin(() => unpluginServer.webpack(), { server: true, client: false })
|
addWebpackPlugin(() => unpluginServer.webpack({ bundle: 'server'}), { server: true, client: false })
|
||||||
addWebpackPlugin(() => unpluginClient.webpack(), { server: false, client: true })
|
addWebpackPlugin(() => unpluginClient.webpack({ bundle: 'client'}), { server: false, client: true })
|
||||||
|
|
||||||
// Do not prefetch global components chunks
|
// Do not prefetch global components chunks
|
||||||
nuxt.hook('build:manifest', (manifest) => {
|
nuxt.hook('build:manifest', (manifest) => {
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import { defineComponent, h, ref } from 'vue'
|
import { DefineComponent, defineComponent, h, ref } from 'vue'
|
||||||
import NuxtIsland from '#app/components/nuxt-island'
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since NuxtIsland is split into a server and client file
|
||||||
|
* we need to pass it as an argument to createServerComponent
|
||||||
|
* It is normally injected by transform plugins
|
||||||
|
*/
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/*@__NO_SIDE_EFFECTS__*/
|
||||||
export const createServerComponent = (name: string) => {
|
export const createServerComponent = (name: string, NuxtIsland: DefineComponent) => {
|
||||||
return defineComponent({
|
return defineComponent({
|
||||||
name,
|
name,
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
@ -47,7 +47,7 @@ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return createUnplugin(() => ({
|
return createUnplugin(({bundle} : {bundle: 'server'|'client'}) => ({
|
||||||
name: 'nuxt:components:imports',
|
name: 'nuxt:components:imports',
|
||||||
transformInclude (id) {
|
transformInclude (id) {
|
||||||
id = normalize(id)
|
id = normalize(id)
|
||||||
@ -88,10 +88,16 @@ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT
|
|||||||
}
|
}
|
||||||
} else if (mode === 'server' || mode === 'server,async') {
|
} else if (mode === 'server' || mode === 'server,async') {
|
||||||
const name = query.nuxt_component_name
|
const name = query.nuxt_component_name
|
||||||
|
console.log( [
|
||||||
|
`import NuxtIsland from "#app/components/nuxt-island.${bundle}"`,
|
||||||
|
`import { createServerComponent } from ${JSON.stringify(serverComponentRuntime)}`,
|
||||||
|
`export default createServerComponent(${JSON.stringify(name)}, NuxtIsland)`
|
||||||
|
].join('\n'))
|
||||||
return {
|
return {
|
||||||
code: [
|
code: [
|
||||||
|
`import NuxtIsland from "#app/components/nuxt-island.${bundle}"`,
|
||||||
`import { createServerComponent } from ${JSON.stringify(serverComponentRuntime)}`,
|
`import { createServerComponent } from ${JSON.stringify(serverComponentRuntime)}`,
|
||||||
`export default createServerComponent(${JSON.stringify(name)})`
|
`export default createServerComponent(${JSON.stringify(name)}, NuxtIsland)`
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
map: null
|
map: null
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,16 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
addComponent({
|
addComponent({
|
||||||
name: 'NuxtIsland',
|
name: 'NuxtIsland',
|
||||||
priority: 10, // built-in that we do not expect the user to override
|
priority: 10, // built-in that we do not expect the user to override
|
||||||
filePath: resolve(nuxt.options.appDir, 'components/nuxt-island')
|
filePath: resolve(nuxt.options.appDir, 'components/nuxt-island.server'),
|
||||||
|
mode: 'server',
|
||||||
|
_raw: true
|
||||||
|
})
|
||||||
|
addComponent({
|
||||||
|
name: 'NuxtIsland',
|
||||||
|
priority: 10, // built-in that we do not expect the user to override
|
||||||
|
filePath: resolve(nuxt.options.appDir, 'components/nuxt-island.client'),
|
||||||
|
mode: 'client',
|
||||||
|
_raw: true
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!nuxt.options.ssr) {
|
if (!nuxt.options.ssr) {
|
||||||
|
Loading…
Reference in New Issue
Block a user