diff --git a/packages/nuxt/src/components/module.ts b/packages/nuxt/src/components/module.ts index 4a5540c91d..5c2d3102db 100644 --- a/packages/nuxt/src/components/module.ts +++ b/packages/nuxt/src/components/module.ts @@ -1,6 +1,6 @@ import { existsSync, statSync, writeFileSync } from 'node:fs' import { isAbsolute, join, normalize, relative, resolve } from 'pathe' -import { addBuildPlugin, addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, logger, resolveAlias, resolvePath, updateTemplates } from '@nuxt/kit' +import { addBuildPlugin, addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, defineNuxtModule, logger, resolveAlias, resolvePath, updateTemplates } from '@nuxt/kit' import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema' import { distDir } from '../dirs' @@ -9,8 +9,8 @@ import { scanComponents } from './scan' import { ClientFallbackAutoIdPlugin } from './plugins/client-fallback-auto-id' import { LoaderPlugin } from './plugins/loader' -import { componentsChunkPlugin, islandsTransform } from './plugins/islands-transform' -import { createTransformPlugin } from './plugins/transform' +import { ComponentsChunkPlugin, IslandsTransformPlugin } from './plugins/islands-transform' +import { TransformPlugin } from './plugins/transform' import { TreeShakeTemplatePlugin } from './plugins/tree-shake' import { ComponentNamePlugin } from './plugins/component-names' @@ -134,14 +134,8 @@ export default defineNuxtModule({ addTemplate(componentsMetadataTemplate) } - const TransformPluginServer = createTransformPlugin(nuxt, getComponents, 'server') - const TransformPluginClient = createTransformPlugin(nuxt, getComponents, 'client') - - addVitePlugin(() => TransformPluginServer.vite(), { server: true, client: false }) - addVitePlugin(() => TransformPluginClient.vite(), { server: false, client: true }) - - addWebpackPlugin(() => TransformPluginServer.webpack(), { server: true, client: false }) - addWebpackPlugin(() => TransformPluginClient.webpack(), { server: false, client: true }) + addBuildPlugin(TransformPlugin(nuxt, getComponents, 'server'), { server: true, client: false }) + addBuildPlugin(TransformPlugin(nuxt, getComponents, 'client'), { server: false, client: true }) // Do not prefetch global components chunks nuxt.hook('build:manifest', (manifest) => { @@ -219,37 +213,50 @@ export default defineNuxtModule({ } }) - nuxt.hook('vite:extendConfig', (config, { isClient, isServer }) => { - const mode = isClient ? 'client' : 'server' + addBuildPlugin(TreeShakeTemplatePlugin({ sourcemap: !!nuxt.options.sourcemap.server, getComponents }), { client: false }) - config.plugins = config.plugins || [] - if (isServer) { - config.plugins.push(TreeShakeTemplatePlugin.vite({ - sourcemap: !!nuxt.options.sourcemap[mode], - getComponents, - })) - } - if (nuxt.options.experimental.clientFallback) { - config.plugins.push(ClientFallbackAutoIdPlugin.vite({ - sourcemap: !!nuxt.options.sourcemap[mode], - rootDir: nuxt.options.rootDir, - })) - } - config.plugins.push(LoaderPlugin.vite({ - sourcemap: !!nuxt.options.sourcemap[mode], - getComponents, - mode, - transform: typeof nuxt.options.components === 'object' && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined, - experimentalComponentIslands: !!nuxt.options.experimental.componentIslands, - })) + if (nuxt.options.experimental.clientFallback) { + addBuildPlugin(ClientFallbackAutoIdPlugin({ sourcemap: !!nuxt.options.sourcemap.client, rootDir: nuxt.options.rootDir }), { server: false }) + addBuildPlugin(ClientFallbackAutoIdPlugin({ sourcemap: !!nuxt.options.sourcemap.server, rootDir: nuxt.options.rootDir }), { client: false }) + } - if (nuxt.options.experimental.componentIslands) { - const selectiveClient = typeof nuxt.options.experimental.componentIslands === 'object' && nuxt.options.experimental.componentIslands.selectiveClient + const sharedLoaderOptions = { + getComponents, + transform: typeof nuxt.options.components === 'object' && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined, + experimentalComponentIslands: !!nuxt.options.experimental.componentIslands, + } + + addBuildPlugin(LoaderPlugin({ ...sharedLoaderOptions, sourcemap: !!nuxt.options.sourcemap.client, mode: 'client' }), { server: false }) + addBuildPlugin(LoaderPlugin({ ...sharedLoaderOptions, sourcemap: !!nuxt.options.sourcemap.server, mode: 'server' }), { client: false }) + + if (nuxt.options.experimental.componentIslands) { + const selectiveClient = typeof nuxt.options.experimental.componentIslands === 'object' && nuxt.options.experimental.componentIslands.selectiveClient + + addVitePlugin({ + name: 'nuxt-server-component-hmr', + handleHotUpdate (ctx) { + const components = getComponents() + const filePath = normalize(ctx.file) + const comp = components.find(c => c.filePath === filePath) + if (comp?.mode === 'server') { + ctx.server.ws.send({ + event: `nuxt-server-component:${comp.pascalName}`, + type: 'custom', + }) + } + }, + }, { server: false }) + + addBuildPlugin(IslandsTransformPlugin({ getComponents, selectiveClient }), { client: false }) + + // TODO: refactor this + nuxt.hook('vite:extendConfig', (config, { isClient }) => { + config.plugins = config.plugins || [] if (isClient && selectiveClient) { writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}') if (!nuxt.options.dev) { - config.plugins.push(componentsChunkPlugin.vite({ + config.plugins.push(ComponentsChunkPlugin.vite({ getComponents, buildDir: nuxt.options.buildDir, })) @@ -263,65 +270,18 @@ export default defineNuxtModule({ )}`) } } + }) - if (isServer) { - config.plugins.push(islandsTransform.vite({ - getComponents, - selectiveClient, - })) - } - } - if (!isServer && nuxt.options.experimental.componentIslands) { - config.plugins.push({ - name: 'nuxt-server-component-hmr', - handleHotUpdate (ctx) { - const components = getComponents() - const filePath = normalize(ctx.file) - const comp = components.find(c => c.filePath === filePath) - if (comp?.mode === 'server') { - ctx.server.ws.send({ - event: `nuxt-server-component:${comp.pascalName}`, - type: 'custom', - }) - } - }, - }) - } - }) - nuxt.hook('webpack:config', (configs) => { - configs.forEach((config) => { - const mode = config.name === 'client' ? 'client' : 'server' - config.plugins = config.plugins || [] - if (mode === 'server') { - config.plugins.push(TreeShakeTemplatePlugin.webpack({ - sourcemap: !!nuxt.options.sourcemap[mode], - getComponents, - })) - } - if (nuxt.options.experimental.clientFallback) { - config.plugins.push(ClientFallbackAutoIdPlugin.webpack({ - sourcemap: !!nuxt.options.sourcemap[mode], - rootDir: nuxt.options.rootDir, - })) - } - config.plugins.push(LoaderPlugin.webpack({ - sourcemap: !!nuxt.options.sourcemap[mode], - getComponents, - mode, - transform: typeof nuxt.options.components === 'object' && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined, - experimentalComponentIslands: !!nuxt.options.experimental.componentIslands, - })) + nuxt.hook('webpack:config', (configs) => { + configs.forEach((config) => { + const mode = config.name === 'client' ? 'client' : 'server' + config.plugins = config.plugins || [] - if (nuxt.options.experimental.componentIslands) { - if (mode === 'server') { - config.plugins.push(islandsTransform.webpack({ - getComponents, - })) - } else { + if (mode !== 'server') { writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}') } - } + }) }) - }) + } }, }) diff --git a/packages/nuxt/src/components/plugins/client-fallback-auto-id.ts b/packages/nuxt/src/components/plugins/client-fallback-auto-id.ts index b12753e4e6..9f3e1b119c 100644 --- a/packages/nuxt/src/components/plugins/client-fallback-auto-id.ts +++ b/packages/nuxt/src/components/plugins/client-fallback-auto-id.ts @@ -12,7 +12,7 @@ interface LoaderOptions { } const CLIENT_FALLBACK_RE = /<(?:NuxtClientFallback|nuxt-client-fallback)(?: [^>]*)?>/ const CLIENT_FALLBACK_GLOBAL_RE = /<(NuxtClientFallback|nuxt-client-fallback)( [^>]*)?>/g -export const ClientFallbackAutoIdPlugin = createUnplugin((options: LoaderOptions) => { +export const ClientFallbackAutoIdPlugin = (options: LoaderOptions) => createUnplugin(() => { const exclude = options.transform?.exclude || [] const include = options.transform?.include || [] diff --git a/packages/nuxt/src/components/plugins/islands-transform.ts b/packages/nuxt/src/components/plugins/islands-transform.ts index ba5aa02d0b..70ad9fb895 100644 --- a/packages/nuxt/src/components/plugins/islands-transform.ts +++ b/packages/nuxt/src/components/plugins/islands-transform.ts @@ -35,14 +35,14 @@ function wrapWithVForDiv (code: string, vfor: string): string { return `
${code}
` } -export const islandsTransform = createUnplugin((options: ServerOnlyComponentTransformPluginOptions, meta) => { +export const IslandsTransformPlugin = (options: ServerOnlyComponentTransformPluginOptions) => createUnplugin((_options, meta) => { const isVite = meta.framework === 'vite' return { - name: 'server-only-component-transform', + name: 'nuxt:server-only-component-transform', enforce: 'pre', transformInclude (id) { if (!isVue(id)) { return false } - if (options.selectiveClient === 'deep') { return true } + if (isVite && options.selectiveClient === 'deep') { return true } const components = options.getComponents() const islands = components.filter(component => @@ -70,54 +70,68 @@ export const islandsTransform = createUnplugin((options: ServerOnlyComponentTran const ast = parse(template[0]) await walk(ast, (node) => { - if (node.type === ELEMENT_NODE) { - if (node.name === 'slot') { - const { attributes, children, loc } = node - - const slotName = attributes.name ?? 'default' - - if (attributes.name) { delete attributes.name } - if (attributes['v-bind']) { - attributes._bind = extractAttributes(attributes, ['v-bind'])['v-bind']! - } - const teleportAttributes = extractAttributes(attributes, ['v-if', 'v-else-if', 'v-else']) - const bindings = getPropsToString(attributes) - // add the wrapper - s.appendLeft(startingIndex + loc[0].start, ``) - - if (children.length) { - // pass slot fallback to NuxtTeleportSsrSlot fallback - const attrString = attributeToString(attributes) - const slice = code.slice(startingIndex + loc[0].end, startingIndex + loc[1].start).replaceAll(/:?key="[^"]"/g, '') - s.overwrite(startingIndex + loc[0].start, startingIndex + loc[1].end, ``) - } else { - s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, code.slice(startingIndex + loc[0].start, startingIndex + loc[0].end).replaceAll(EXTRACTED_ATTRS_RE, '')) - } - - s.appendRight(startingIndex + loc[1].end, '') - } else if (options.selectiveClient && ('nuxt-client' in node.attributes || ':nuxt-client' in node.attributes)) { - hasNuxtClient = true - const { loc, attributes } = node - const attributeValue = attributes[':nuxt-client'] || attributes['nuxt-client'] || 'true' - if (isVite) { - const uid = hash(id + node.loc[0].start + node.loc[0].end) - const wrapperAttributes = extractAttributes(attributes, ['v-if', 'v-else-if', 'v-else']) - - let startTag = code.slice(startingIndex + loc[0].start, startingIndex + loc[0].end).replace(NUXTCLIENT_ATTR_RE, '') - if (wrapperAttributes) { - startTag = startTag.replaceAll(EXTRACTED_ATTRS_RE, '') - } - - s.appendLeft(startingIndex + loc[0].start, ``) - s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, startTag) - s.appendRight(startingIndex + loc[1].end, '') - } - } + if (node.type !== ELEMENT_NODE) { + return } + if (node.name === 'slot') { + const { attributes, children, loc } = node + + const slotName = attributes.name ?? 'default' + + if (attributes.name) { delete attributes.name } + if (attributes['v-bind']) { + attributes._bind = extractAttributes(attributes, ['v-bind'])['v-bind']! + } + const teleportAttributes = extractAttributes(attributes, ['v-if', 'v-else-if', 'v-else']) + const bindings = getPropsToString(attributes) + // add the wrapper + s.appendLeft(startingIndex + loc[0].start, ``) + + if (children.length) { + // pass slot fallback to NuxtTeleportSsrSlot fallback + const attrString = attributeToString(attributes) + const slice = code.slice(startingIndex + loc[0].end, startingIndex + loc[1].start).replaceAll(/:?key="[^"]"/g, '') + s.overwrite(startingIndex + loc[0].start, startingIndex + loc[1].end, ``) + } else { + s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, code.slice(startingIndex + loc[0].start, startingIndex + loc[0].end).replaceAll(EXTRACTED_ATTRS_RE, '')) + } + + s.appendRight(startingIndex + loc[1].end, '') + return + } + + if (!('nuxt-client' in node.attributes) && !(':nuxt-client' in node.attributes)) { + return + } + + hasNuxtClient = true + + if (!isVite || !options.selectiveClient) { + return + } + + const { loc, attributes } = node + const attributeValue = attributes[':nuxt-client'] || attributes['nuxt-client'] || 'true' + + const uid = hash(id + node.loc[0].start + node.loc[0].end) + const wrapperAttributes = extractAttributes(attributes, ['v-if', 'v-else-if', 'v-else']) + + let startTag = code.slice(startingIndex + loc[0].start, startingIndex + loc[0].end).replace(NUXTCLIENT_ATTR_RE, '') + if (wrapperAttributes) { + startTag = startTag.replaceAll(EXTRACTED_ATTRS_RE, '') + } + + s.appendLeft(startingIndex + loc[0].start, ``) + s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, startTag) + s.appendRight(startingIndex + loc[1].end, '') }) - if (!isVite && hasNuxtClient) { - console.warn(`nuxt-client attribute and client components within islands is only supported with Vite. file: ${id}`) + if (hasNuxtClient) { + if (!options.selectiveClient) { + console.warn(`The \`nuxt-client\` attribute and client components within islands are only supported when \`experimental.componentIslands.selectiveClient\` is enabled. file: ${id}`) + } else if (!isVite) { + console.warn(`The \`nuxt-client\` attribute and client components within islands are only supported with Vite. file: ${id}`) + } } if (s.hasChanged()) { @@ -164,10 +178,10 @@ function getPropsToString (bindings: Record): string { } } -export const componentsChunkPlugin = createUnplugin((options: ComponentChunkOptions) => { +export const ComponentsChunkPlugin = createUnplugin((options: ComponentChunkOptions) => { const { buildDir } = options return { - name: 'componentsChunkPlugin', + name: 'nuxt:components-chunk', vite: { async config (config) { const components = options.getComponents() diff --git a/packages/nuxt/src/components/plugins/loader.ts b/packages/nuxt/src/components/plugins/loader.ts index d2d4813767..2eecc471b1 100644 --- a/packages/nuxt/src/components/plugins/loader.ts +++ b/packages/nuxt/src/components/plugins/loader.ts @@ -17,7 +17,7 @@ interface LoaderOptions { experimentalComponentIslands?: boolean } -export const LoaderPlugin = createUnplugin((options: LoaderOptions) => { +export const LoaderPlugin = (options: LoaderOptions) => createUnplugin(() => { const exclude = options.transform?.exclude || [] const include = options.transform?.include || [] const serverComponentRuntime = resolve(distDir, 'components/runtime/server-component') diff --git a/packages/nuxt/src/components/plugins/transform.ts b/packages/nuxt/src/components/plugins/transform.ts index 064fe9a56f..85108f0122 100644 --- a/packages/nuxt/src/components/plugins/transform.ts +++ b/packages/nuxt/src/components/plugins/transform.ts @@ -12,7 +12,7 @@ import type { getComponentsT } from '../module' const COMPONENT_QUERY_RE = /[?&]nuxt_component=/ -export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT, mode: 'client' | 'server' | 'all') { +export function TransformPlugin (nuxt: Nuxt, getComponents: getComponentsT, mode: 'client' | 'server' | 'all') { const serverComponentRuntime = resolve(distDir, 'components/runtime/server-component') const componentUnimport = createUnimport({ imports: [ diff --git a/packages/nuxt/src/components/plugins/tree-shake.ts b/packages/nuxt/src/components/plugins/tree-shake.ts index 2eaf341d87..ff68f2fa21 100644 --- a/packages/nuxt/src/components/plugins/tree-shake.ts +++ b/packages/nuxt/src/components/plugins/tree-shake.ts @@ -20,7 +20,7 @@ const PLACEHOLDER_EXACT_RE = /^(?:fallback|placeholder)$/ const CLIENT_ONLY_NAME_RE = /^(?:_unref\()?(?:_component_)?(?:Lazy|lazy_)?(?:client_only|ClientOnly\)?)$/ const PARSER_OPTIONS = { sourceType: 'module', ecmaVersion: 'latest' } -export const TreeShakeTemplatePlugin = createUnplugin((options: TreeShakeTemplatePluginOptions) => { +export const TreeShakeTemplatePlugin = (options: TreeShakeTemplatePluginOptions) => createUnplugin(() => { const regexpMap = new WeakMap() return { name: 'nuxt:tree-shake-template', diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index 9caa634fdf..6af0933b8a 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -33,9 +33,7 @@ import { version } from '../../package.json' import { scriptsStubsPreset } from '../imports/presets' import { resolveTypePath } from './utils/types' import { nuxtImportProtections } from './plugins/import-protection' -import type { UnctxTransformPluginOptions } from './plugins/unctx' import { UnctxTransformPlugin } from './plugins/unctx' -import type { TreeShakeComposablesPluginOptions } from './plugins/tree-shake' import { TreeShakeComposablesPlugin } from './plugins/tree-shake' import { DevOnlyPlugin } from './plugins/dev-only' import { LayerAliasingPlugin } from './plugins/layer-aliasing' @@ -265,58 +263,45 @@ async function initNuxt (nuxt: Nuxt) { if (nuxt.options.experimental.localLayerAliases) { // Add layer aliasing support for ~, ~~, @ and @@ aliases - addVitePlugin(() => LayerAliasingPlugin.vite({ + addBuildPlugin(LayerAliasingPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, dev: nuxt.options.dev, root: nuxt.options.srcDir, // skip top-level layer (user's project) as the aliases will already be correctly resolved layers: nuxt.options._layers.slice(1), })) - addWebpackPlugin(() => LayerAliasingPlugin.webpack({ - sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, - dev: nuxt.options.dev, - root: nuxt.options.srcDir, - // skip top-level layer (user's project) as the aliases will already be correctly resolved - layers: nuxt.options._layers.slice(1), - transform: true, - })) } nuxt.hook('modules:done', async () => { // Add unctx transform - const options = { + addBuildPlugin(UnctxTransformPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, transformerOptions: { ...nuxt.options.optimization.asyncTransforms, helperModule: await tryResolveModule('unctx', nuxt.options.modulesDir) ?? 'unctx', }, - } satisfies UnctxTransformPluginOptions - addVitePlugin(() => UnctxTransformPlugin.vite(options)) - addWebpackPlugin(() => UnctxTransformPlugin.webpack(options)) + })) // Add composable tree-shaking optimisations - const serverTreeShakeOptions: TreeShakeComposablesPluginOptions = { - sourcemap: !!nuxt.options.sourcemap.server, - composables: nuxt.options.optimization.treeShake.composables.server, + if (Object.keys(nuxt.options.optimization.treeShake.composables.server).length) { + addBuildPlugin(TreeShakeComposablesPlugin({ + sourcemap: !!nuxt.options.sourcemap.server, + composables: nuxt.options.optimization.treeShake.composables.server, + }), { client: false }) } - if (Object.keys(serverTreeShakeOptions.composables).length) { - addVitePlugin(() => TreeShakeComposablesPlugin.vite(serverTreeShakeOptions), { client: false }) - addWebpackPlugin(() => TreeShakeComposablesPlugin.webpack(serverTreeShakeOptions), { client: false }) - } - const clientTreeShakeOptions: TreeShakeComposablesPluginOptions = { - sourcemap: !!nuxt.options.sourcemap.client, - composables: nuxt.options.optimization.treeShake.composables.client, - } - if (Object.keys(clientTreeShakeOptions.composables).length) { - addVitePlugin(() => TreeShakeComposablesPlugin.vite(clientTreeShakeOptions), { server: false }) - addWebpackPlugin(() => TreeShakeComposablesPlugin.webpack(clientTreeShakeOptions), { server: false }) + if (Object.keys(nuxt.options.optimization.treeShake.composables.client).length) { + addBuildPlugin(TreeShakeComposablesPlugin({ + sourcemap: !!nuxt.options.sourcemap.client, + composables: nuxt.options.optimization.treeShake.composables.client, + }), { server: false }) } }) if (!nuxt.options.dev) { // DevOnly component tree-shaking - build time only - addVitePlugin(() => DevOnlyPlugin.vite({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client })) - addWebpackPlugin(() => DevOnlyPlugin.webpack({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client })) + addBuildPlugin(DevOnlyPlugin({ + sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, + })) } if (nuxt.options.dev) { diff --git a/packages/nuxt/src/core/plugins/dev-only.ts b/packages/nuxt/src/core/plugins/dev-only.ts index 35437ad777..17992aa3d1 100644 --- a/packages/nuxt/src/core/plugins/dev-only.ts +++ b/packages/nuxt/src/core/plugins/dev-only.ts @@ -10,7 +10,7 @@ interface DevOnlyPluginOptions { const DEVONLY_COMP_SINGLE_RE = /<(?:dev-only|DevOnly|lazy-dev-only|LazyDevOnly)>[\s\S]*?<\/(?:dev-only|DevOnly|lazy-dev-only|LazyDevOnly)>/ const DEVONLY_COMP_RE = /<(?:dev-only|DevOnly|lazy-dev-only|LazyDevOnly)>[\s\S]*?<\/(?:dev-only|DevOnly|lazy-dev-only|LazyDevOnly)>/g -export const DevOnlyPlugin = createUnplugin((options: DevOnlyPluginOptions) => { +export const DevOnlyPlugin = (options: DevOnlyPluginOptions) => createUnplugin(() => { return { name: 'nuxt:server-devonly:transform', enforce: 'pre', diff --git a/packages/nuxt/src/core/plugins/layer-aliasing.ts b/packages/nuxt/src/core/plugins/layer-aliasing.ts index dd5de8b88b..9f12c72988 100644 --- a/packages/nuxt/src/core/plugins/layer-aliasing.ts +++ b/packages/nuxt/src/core/plugins/layer-aliasing.ts @@ -6,7 +6,6 @@ import MagicString from 'magic-string' interface LayerAliasingOptions { sourcemap?: boolean - transform?: boolean root: string dev: boolean layers: NuxtConfigLayer[] @@ -15,7 +14,7 @@ interface LayerAliasingOptions { const ALIAS_RE = /(?<=['"])[~@]{1,2}(?=\/)/g const ALIAS_RE_SINGLE = /(?<=['"])[~@]{1,2}(?=\/)/ -export const LayerAliasingPlugin = createUnplugin((options: LayerAliasingOptions) => { +export const LayerAliasingPlugin = (options: LayerAliasingOptions) => createUnplugin((_options, meta) => { const aliases: Record> = {} for (const layer of options.layers) { const srcDir = layer.config.srcDir || layer.cwd @@ -52,12 +51,13 @@ export const LayerAliasingPlugin = createUnplugin((options: LayerAliasingOptions // webpack-only transform transformInclude: (id) => { - if (!options.transform) { return false } + if (meta.framework === 'vite') { return false } + const _id = normalize(id) return layers.some(dir => _id.startsWith(dir)) }, transform (code, id) { - if (!options.transform) { return } + if (meta.framework === 'vite') { return } const _id = normalize(id) const layer = layers.find(l => _id.startsWith(l)) diff --git a/packages/nuxt/src/core/plugins/tree-shake.ts b/packages/nuxt/src/core/plugins/tree-shake.ts index 950ec8edbc..aed3fad9e2 100644 --- a/packages/nuxt/src/core/plugins/tree-shake.ts +++ b/packages/nuxt/src/core/plugins/tree-shake.ts @@ -5,12 +5,12 @@ import { isJS, isVue } from '../utils' type ImportPath = string -export interface TreeShakeComposablesPluginOptions { +interface TreeShakeComposablesPluginOptions { sourcemap?: boolean composables: Record } -export const TreeShakeComposablesPlugin = createUnplugin((options: TreeShakeComposablesPluginOptions) => { +export const TreeShakeComposablesPlugin = (options: TreeShakeComposablesPluginOptions) => createUnplugin(() => { /** * @todo Use the options import-path to tree-shake composables in a safer way. */ diff --git a/packages/nuxt/src/core/plugins/unctx.ts b/packages/nuxt/src/core/plugins/unctx.ts index f935adc112..efaf9fde5a 100644 --- a/packages/nuxt/src/core/plugins/unctx.ts +++ b/packages/nuxt/src/core/plugins/unctx.ts @@ -6,12 +6,12 @@ import { isJS, isVue } from '../utils' const TRANSFORM_MARKER = '/* _processed_nuxt_unctx_transform */\n' -export interface UnctxTransformPluginOptions { +interface UnctxTransformPluginOptions { sourcemap?: boolean transformerOptions: TransformerOptions } -export const UnctxTransformPlugin = createUnplugin((options: UnctxTransformPluginOptions) => { +export const UnctxTransformPlugin = (options: UnctxTransformPluginOptions) => createUnplugin(() => { const transformer = createTransformer(options.transformerOptions) return { name: 'unctx:transform', diff --git a/packages/nuxt/src/pages/module.ts b/packages/nuxt/src/pages/module.ts index ee7c937182..d06511fb46 100644 --- a/packages/nuxt/src/pages/module.ts +++ b/packages/nuxt/src/pages/module.ts @@ -1,6 +1,6 @@ import { existsSync, readdirSync } from 'node:fs' import { mkdir, readFile } from 'node:fs/promises' -import { addBuildPlugin, addComponent, addPlugin, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, findPath, logger, resolvePath, updateTemplates, useNitro } from '@nuxt/kit' +import { addBuildPlugin, addComponent, addPlugin, addTemplate, addTypeTemplate, defineNuxtModule, findPath, logger, resolvePath, updateTemplates, useNitro } from '@nuxt/kit' import { dirname, join, relative, resolve } from 'pathe' import { genImport, genObjectFromRawEntries, genString } from 'knitwork' import { joinURL } from 'ufo' @@ -15,7 +15,6 @@ import { distDir } from '../dirs' import { resolveTypePath } from '../core/utils/types' import { normalizeRoutes, resolvePagesRoutes, resolveRoutePaths } from './utils' import { extractRouteRules, getMappedPages } from './route-rules' -import type { PageMetaPluginOptions } from './plugins/page-meta' import { PageMetaPlugin } from './plugins/page-meta' import { RouteInjectionPlugin } from './plugins/route-injection' @@ -423,13 +422,11 @@ export default defineNuxtModule({ } // Extract macros from pages - const pageMetaOptions: PageMetaPluginOptions = { - dev: nuxt.options.dev, - sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, - } nuxt.hook('modules:done', () => { - addVitePlugin(() => PageMetaPlugin.vite(pageMetaOptions)) - addWebpackPlugin(() => PageMetaPlugin.webpack(pageMetaOptions)) + addBuildPlugin(PageMetaPlugin({ + dev: nuxt.options.dev, + sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, + })) }) // Add prefetching support for middleware & layouts diff --git a/packages/nuxt/src/pages/plugins/page-meta.ts b/packages/nuxt/src/pages/plugins/page-meta.ts index 7597aef8cd..f6645a5653 100644 --- a/packages/nuxt/src/pages/plugins/page-meta.ts +++ b/packages/nuxt/src/pages/plugins/page-meta.ts @@ -10,7 +10,7 @@ import MagicString from 'magic-string' import { isAbsolute } from 'pathe' import { logger } from '@nuxt/kit' -export interface PageMetaPluginOptions { +interface PageMetaPluginOptions { dev?: boolean sourcemap?: boolean } @@ -36,7 +36,7 @@ if (import.meta.webpackHot) { }) }` -export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) => { +export const PageMetaPlugin = (options: PageMetaPluginOptions) => createUnplugin(() => { return { name: 'nuxt:pages-macros-transform', enforce: 'post', diff --git a/packages/nuxt/test/components-transform.test.ts b/packages/nuxt/test/components-transform.test.ts index 338d470003..167229a4dc 100644 --- a/packages/nuxt/test/components-transform.test.ts +++ b/packages/nuxt/test/components-transform.test.ts @@ -4,7 +4,7 @@ import type { Component, Nuxt } from '@nuxt/schema' import { kebabCase } from 'scule' import { normalize } from 'pathe' -import { createTransformPlugin } from '../src/components/plugins/transform' +import { TransformPlugin } from '../src/components/plugins/transform' describe('components:transform', () => { it('should transform #components imports', async () => { @@ -92,7 +92,7 @@ function createTransformer (components: Component[], mode: 'client' | 'server' | }, }, } as Nuxt - const plugin = createTransformPlugin(stubNuxt, () => components, mode).vite() + const plugin = TransformPlugin(stubNuxt, () => components, mode).vite() return async (code: string, id: string) => { const result = await (plugin as any).transform!(code, id) diff --git a/packages/nuxt/test/devonly.test.ts b/packages/nuxt/test/devonly.test.ts index cf0b734f92..31a876e84c 100644 --- a/packages/nuxt/test/devonly.test.ts +++ b/packages/nuxt/test/devonly.test.ts @@ -3,7 +3,7 @@ import type { Plugin } from 'vite' import { DevOnlyPlugin } from '../src/core/plugins/dev-only' import { normalizeLineEndings } from './utils' -const pluginVite = DevOnlyPlugin.raw({}, { framework: 'vite' }) as Plugin +const pluginVite = DevOnlyPlugin({}).raw({}, { framework: 'vite' }) as Plugin const viteTransform = async (source: string, id: string) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type diff --git a/packages/nuxt/test/islandTransform.test.ts b/packages/nuxt/test/island-transform.test.ts similarity index 97% rename from packages/nuxt/test/islandTransform.test.ts rename to packages/nuxt/test/island-transform.test.ts index 5634dee92e..3743987565 100644 --- a/packages/nuxt/test/islandTransform.test.ts +++ b/packages/nuxt/test/island-transform.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it, vi } from 'vitest' import type { Plugin } from 'vite' import type { Component } from '@nuxt/schema' import type { UnpluginOptions } from 'unplugin' -import { islandsTransform } from '../src/components/plugins/islands-transform' +import { IslandsTransformPlugin } from '../src/components/plugins/islands-transform' import { normalizeLineEndings } from './utils' const getComponents = () => [{ @@ -18,16 +18,16 @@ const getComponents = () => [{ preload: false, }] as Component[] -const pluginWebpack = islandsTransform.raw({ +const pluginWebpack = IslandsTransformPlugin({ getComponents, selectiveClient: true, -}, { framework: 'webpack', webpack: { compiler: {} as any } }) +}).raw({}, { framework: 'webpack', webpack: { compiler: {} as any } }) const viteTransform = async (source: string, id: string, selectiveClient = false) => { - const vitePlugin = islandsTransform.raw({ + const vitePlugin = IslandsTransformPlugin({ getComponents, selectiveClient, - }, { framework: 'vite' }) as Plugin + }).raw({}, { framework: 'vite' }) as Plugin // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type const result = await (vitePlugin.transform! as Function)(source, id) @@ -454,7 +454,7 @@ withDefaults(defineProps<{ things?: any[]; somethingElse?: string }>(), { " `) - expect(spyOnWarn).toHaveBeenCalledWith('nuxt-client attribute and client components within islands is only supported with Vite. file: hello.server.vue') + expect(spyOnWarn).toHaveBeenCalledWith('The `nuxt-client` attribute and client components within islands are only supported with Vite. file: hello.server.vue') }) }) }) diff --git a/packages/nuxt/test/treeshake-client.test.ts b/packages/nuxt/test/treeshake-client.test.ts index 2cc0ac27c9..b0afa0cb19 100644 --- a/packages/nuxt/test/treeshake-client.test.ts +++ b/packages/nuxt/test/treeshake-client.test.ts @@ -27,7 +27,7 @@ function vuePlugin (options: Options) { const WithClientOnly = normalizeLineEndings(readFileSync(path.resolve(fixtureDir, './components/client/WithClientOnlySetup.vue')).toString()) -const treeshakeTemplatePlugin = TreeShakeTemplatePlugin.raw({ +const treeshakeTemplatePlugin = TreeShakeTemplatePlugin({ sourcemap: false, getComponents () { return [{ @@ -52,7 +52,7 @@ const treeshakeTemplatePlugin = TreeShakeTemplatePlugin.raw({ mode: 'client', }] }, -}, { framework: 'rollup' }) as Plugin +}).raw({}, { framework: 'rollup' }) as Plugin const treeshake = async (source: string): Promise => { // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type diff --git a/packages/nuxt/test/unctx-transform.test.ts b/packages/nuxt/test/unctx-transform.test.ts index df7c76ec96..42dff085dc 100644 --- a/packages/nuxt/test/unctx-transform.test.ts +++ b/packages/nuxt/test/unctx-transform.test.ts @@ -62,6 +62,6 @@ function transform (code: string, id = 'app.vue') { definePageMeta: ['middleware', 'validate'], }, } - const plugin = UnctxTransformPlugin.raw({ sourcemap: false, transformerOptions }, {} as any) as any + const plugin = UnctxTransformPlugin({ sourcemap: false, transformerOptions }).raw({}, {} as any) as any return plugin.transformInclude(id) ? Promise.resolve(plugin.transform(code)).then((r: any) => r?.code.replace(/^ {6}/gm, '').trim()) : null }