2022-12-13 10:30:12 +00:00
import { addVitePlugin , addWebpackPlugin , defineNuxtModule , addTemplate , resolveAlias , useNuxt , updateTemplates } from '@nuxt/kit'
2021-10-20 09:47:18 +00:00
import { isAbsolute , join , relative , resolve , normalize } from 'pathe'
2022-12-11 21:44:52 +00:00
import type { Import , Unimport } from 'unimport'
2022-12-13 10:30:12 +00:00
import { createUnimport , scanDirExports } from 'unimport'
2022-12-11 21:44:52 +00:00
import type { ImportsOptions , ImportPresetWithDeprecation } from '@nuxt/schema'
2021-08-24 07:49:03 +00:00
import { TransformPlugin } from './transform'
2022-03-11 08:09:11 +00:00
import { defaultPresets } from './presets'
2021-08-10 00:27:23 +00:00
2022-08-23 14:22:11 +00:00
export default defineNuxtModule < Partial < ImportsOptions > > ( {
2022-01-05 18:09:53 +00:00
meta : {
2022-08-23 14:22:11 +00:00
name : 'imports' ,
configKey : 'imports'
2022-01-05 18:09:53 +00:00
} ,
2021-10-18 13:39:53 +00:00
defaults : {
2022-08-24 08:44:38 +00:00
autoImport : true ,
2022-03-11 08:09:11 +00:00
presets : defaultPresets ,
2021-10-20 09:47:18 +00:00
global : false ,
2022-03-11 08:09:11 +00:00
imports : [ ] ,
2021-12-21 14:28:45 +00:00
dirs : [ ] ,
transform : {
2022-06-10 13:33:16 +00:00
include : [ ] ,
2021-12-21 14:28:45 +00:00
exclude : undefined
2023-01-09 11:35:44 +00:00
} ,
virtualImports : [ '#imports' ]
2021-10-18 13:39:53 +00:00
} ,
async setup ( options , nuxt ) {
2022-11-10 13:52:04 +00:00
// TODO: fix sharing of defaults between invocations of modules
const presets = JSON . parse ( JSON . stringify ( options . presets ) ) as ImportPresetWithDeprecation [ ]
2021-10-18 13:39:53 +00:00
// Allow modules extending sources
2022-11-10 13:52:04 +00:00
await nuxt . callHook ( 'imports:sources' , presets )
2022-03-11 08:09:11 +00:00
2021-10-18 13:39:53 +00:00
// Filter disabled sources
2022-03-11 08:09:11 +00:00
// options.sources = options.sources.filter(source => source.disabled !== true)
2021-10-18 13:39:53 +00:00
2021-10-20 09:47:18 +00:00
// Create a context to share state between module internals
2022-03-11 08:09:11 +00:00
const ctx = createUnimport ( {
2023-01-09 11:35:44 +00:00
. . . options ,
2022-06-08 20:09:31 +00:00
addons : {
2023-01-09 11:35:44 +00:00
vueTemplate : options.autoImport ,
. . . options . addons
} ,
presets
2022-03-11 08:09:11 +00:00
} )
2021-10-20 09:47:18 +00:00
2023-01-09 11:35:44 +00:00
await nuxt . callHook ( 'imports:context' , ctx )
2022-03-16 20:36:30 +00:00
// composables/ dirs from all layers
2022-08-12 17:47:58 +00:00
let composablesDirs : string [ ] = [ ]
2022-03-16 20:36:30 +00:00
for ( const layer of nuxt . options . _layers ) {
2022-03-09 11:03:36 +00:00
composablesDirs . push ( resolve ( layer . config . srcDir , 'composables' ) )
2022-11-09 09:43:16 +00:00
composablesDirs . push ( resolve ( layer . config . srcDir , 'utils' ) )
2022-08-23 14:22:11 +00:00
for ( const dir of ( layer . config . imports ? . dirs ? ? [ ] ) ) {
2022-08-12 17:47:58 +00:00
if ( ! dir ) {
continue
}
2022-03-09 11:03:36 +00:00
composablesDirs . push ( resolve ( layer . config . srcDir , dir ) )
}
}
2022-08-23 14:22:11 +00:00
await nuxt . callHook ( 'imports:dirs' , composablesDirs )
2021-10-20 09:47:18 +00:00
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' ,
2022-10-26 08:28:00 +00:00
getContents : async ( ) = > await ctx . toExports ( ) + '\nif (process.dev) { console.warn("[nuxt] `#imports` should be transformed with real imports. There seems to be something wrong with the imports plugin.") }'
2021-11-29 11:20:57 +00:00
} )
nuxt . options . alias [ '#imports' ] = join ( nuxt . options . buildDir , 'imports' )
2022-12-13 10:30:12 +00:00
// Transform to inject imports in production mode
addVitePlugin ( TransformPlugin . vite ( { ctx , options , sourcemap : nuxt.options.sourcemap.server || nuxt . options . sourcemap . client } ) )
addWebpackPlugin ( TransformPlugin . webpack ( { ctx , options , sourcemap : nuxt.options.sourcemap.server || nuxt . options . sourcemap . client } ) )
2021-08-10 00:27:23 +00:00
2022-08-23 14:22:11 +00:00
const regenerateImports = async ( ) = > {
2022-04-26 15:52:39 +00:00
ctx . clearDynamicImports ( )
2022-03-11 08:09:11 +00:00
await ctx . modifyDynamicImports ( async ( imports ) = > {
2022-04-26 15:52:39 +00:00
// Scan composables/
imports . push ( . . . await scanDirExports ( composablesDirs ) )
// Modules extending
2022-08-23 14:22:11 +00:00
await nuxt . callHook ( 'imports:extend' , imports )
2022-03-11 08:09:11 +00:00
} )
2021-10-05 20:47:19 +00:00
}
2022-02-08 19:09:24 +00:00
2022-08-23 14:22:11 +00:00
await regenerateImports ( )
2022-02-08 19:09:24 +00:00
// Generate types
2022-08-24 08:44:38 +00:00
addDeclarationTemplates ( ctx , options )
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-08-23 14:22:11 +00:00
references . push ( { path : resolve ( nuxt . options . buildDir , 'types/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
2022-10-24 08:53:02 +00:00
const templates = [
'types/imports.d.ts' ,
'imports.d.ts' ,
'imports.mjs'
]
2021-10-20 09:47:18 +00:00
nuxt . hook ( 'builder:watch' , async ( _ , path ) = > {
const _resolved = resolve ( nuxt . options . srcDir , path )
if ( composablesDirs . find ( dir = > _resolved . startsWith ( dir ) ) ) {
2022-10-24 08:53:02 +00:00
await updateTemplates ( {
filter : template = > templates . includes ( template . filename )
} )
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 ( ) = > {
2022-08-23 14:22:11 +00:00
await regenerateImports ( )
2022-03-07 10:39:54 +00:00
} )
2021-08-10 00:27:23 +00:00
}
} )
2022-08-24 08:44:38 +00:00
function addDeclarationTemplates ( ctx : Unimport , options : Partial < ImportsOptions > ) {
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]+$/ , '' )
2022-08-12 17:47:58 +00:00
const resolved : Record < string , string > = { }
2022-03-11 08:09:11 +00:00
const r = ( { from } : Import ) = > {
if ( resolved [ from ] ) {
return resolved [ from ]
}
let path = resolveAlias ( from )
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-11 08:09:11 +00:00
2022-03-08 10:07:40 +00:00
path = stripExtension ( path )
2022-03-11 08:09:11 +00:00
resolved [ from ] = path
2021-10-20 09:47:18 +00:00
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-07-22 07:30:29 +00:00
getContents : ( ) = > ctx . toExports ( nuxt . options . buildDir )
2021-11-29 11:20:57 +00:00
} )
2021-10-20 09:47:18 +00:00
addTemplate ( {
2022-08-23 14:22:11 +00:00
filename : 'types/imports.d.ts' ,
2022-10-26 08:28:00 +00:00
getContents : async ( ) = > '// Generated by auto imports\n' + (
2022-08-24 08:44:38 +00:00
options . autoImport
2022-10-26 08:28:00 +00:00
? await ctx . generateTypeDeclarations ( { resolvePath : r } )
2022-08-24 08:44:38 +00:00
: '// Implicit auto importing is disabled, you can use explicitly import from `#imports` instead.'
)
2021-10-20 09:47:18 +00:00
} )
2021-08-10 00:27:23 +00:00
}