diff --git a/packages/nuxt/src/auto-imports/module.ts b/packages/nuxt/src/auto-imports/module.ts index 447d3f67780..ab5fb933ce2 100644 --- a/packages/nuxt/src/auto-imports/module.ts +++ b/packages/nuxt/src/auto-imports/module.ts @@ -38,6 +38,7 @@ export default defineNuxtModule>({ const ctx = createUnimport({ presets: options.presets, imports: options.imports, + virtualImports: ['#imports'], addons: { vueTemplate: true } @@ -58,7 +59,7 @@ export default defineNuxtModule>({ // Support for importing from '#imports' addTemplate({ filename: 'imports.mjs', - getContents: () => ctx.toExports() + getContents: () => ctx.toExports() + '\nif (process.dev) { console.warn("[nuxt] `#imports` should be transformed with real imports. There seems to be something wrong with the auto-imports plugin.") }' }) nuxt.options.alias['#imports'] = join(nuxt.options.buildDir, 'imports') diff --git a/packages/nuxt/src/auto-imports/transform.ts b/packages/nuxt/src/auto-imports/transform.ts index fb5427c4fdc..77efb5a2647 100644 --- a/packages/nuxt/src/auto-imports/transform.ts +++ b/packages/nuxt/src/auto-imports/transform.ts @@ -3,6 +3,7 @@ import { createUnplugin } from 'unplugin' import { parseQuery, parseURL } from 'ufo' import { Unimport } from 'unimport' import { AutoImportsOptions } from '@nuxt/schema' +import { normalize } from 'pathe' export const TransformPlugin = createUnplugin(({ ctx, options, sourcemap }: {ctx: Unimport, options: Partial, sourcemap?: boolean }) => { return { @@ -12,15 +13,16 @@ export const TransformPlugin = createUnplugin(({ ctx, options, sourcemap }: {ctx const { pathname, search } = parseURL(decodeURIComponent(pathToFileURL(id).href)) const { type, macro } = parseQuery(search) - const exclude = options.transform?.exclude || [/[\\/]node_modules[\\/]/] - const include = options.transform?.include || [] - - // Custom includes - exclude node_modules by default - if (exclude.some(pattern => id.match(pattern)) && !include.some(pattern => id.match(pattern))) { + // Included + if (options.transform?.include?.some(pattern => id.match(pattern))) { + return true + } + // Excluded + if (options.transform?.exclude?.some(pattern => id.match(pattern))) { return false } - // vue files + // Vue files if ( pathname.endsWith('.vue') && (type === 'template' || type === 'script' || macro || !search) @@ -28,19 +30,25 @@ export const TransformPlugin = createUnplugin(({ ctx, options, sourcemap }: {ctx return true } - // js files + // JavaScript files if (pathname.match(/\.((c|m)?j|t)sx?$/g)) { return true } }, - async transform (_code, id) { - const { code, s } = await ctx.injectImports(_code, id) - if (code === _code) { + async transform (code, id) { + id = normalize(id) + const isNodeModule = id.match(/[\\/]node_modules[\\/]/) && !options.transform?.include?.some(pattern => id.match(pattern)) + // For modules in node_modules, we only transform `#imports` but not doing auto-imports + if (isNodeModule && !code.match(/(['"])#imports\1/)) { return } - return { - code, - map: sourcemap && s.generateMap({ source: id, includeContent: true }) + + const { s } = await ctx.injectImports(code, id, { autoImport: !isNodeModule }) + if (s.hasChanged()) { + return { + code: s.toString(), + map: sourcemap && s.generateMap({ source: id, includeContent: true }) + } } } } diff --git a/test/fixtures/basic/composables/badSideEffect.ts b/test/fixtures/basic/composables/badSideEffect.ts new file mode 100644 index 00000000000..01f0bd44eb2 --- /dev/null +++ b/test/fixtures/basic/composables/badSideEffect.ts @@ -0,0 +1,5 @@ +export function badSideEffect () { + // ... +} + +throw new Error('composables/badSideEffect.ts should be tree-shaked') diff --git a/test/fixtures/basic/pages/index.vue b/test/fixtures/basic/pages/index.vue index 133f790600d..06903d38513 100644 --- a/test/fixtures/basic/pages/index.vue +++ b/test/fixtures/basic/pages/index.vue @@ -18,6 +18,8 @@