This commit is contained in:
Julien Huang 2024-06-10 23:05:29 +02:00
parent b3f519aa6e
commit 066f2c597e
5 changed files with 37 additions and 4 deletions

View File

@ -1,3 +1,4 @@
import { pathToFileURL } from 'node:url'
import { createUnplugin } from 'unplugin' import { createUnplugin } from 'unplugin'
import { genDynamicImport, genImport } from 'knitwork' import { genDynamicImport, genImport } from 'knitwork'
import MagicString from 'magic-string' import MagicString from 'magic-string'
@ -6,6 +7,7 @@ import { resolve } from 'pathe'
import type { Component, ComponentsOptions } from 'nuxt/schema' import type { Component, ComponentsOptions } from 'nuxt/schema'
import { logger, tryUseNuxt } from '@nuxt/kit' import { logger, tryUseNuxt } from '@nuxt/kit'
import { parseQuery, parseURL } from 'ufo'
import { distDir } from '../dirs' import { distDir } from '../dirs'
import { isVue } from '../core/utils' import { isVue } from '../core/utils'
@ -17,6 +19,30 @@ interface LoaderOptions {
experimentalComponentIslands?: boolean 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) => { export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
const exclude = options.transform?.exclude || [] const exclude = options.transform?.exclude || []
const include = options.transform?.include || [] 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$/) return isVue(id, { type: ['template', 'script'] }) || !!id.match(/\.[tj]sx$/)
}, },
transform (code) { transform (code) {
const components = options.getComponents() const components = options.getComponents()

View File

@ -1,13 +1,13 @@
import fs, { statSync } from 'node:fs' import fs, { statSync } from 'node:fs'
import { join, normalize, relative, resolve } from 'pathe' 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 type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema'
import { distDir } from '../dirs' import { distDir } from '../dirs'
import { clientFallbackAutoIdPlugin } from './client-fallback-auto-id' import { clientFallbackAutoIdPlugin } from './client-fallback-auto-id'
import { componentNamesTemplate, componentsIslandsTemplate, componentsMetadataTemplate, componentsPluginTemplate, componentsTypeTemplate } from './templates' import { componentNamesTemplate, componentsIslandsTemplate, componentsMetadataTemplate, componentsPluginTemplate, componentsTypeTemplate } from './templates'
import { scanComponents } from './scan' import { scanComponents } from './scan'
import { loaderPlugin } from './loader' import { loadTransformedPlugin, loaderPlugin } from './loader'
import { TreeShakeTemplatePlugin } from './tree-shake' import { TreeShakeTemplatePlugin } from './tree-shake'
import { componentsChunkPlugin, islandsTransform } from './islandsTransform' import { componentsChunkPlugin, islandsTransform } from './islandsTransform'
import { createTransformPlugin } from './transform' import { createTransformPlugin } from './transform'
@ -166,7 +166,9 @@ export default defineNuxtModule<ComponentsOptions>({
}) })
const serverPlaceholderPath = resolve(distDir, 'app/components/server-placeholder') const serverPlaceholderPath = resolve(distDir, 'app/components/server-placeholder')
addBuildPlugin(loadTransformedPlugin({
getComponents,
}))
// Scan components and add to plugin // Scan components and add to plugin
nuxt.hook('app:templates', async (app) => { nuxt.hook('app:templates', async (app) => {
const newComponents = await scanComponents(componentDirs, nuxt.options.srcDir!) const newComponents = await scanComponents(componentDirs, nuxt.options.srcDir!)

View File

@ -1,5 +1,6 @@
<script setup> <script setup>
prerenderRoutes(['/some/url/from/server-only/component']) prerenderRoutes(['/some/url/from/server-only/component'])
console.log('should not be in client bundle')
</script> </script>
<template> <template>

View File

@ -3,7 +3,9 @@
server-only component child (non-server-only) server-only component child (non-server-only)
</div> </div>
</template> </template>
<script>
console.log('should not be in client bundle child')
</script>
<style> <style>
:root { :root {
--server-only-child: 'server-only-child'; --server-only-child: 'server-only-child';

View File

@ -94,6 +94,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { setupDevtoolsPlugin } from '@vue/devtools-api' import { setupDevtoolsPlugin } from '@vue/devtools-api'
import ServerOnlyComponent from '../components/ServerOnlyComponent.server.vue'
import { useRuntimeConfig } from '#imports' import { useRuntimeConfig } from '#imports'
import { importedRE, importedValue } from '~/some-exports' import { importedRE, importedValue } from '~/some-exports'