diff --git a/packages/nuxt/src/components/loader.ts b/packages/nuxt/src/components/loader.ts index b56271e631..3a62ae96ee 100644 --- a/packages/nuxt/src/components/loader.ts +++ b/packages/nuxt/src/components/loader.ts @@ -1,3 +1,4 @@ +import { pathToFileURL } from 'node:url' import { createUnplugin } from 'unplugin' import { genDynamicImport, genImport } from 'knitwork' import MagicString from 'magic-string' @@ -6,6 +7,7 @@ import { resolve } from 'pathe' import type { Component, ComponentsOptions } from 'nuxt/schema' import { logger, tryUseNuxt } from '@nuxt/kit' +import { parseQuery, parseURL } from 'ufo' import { distDir } from '../dirs' import { isVue } from '../core/utils' @@ -17,6 +19,30 @@ interface LoaderOptions { experimentalComponentIslands?: boolean } +export const loadTransformedPlugin = (options: LoaderOptions) => createUnplugin(() => { + const serverComponentRuntime = resolve(distDir, 'components/runtime/server-component') + return { + name: 'nuxt:components-transformed-loader', + enforce: 'pre', + resolveId (id) { + const components = options.getComponents() + const component = components.find(c => c.filePath === id) + if (component && (component.island || component.mode === 'server')) { + return id + '?nuxt_server_component=' + component.pascalName + } + }, + load (id) { + const { search } = parseURL(decodeURIComponent(pathToFileURL(id).href)) + const query = parseQuery(search) + + if (query.nuxt_server_component) { + console.log('query.nuxt_server_component', query.nuxt_server_component) + return `import { createServerComponent } from ${JSON.stringify(serverComponentRuntime)};export default createServerComponent("${JSON.stringify(query.nuxt_server_component)}");` + } + }, + } +}) + export const loaderPlugin = createUnplugin((options: LoaderOptions) => { const exclude = options.transform?.exclude || [] const include = options.transform?.include || [] @@ -34,6 +60,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => { } return isVue(id, { type: ['template', 'script'] }) || !!id.match(/\.[tj]sx$/) }, + transform (code) { const components = options.getComponents() diff --git a/packages/nuxt/src/components/module.ts b/packages/nuxt/src/components/module.ts index 24fe7f3fbc..50813a3d95 100644 --- a/packages/nuxt/src/components/module.ts +++ b/packages/nuxt/src/components/module.ts @@ -1,13 +1,13 @@ import fs, { statSync } from 'node:fs' import { join, normalize, relative, resolve } from 'pathe' -import { addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, logger, resolveAlias, updateTemplates } from '@nuxt/kit' +import { addBuildPlugin, addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, logger, resolveAlias, updateTemplates } from '@nuxt/kit' import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema' import { distDir } from '../dirs' import { clientFallbackAutoIdPlugin } from './client-fallback-auto-id' import { componentNamesTemplate, componentsIslandsTemplate, componentsMetadataTemplate, componentsPluginTemplate, componentsTypeTemplate } from './templates' import { scanComponents } from './scan' -import { loaderPlugin } from './loader' +import { loadTransformedPlugin, loaderPlugin } from './loader' import { TreeShakeTemplatePlugin } from './tree-shake' import { componentsChunkPlugin, islandsTransform } from './islandsTransform' import { createTransformPlugin } from './transform' @@ -166,7 +166,9 @@ export default defineNuxtModule({ }) const serverPlaceholderPath = resolve(distDir, 'app/components/server-placeholder') - + addBuildPlugin(loadTransformedPlugin({ + getComponents, + })) // Scan components and add to plugin nuxt.hook('app:templates', async (app) => { const newComponents = await scanComponents(componentDirs, nuxt.options.srcDir!) diff --git a/test/fixtures/basic/components/ServerOnlyComponent.server.vue b/test/fixtures/basic/components/ServerOnlyComponent.server.vue index ff3b40a1ba..cfa5c5a819 100644 --- a/test/fixtures/basic/components/ServerOnlyComponent.server.vue +++ b/test/fixtures/basic/components/ServerOnlyComponent.server.vue @@ -1,5 +1,6 @@ - +