diff --git a/packages/bridge/src/auto-imports.ts b/packages/bridge/src/auto-imports.ts index 9378fc2027..bce37f8f7c 100644 --- a/packages/bridge/src/auto-imports.ts +++ b/packages/bridge/src/auto-imports.ts @@ -1,35 +1,29 @@ import { installModule, useNuxt } from '@nuxt/kit' import * as CompositionApi from '@vue/composition-api' +import type { Preset } from 'unimport' import autoImports from '../../nuxt3/src/auto-imports/module' +import { vuePreset, commonPresets, appPreset } from '../../nuxt3/src/auto-imports/presets' const UnsupportedImports = new Set(['useAsyncData', 'useFetch']) const CapiHelpers = new Set(Object.keys(CompositionApi)) -const ImportRewrites = { - vue: '@vue/composition-api' -} - export function setupAutoImports () { const nuxt = useNuxt() - nuxt.hook('autoImports:extend', (autoImports) => { - for (const autoImport of autoImports) { - // Rewrite imports - if (autoImport.from in ImportRewrites) { - autoImport.from = ImportRewrites[autoImport.from] - } - // Disable unsupported imports - if (UnsupportedImports.has(autoImport.name)) { - autoImport.disabled = true - } - if (autoImport.from === '@vue/composition-api' && !CapiHelpers.has(autoImport.name)) { - autoImport.disabled = true - } + const bridgePresets: Preset[] = [ + ...commonPresets, + { + from: '#app', + imports: [ + ...appPreset.imports.filter(i => !UnsupportedImports.has(i as string)), + 'useNuxt2Meta' + ] + }, + { + from: '@vue/composition-api', + imports: vuePreset.imports.filter(i => CapiHelpers.has(i as string)) } + ] - // Add bridge-only auto-imports - autoImports.push({ name: 'useNuxt2Meta', as: 'useNuxt2Meta', from: '#app' }) - }) - - nuxt.hook('modules:done', () => installModule(autoImports)) + nuxt.hook('modules:done', () => installModule(autoImports, { presets: bridgePresets })) } diff --git a/packages/bridge/test/auto-imports.test.ts b/packages/bridge/test/auto-imports.test.ts deleted file mode 100644 index edfba200de..0000000000 --- a/packages/bridge/test/auto-imports.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as CompositionApi from '@vue/composition-api' -import { expect, describe, it } from 'vitest' - -import { Nuxt3AutoImports } from '../../nuxt3/src/auto-imports/imports' - -const excludedVueHelpers = [ - 'EffectScope', - 'createApp', - 'createRef', - 'default', - 'del', - 'isRaw', - 'set', - 'useCSSModule', - 'version', - 'warn', - 'watchPostEffect', - 'watchSyncEffect' -] - -describe('auto-imports:vue', () => { - for (const name of Object.keys(CompositionApi)) { - if (excludedVueHelpers.includes(name)) { - continue - } - it(`should register ${name} globally`, () => { - expect(Nuxt3AutoImports.find(a => a.from === 'vue').names).to.include(name) - }) - } -}) diff --git a/packages/kit/package.json b/packages/kit/package.json index 60127d6bfa..67d63a8c70 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -29,6 +29,7 @@ "scule": "^0.2.1", "semver": "^7.3.5", "unctx": "^1.0.2", + "unimport": "0.0.8", "untyped": "^0.4.2" }, "devDependencies": { diff --git a/packages/kit/src/auto-import.ts b/packages/kit/src/auto-import.ts index cf422f97db..673774d1ef 100644 --- a/packages/kit/src/auto-import.ts +++ b/packages/kit/src/auto-import.ts @@ -1,14 +1,12 @@ -import type { AutoImport } from '../../schema/src/types/imports' +import { Import } from 'unimport' import { useNuxt } from './context' import { assertNuxtCompatibility } from './compatibility' -export function addAutoImport (_autoImports: AutoImport | AutoImport[]) { +export function addAutoImport (imports: Import | Import[]) { assertNuxtCompatibility({ bridge: true }) - useNuxt().hook('autoImports:extend', (autoImports: AutoImport[]) => { - for (const composable of (Array.isArray(_autoImports) ? _autoImports : [_autoImports])) { - autoImports.push(composable) - } + useNuxt().hook('autoImports:extend', (autoImports) => { + autoImports.push(...(Array.isArray(imports) ? imports : [imports])) }) } diff --git a/packages/nuxt3/package.json b/packages/nuxt3/package.json index 9f266add3d..bc36929930 100644 --- a/packages/nuxt3/package.json +++ b/packages/nuxt3/package.json @@ -58,6 +58,7 @@ "pathe": "^0.2.0", "scule": "^0.2.1", "ufo": "^0.7.11", + "unimport": "0.0.8", "unplugin": "^0.4.0", "untyped": "^0.4.2", "vue": "^3.2.31", diff --git a/packages/nuxt3/src/auto-imports/composables.ts b/packages/nuxt3/src/auto-imports/composables.ts index e2fad9b49e..e615b95c89 100644 --- a/packages/nuxt3/src/auto-imports/composables.ts +++ b/packages/nuxt3/src/auto-imports/composables.ts @@ -2,44 +2,45 @@ import { promises as fsp, existsSync } from 'fs' import { parse as parsePath } from 'pathe' import { findExports } from 'mlly' import { camelCase } from 'scule' -import { AutoImport } from '@nuxt/schema' import { resolveFiles } from '@nuxt/kit' -import { filterInPlace } from './utils' +import { Unimport } from 'unimport' -export async function scanForComposables (dir: string | string[], autoImports: AutoImport[]) { +export async function scanForComposables (dir: string | string[], ctx: Unimport) { const performScan = async (entry: string) => { const files = await resolveFiles(entry, [ '*.{ts,js,mjs,cjs,mts,cts}', '*/index.{ts,js,mjs,cjs,mts,cts}' ]) - await Promise.all( - files.map(async (path) => { - // Remove original entries from the same import (for build watcher) - filterInPlace(autoImports, i => i.from !== path) + await ctx.modifyDynamicImports(async (dynamicImports) => { + await Promise.all( + files.map(async (path) => { + // Remove original entries from the same import (for build watcher) + filterInPlace(dynamicImports, i => i.from !== path) - const code = await fsp.readFile(path, 'utf-8') - const exports = findExports(code) - const defaultExport = exports.find(i => i.type === 'default') + const code = await fsp.readFile(path, 'utf-8') + const exports = findExports(code) + const defaultExport = exports.find(i => i.type === 'default') - if (defaultExport) { - let name = parsePath(path).name - if (name === 'index') { - name = parsePath(path.split('/').slice(0, -1).join('/')).name - } - autoImports.push({ name: 'default', as: camelCase(name), from: path }) - } - for (const exp of exports) { - if (exp.type === 'named') { - for (const name of exp.names) { - autoImports.push({ name, as: name, from: path }) + if (defaultExport) { + let name = parsePath(path).name + if (name === 'index') { + name = parsePath(path.split('/').slice(0, -1).join('/')).name } - } else if (exp.type === 'declaration') { - autoImports.push({ name: exp.name, as: exp.name, from: path }) + dynamicImports.push({ name: 'default', as: camelCase(name), from: path }) } - } - }) - ) + for (const exp of exports) { + if (exp.type === 'named') { + for (const name of exp.names) { + dynamicImports.push({ name, as: name, from: path }) + } + } else if (exp.type === 'declaration') { + dynamicImports.push({ name: exp.name, as: exp.name, from: path }) + } + } + }) + ) + }) } for (const entry of Array.isArray(dir) ? dir : [dir]) { @@ -48,3 +49,12 @@ export async function scanForComposables (dir: string | string[], autoImports: A await performScan(entry) } } + +function filterInPlace (arr: T[], predicate: (v: T) => any) { + let i = arr.length + while (i--) { + if (!predicate(arr[i])) { + arr.splice(i, 1) + } + } +} diff --git a/packages/nuxt3/src/auto-imports/context.ts b/packages/nuxt3/src/auto-imports/context.ts deleted file mode 100644 index dcec647874..0000000000 --- a/packages/nuxt3/src/auto-imports/context.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { AutoImport } from '@nuxt/schema' -import escapeRE from 'escape-string-regexp' - -export interface AutoImportContext { - autoImports: AutoImport[] - matchRE: RegExp - transform: { - exclude: RegExp[] - } - map: Map -} - -export function createAutoImportContext (opts): AutoImportContext { - return { - autoImports: [], - map: new Map(), - matchRE: /__never__/, - transform: { - exclude: opts.transform.exclude || [/node_modules/] - } - } -} - -export function updateAutoImportContext (ctx: AutoImportContext) { - // Detect duplicates - const usedNames = new Set() - for (const autoImport of ctx.autoImports) { - if (usedNames.has(autoImport.as)) { - autoImport.disabled = true - console.warn(`Disabling duplicate auto import '${autoImport.as}' (imported from '${autoImport.from}')`) - } else { - usedNames.add(autoImport.as) - } - } - - // Filter out disabled auto imports - ctx.autoImports = ctx.autoImports.filter(i => i.disabled !== true) - - // Create regex - ctx.matchRE = new RegExp(`\\b(${ctx.autoImports.map(i => escapeRE(i.as)).join('|')})\\b`, 'g') - - // Create map - ctx.map.clear() - for (const autoImport of ctx.autoImports) { - ctx.map.set(autoImport.as, autoImport) - } - - return ctx -} diff --git a/packages/nuxt3/src/auto-imports/imports.ts b/packages/nuxt3/src/auto-imports/imports.ts deleted file mode 100644 index c056650853..0000000000 --- a/packages/nuxt3/src/auto-imports/imports.ts +++ /dev/null @@ -1,113 +0,0 @@ -import type { AutoImportSource } from '@nuxt/schema' - -export const Nuxt3AutoImports: AutoImportSource[] = [ - // #app - { - from: '#app', - names: [ - 'useAsyncData', - 'useLazyAsyncData', - 'defineNuxtComponent', - 'useNuxtApp', - 'defineNuxtPlugin', - 'useRuntimeConfig', - 'useState', - 'useFetch', - 'useLazyFetch', - 'useCookie', - 'useRequestHeaders', - 'useRouter', - 'useRoute', - 'defineNuxtRouteMiddleware', - 'navigateTo', - 'abortNavigation', - 'addRouteMiddleware' - ] - }, - // #meta - { - from: '#meta', - names: [ - 'useMeta' - ] - }, - // vue-demi (mocked) - { - from: 'vue-demi', - names: [ - 'isVue2', - 'isVue3' - ] - }, - // vue - { - from: 'vue', - names: [ - //