2021-10-20 09:47:18 +00:00
|
|
|
import { addVitePlugin, addWebpackPlugin, defineNuxtModule, addTemplate, resolveAlias, addPluginTemplate, useNuxt } from '@nuxt/kit'
|
2021-11-21 16:14:46 +00:00
|
|
|
import type { AutoImportsOptions } from '@nuxt/schema'
|
2021-10-20 09:47:18 +00:00
|
|
|
import { isAbsolute, join, relative, resolve, normalize } from 'pathe'
|
2022-02-07 13:45:47 +00:00
|
|
|
import { genDynamicImport } from 'knitwork'
|
2021-08-24 07:49:03 +00:00
|
|
|
import { TransformPlugin } from './transform'
|
2021-10-18 13:39:53 +00:00
|
|
|
import { Nuxt3AutoImports } from './imports'
|
2021-10-20 09:47:18 +00:00
|
|
|
import { scanForComposables } from './composables'
|
2021-11-29 11:20:57 +00:00
|
|
|
import { toExports, toImports } from './utils'
|
2021-10-20 09:47:18 +00:00
|
|
|
import { AutoImportContext, createAutoImportContext, updateAutoImportContext } from './context'
|
2021-08-10 00:27:23 +00:00
|
|
|
|
2021-10-11 08:07:27 +00:00
|
|
|
export default defineNuxtModule<AutoImportsOptions>({
|
2022-01-05 18:09:53 +00:00
|
|
|
meta: {
|
|
|
|
name: 'auto-imports',
|
|
|
|
configKey: 'autoImports'
|
|
|
|
},
|
2021-10-18 13:39:53 +00:00
|
|
|
defaults: {
|
|
|
|
sources: Nuxt3AutoImports,
|
2021-10-20 09:47:18 +00:00
|
|
|
global: false,
|
2021-12-21 14:28:45 +00:00
|
|
|
dirs: [],
|
|
|
|
transform: {
|
|
|
|
exclude: undefined
|
|
|
|
}
|
2021-10-18 13:39:53 +00:00
|
|
|
},
|
|
|
|
async setup (options, nuxt) {
|
|
|
|
// Allow modules extending sources
|
|
|
|
await nuxt.callHook('autoImports:sources', options.sources)
|
|
|
|
|
|
|
|
// Filter disabled sources
|
|
|
|
options.sources = options.sources.filter(source => source.disabled !== true)
|
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
// Create a context to share state between module internals
|
2021-12-21 14:28:45 +00:00
|
|
|
const ctx = createAutoImportContext(options)
|
2021-10-20 09:47:18 +00:00
|
|
|
|
|
|
|
// composables/ dirs
|
|
|
|
let composablesDirs = [
|
|
|
|
join(nuxt.options.srcDir, 'composables'),
|
|
|
|
...options.dirs
|
|
|
|
]
|
2022-03-09 11:03:36 +00:00
|
|
|
|
|
|
|
// Extend with layers
|
|
|
|
for (const layer of nuxt.options._extends) {
|
|
|
|
composablesDirs.push(resolve(layer.config.srcDir, 'composables'))
|
|
|
|
for (const dir of (layer.config.autoImports?.dirs ?? [])) {
|
|
|
|
composablesDirs.push(resolve(layer.config.srcDir, dir))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
await nuxt.callHook('autoImports:dirs', composablesDirs)
|
|
|
|
composablesDirs = composablesDirs.map(dir => normalize(dir))
|
2021-10-12 12:24:43 +00:00
|
|
|
|
2021-11-29 11:20:57 +00:00
|
|
|
// Support for importing from '#imports'
|
|
|
|
addTemplate({
|
|
|
|
filename: 'imports.mjs',
|
|
|
|
getContents: () => toExports(ctx.autoImports)
|
|
|
|
})
|
|
|
|
nuxt.options.alias['#imports'] = join(nuxt.options.buildDir, 'imports')
|
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
// Transpile and injection
|
|
|
|
// @ts-ignore temporary disabled due to #746
|
2021-10-18 13:39:53 +00:00
|
|
|
if (nuxt.options.dev && options.global) {
|
2021-08-10 00:27:23 +00:00
|
|
|
// Add all imports to globalThis in development mode
|
|
|
|
addPluginTemplate({
|
2021-10-11 08:07:27 +00:00
|
|
|
filename: 'auto-imports.mjs',
|
2021-08-10 00:27:23 +00:00
|
|
|
getContents: () => {
|
2021-10-20 09:47:18 +00:00
|
|
|
const imports = toImports(ctx.autoImports)
|
|
|
|
const globalThisSet = ctx.autoImports.map(i => `globalThis.${i.as} = ${i.as};`).join('\n')
|
2021-08-10 00:27:23 +00:00
|
|
|
return `${imports}\n\n${globalThisSet}\n\nexport default () => {};`
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
// Transform to inject imports in production mode
|
2021-10-20 09:47:18 +00:00
|
|
|
addVitePlugin(TransformPlugin.vite(ctx))
|
|
|
|
addWebpackPlugin(TransformPlugin.webpack(ctx))
|
2021-08-10 00:27:23 +00:00
|
|
|
}
|
|
|
|
|
2022-02-08 19:09:24 +00:00
|
|
|
const regenerateAutoImports = async () => {
|
|
|
|
// Resolve autoimports from sources
|
|
|
|
ctx.autoImports = options.sources.flatMap(source => source.names.map(
|
|
|
|
importName => typeof importName === 'string'
|
|
|
|
? { name: importName, as: importName, from: source.from }
|
|
|
|
: { name: importName.name, as: importName.as || importName.name, from: source.from }
|
|
|
|
))
|
2021-10-20 09:47:18 +00:00
|
|
|
// Scan composables/
|
2022-03-07 10:39:54 +00:00
|
|
|
await scanForComposables(composablesDirs, ctx.autoImports)
|
2021-10-20 09:47:18 +00:00
|
|
|
// Allow modules extending
|
|
|
|
await nuxt.callHook('autoImports:extend', ctx.autoImports)
|
|
|
|
// Update context
|
|
|
|
updateAutoImportContext(ctx)
|
2021-10-05 20:47:19 +00:00
|
|
|
}
|
2022-02-08 19:09:24 +00:00
|
|
|
|
|
|
|
await regenerateAutoImports()
|
|
|
|
|
|
|
|
// Generate types
|
|
|
|
addDeclarationTemplates(ctx)
|
2021-08-11 20:28:38 +00:00
|
|
|
|
2021-10-20 12:53:13 +00:00
|
|
|
// Add generated types to `nuxt.d.ts`
|
|
|
|
nuxt.hook('prepare:types', ({ references }) => {
|
2022-02-07 10:20:01 +00:00
|
|
|
references.push({ path: resolve(nuxt.options.buildDir, 'types/auto-imports.d.ts') })
|
2022-02-15 09:50:11 +00:00
|
|
|
references.push({ path: resolve(nuxt.options.buildDir, 'imports.d.ts') })
|
2021-10-20 12:53:13 +00:00
|
|
|
})
|
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
// Watch composables/ directory
|
|
|
|
nuxt.hook('builder:watch', async (_, path) => {
|
|
|
|
const _resolved = resolve(nuxt.options.srcDir, path)
|
|
|
|
if (composablesDirs.find(dir => _resolved.startsWith(dir))) {
|
2022-02-08 19:09:24 +00:00
|
|
|
await nuxt.callHook('builder:generateApp')
|
2021-10-20 09:47:18 +00:00
|
|
|
}
|
2021-08-10 00:27:23 +00:00
|
|
|
})
|
2022-03-07 10:39:54 +00:00
|
|
|
|
|
|
|
nuxt.hook('builder:generateApp', async () => {
|
|
|
|
await regenerateAutoImports()
|
|
|
|
})
|
2021-08-10 00:27:23 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-02-08 19:09:24 +00:00
|
|
|
function addDeclarationTemplates (ctx: AutoImportContext) {
|
2021-10-20 09:47:18 +00:00
|
|
|
const nuxt = useNuxt()
|
|
|
|
|
2022-03-08 10:07:40 +00:00
|
|
|
// Remove file extension for benefit of TypeScript
|
|
|
|
const stripExtension = (path: string) => path.replace(/\.[a-z]+$/, '')
|
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
const resolved = {}
|
|
|
|
const r = (id: string) => {
|
|
|
|
if (resolved[id]) { return resolved[id] }
|
2022-02-07 21:00:20 +00:00
|
|
|
let path = resolveAlias(id)
|
2021-10-20 09:47:18 +00:00
|
|
|
if (isAbsolute(path)) {
|
2022-02-07 10:20:01 +00:00
|
|
|
path = relative(join(nuxt.options.buildDir, 'types'), path)
|
2021-08-10 00:27:23 +00:00
|
|
|
}
|
2022-03-08 10:07:40 +00:00
|
|
|
path = stripExtension(path)
|
2021-10-20 09:47:18 +00:00
|
|
|
resolved[id] = path
|
|
|
|
return path
|
2021-10-18 13:39:53 +00:00
|
|
|
}
|
2021-10-20 09:47:18 +00:00
|
|
|
|
2021-11-29 11:20:57 +00:00
|
|
|
addTemplate({
|
2022-02-15 09:50:11 +00:00
|
|
|
filename: 'imports.d.ts',
|
2022-03-08 10:07:40 +00:00
|
|
|
getContents: () => toExports(ctx.autoImports.map(i => ({ ...i, from: stripExtension(i.from) })))
|
2021-11-29 11:20:57 +00:00
|
|
|
})
|
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
addTemplate({
|
2022-02-07 10:20:01 +00:00
|
|
|
filename: 'types/auto-imports.d.ts',
|
2021-10-20 09:47:18 +00:00
|
|
|
getContents: () => `// Generated by auto imports
|
|
|
|
declare global {
|
2022-02-07 13:45:47 +00:00
|
|
|
${ctx.autoImports.map(i => ` const ${i.as}: typeof ${genDynamicImport(r(i.from), { wrapper: false })}['${i.name}']`).join('\n')}
|
2021-10-20 09:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export {}
|
|
|
|
`
|
|
|
|
})
|
2021-08-10 00:27:23 +00:00
|
|
|
}
|