diff --git a/packages/nuxt/src/components/module.ts b/packages/nuxt/src/components/module.ts index 9a3cfd9279..7666723aa9 100644 --- a/packages/nuxt/src/components/module.ts +++ b/packages/nuxt/src/components/module.ts @@ -38,7 +38,7 @@ export default defineNuxtModule({ const getComponents: getComponentsT = (mode) => { return (mode && mode !== 'all') - ? context.components.filter(c => c.mode === mode || c.mode === 'all') + ? context.components.filter(c => c.mode === mode || c.mode === 'all' || (c.mode === 'server' && !context.components.some(otherComponent => otherComponent.mode !== 'server' && otherComponent.pascalName === c.pascalName))) : context.components } diff --git a/packages/nuxt/src/components/transform.ts b/packages/nuxt/src/components/transform.ts index 6d1a45af39..d4ca5fa743 100644 --- a/packages/nuxt/src/components/transform.ts +++ b/packages/nuxt/src/components/transform.ts @@ -5,12 +5,14 @@ import { createUnimport } from 'unimport' import { createUnplugin } from 'unplugin' import { parseURL } from 'ufo' import { parseQuery } from 'vue-router' -import { normalize } from 'pathe' +import { normalize, resolve } from 'pathe' +import { distDir } from '../dirs' import type { getComponentsT } from './module' const COMPONENT_QUERY_RE = /[?&]nuxt_component=/ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT, mode: 'client' | 'server' | 'all') { + const serverComponentRuntime = resolve(distDir, 'components/runtime/server-component') const componentUnimport = createUnimport({ imports: [ { @@ -25,18 +27,20 @@ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT const components = getComponents(mode) return components.flatMap((c): Import[] => { const withMode = (mode: string | undefined) => mode - ? `${c.filePath}${c.filePath.includes('?') ? '&' : '?'}nuxt_component=${mode}` + ? `${c.filePath}${c.filePath.includes('?') ? '&' : '?'}nuxt_component=${mode}&nuxt_component_name=${c.pascalName}` : c.filePath + const mode = !c._raw && c.mode && ['client', 'server'].includes(c.mode) ? c.mode : undefined + return [ { as: c.pascalName, - from: withMode(c.mode === 'client' ? 'client' : undefined), + from: withMode(mode), name: 'default' }, { as: 'Lazy' + c.pascalName, - from: withMode([c.mode === 'client' ? 'client' : '', 'async'].filter(Boolean).join(',')), + from: withMode([mode, 'async'].filter(Boolean).join(',')), name: 'default' } ] @@ -82,6 +86,15 @@ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT ].join('\n'), map: null } + } else if (mode === 'server' || mode === 'server,async') { + const name = query.nuxt_component_name + return { + code: [ + `import { createServerComponent } from ${JSON.stringify(serverComponentRuntime)}`, + `export default createServerComponent(${JSON.stringify(name)})` + ].join('\n'), + map: null + } } else { throw new Error(`Unknown component mode: ${mode}, this might be an internal bug of Nuxt.`) } diff --git a/test/fixtures/basic/components/global/ServerComponentGlobal.server.vue b/test/fixtures/basic/components/global/ServerComponentGlobal.server.vue new file mode 100644 index 0000000000..435ce32581 --- /dev/null +++ b/test/fixtures/basic/components/global/ServerComponentGlobal.server.vue @@ -0,0 +1,5 @@ +