unimport

repository·main·Indexed 20 days ago

https://github.com/unjs/unimport

A unified utility for auto-importing APIs in modules, used by Nuxt and unplugin-auto-import. It allows developers to use APIs without explicit import statements by automatically injecting them during the build process. Features include directory scanning for exports, TypeScript type declaration generation, and built-in presets for frameworks like Vue, React, Svelte, and SolidJS.

Tokens
5.9K
Snippets
25
Records
26
Agent score
72%

What's inside unimport

  1. Define Auto-import Presets

    main

    Unimport supports two main types of presets to automate import registration:

    InlinePreset

    Allows you to define a group of imports manually. Each preset can contain nested imports.

    PackagePreset

    Automatically extracts exports from a specific npm package.

    • package: The name of the package.
    • url: The path of the importer (defaults to process.cwd()).
    • ignore: A RegExp, string, or function to exclude specific names from being auto-imported.
    • cache: Whether to use a local cache (defaults to true).
    // Example of an InlinePreset structure
    const myPreset: InlinePreset = {
      from: 'my-library',
      imports: [
        { name: 'funcA' },
        { name: 'funcB', as: 'otherName' }
      ]
    };
    
    // Example of a PackagePreset
    const pkgPreset: PackagePreset = {
      package: 'lodash-es',
      ignore: ['cloneDeep']
    };
  2. Configure Vue Addons for Auto-imports

    main

    Unimport provides built-in support for Vue-specific auto-importing via the addons option:

    • vueTemplate: Enables auto-imports inside Vue <template> blocks.
    • vueDirectives: Enables auto-importing of Vue directives in SFCs.

    To use custom directives with vueDirectives, provide an isDirective callback that determines if a specific import should be treated as a directive.

    Note: For library authors, ensure your imports include meta.vueDirective: true in their metadata so they are recognized correctly.

    const options: UnimportOptions = {
      addons: {
        vueTemplate: true,
        vueDirectives: {
          isDirective: (from, importEntry) => {
            // Logic to identify if 'from' is a local directive
            return from.includes('local-directives');
          }
        }
      }
    };
  3. Configure Unimport via UnimportPluginOptions

    main

    When using unimport as a plugin (e.g., via unplugin), you can provide an options object of type UnimportPluginOptions. This allows you to control which files are processed, how TypeScript definitions are generated, and whether auto-imports are enabled.

    Options

    • include: A FilterPattern defining which files to include. Defaults to [/\.[jt]sx?$/, /\.vue$/, /\.vue\?vue/, /\.svelte$/] if not provided.
    • exclude: A FilterPattern defining which files to exclude. Defaults to [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/] if not provided.
    • dts: Controls TypeScript declaration generation.
      • true: Generates unimport.d.ts.
      • string: Generates a file at the specified path.
      • false (or omitted): Disables generation.
    • autoImport: (Boolean, default: true) Enables implicit auto-importing of symbols.
    // Example configuration shape
    {
      include: /src/,
      exclude: /tests/,
      dts: 'my-imports.d.ts',
      autoImport: true
    }
  4. Configure Unimport via UnimportOptions

    main

    When initializing unimport, you can provide an UnimportOptions object to define how auto-imports behave. Key configuration areas include:

    • Imports & Presets: Define specific imports or use presets (which can be InlinePreset or PackagePreset).
    • Addons: Enable specialized features like vueTemplate or vueDirectives.
    • Scanning: Specify directories to scan using dirs and dirsScanOptions.
    • Parsing: Choose a parser ('regex', 'acorn', or 'oxc').
    • Injection: Control where imports are placed using injectAtEnd and whether to mergeExisting imports.
    • Virtual Modules: Define virtualImports to expose all registered auto-imports via a virtual module.
    const options: UnimportOptions = {
      imports: [{ name: 'ref', from: 'vue' }],
      presets: ['vue'],
      addons: {
        vueTemplate: true,
        vueDirectives: true
      },
      virtualImports: ['virtual:imports'],
      dirs: ['src/composables'],
      parser: 'oxc'
    };
  5. Initialize unimport with createUnimport()

    main

    To use unimport programmatically, call createUnimport(opts) with your desired configuration. This returns an Unimport instance that provides methods for scanning, detecting, and injecting imports into your code.

    Common configuration options include:

    • imports: An array of static imports to include.
    • presets: An array of built-in presets to resolve.
    • dirs: Directories to scan for exports.
    • collectMeta: If true, enables metadata collection for tracking injection usage.
    • commentsDisable: Array of comment strings that, if present in a file, prevent any imports from being injected (default: ['@unimport-disable', '@imports-disable']).
    • commentsDebug: Array of comment strings that, if present, trigger debug logging of detected imports (default: ['@unimport-debug', '@imports-debug']).
    import { createUnimport } from 'unimport'
    
    const unimport = createUnimport({
      imports: ['myStaticImport'],
      presets: ['vue'],
      dirs: ['./src/components']
    })
  6. Generate import strings with `stringifyImports`

    main

    The stringifyImports function converts an array of Import objects into valid JavaScript import or require statements. It supports both ESM (import ... from ...) and CommonJS (const ... = require(...)) formats.

    It handles several special import patterns:

    • Side-effect imports: import 'module' or require('module').
    • Default imports: import name from 'module' or const { default: name } = require('module').
    • Namespace imports: import * as name from 'module' or const name = require('module').
    • Named imports: import { a, b } from 'module' or const { a, b } = require('module').
    • Import Attributes: Supports the with { ... } syntax for ESM imports.
    import { stringifyImports } from 'unimport'
    
    // Example usage (conceptual):
    // const code = stringifyImports(myImports, false) // ESM
    // const cjsCode = stringifyImports(myImports, true) // CJS
  7. Generate TypeScript type declarations

    main

    You can generate .d.ts files for your injected imports using generateTypeDeclarations(). This ensures that the automatically injected variables are recognized by the TypeScript compiler.

    Options (TypeDeclarationOptions):

    • typeReExports: If true (default), it generates re-exports for type-only imports.
    • resolvePath: A function to resolve the path for an import (defaults to stripping file extensions).

    Returns: A string containing the generated TypeScript declaration content.

    const dts = await unimport.generateTypeDeclarations({
      typeReExports: true
    })
  8. Inject imports into code with `addImportToCode`

    main

    The addImportToCode function uses magic-string to programmatically inject import statements into existing source code. It is highly configurable to allow for precise placement and merging.

    Key Options:

    • code: The original source code (string or MagicString).
    • imports: An array of Import objects to inject.
    • isCJS: Whether to generate CommonJS require statements.
    • mergeExisting: If true and using ESM, it attempts to merge new imports into existing curly-brace imports from the same module.
    • injectAtLast: If true, injects imports at the end of the import block rather than at the top.
    • firstOccurrence: The index used to determine where to inject if not at the very top.
    • onResolved: A callback to transform the imports before they are stringified.
    • onStringified: A callback to transform the resulting import string.
    import { addImportToCode } from 'unimport'
    
    const result = addImportToCode(originalCode, imports, false, true)
    console.log(result.code)
  9. Resolve and manage presets

    main

    Unimport uses presets to define sets of auto-imports. You can interact with them using the following utilities:

    • resolvePreset(name): Resolves a specific preset by name.
    • resolveBuiltinPresets(): Returns a list of all available built-in presets.
    • builtinPresets: An object containing the collection of built-in presets.
    • BuiltinPresetName: A type representing the valid names of built-in presets.
    import { resolvePreset, resolveBuiltinPresets, builtinPresets, type BuiltinPresetName } from 'unimport'
    
    // Example: resolving a preset
    const myPreset = resolvePreset('some-preset-name' as BuiltinPresetName)
  10. Manage dynamic imports manually

    main

    Unimport allows you to programmatically control the list of dynamic imports that are considered during detection and injection.

    • modifyDynamicImports(fn): Allows you to mutate the current list of dynamic imports using a callback function.
    • clearDynamicImports(): Removes all currently registered dynamic imports.
    • getImports(): Returns the current list of all combined imports (static + dynamic).
    // Add a custom dynamic import manually
    await unimport.modifyDynamicImports(imports => {
      return [...imports, { name: 'customVar', from: 'my-module' }]
    })
    
    // Clear them all
    unimport.clearDynamicImports()
  11. Scan directories and files for exports

    main

    Unimport can scan your project structure to discover available exports and add them to its internal registry.

    • scanImportsFromDir(dirs, options): Scans the provided directories for exports. This is useful for automatically discovering components or utilities in a project.
    • scanImportsFromFile(filepath, includeTypes): Scans a specific file for exports and adds them to the dynamic imports list.
    • init(): A convenience method that triggers scanImportsFromDir using the directories provided in the initial configuration.
    // Initialize and scan configured directories
    await unimport.init()
    
    // Or manually scan a specific file
    await unimport.scanImportsFromFile('./src/utils/math.ts')
  12. Inject imports into code with injectImports()

    main

    The injectImports method is the primary way to automatically add import statements to a string of code (or a MagicString instance). It detects which imports are needed based on the code content and returns a result containing the modified code and the list of imports added.

    Key features:

    • Automatic Detection: Uses detectImports to find matches.
    • Context Awareness: Handles CJS/ESM contexts.
    • Customization: Supports mergeExisting and injectAtEnd options.
    • Addon Support: Allows addons to transform the code or modify the resolved imports before injection.

    Options (InjectImportsOptions):

    • mergeExisting: Whether to merge with existing imports in the file.
    • injectAtEnd: Whether to inject imports at the end of the file instead of the top.

    Returns: An object containing the modified MagicString (or string) and the imports array.

    const result = await unimport.injectImports(code, 'my-file.ts', {
      mergeExisting: true,
      injectAtEnd: false
    })
    
    console.log(result.imports)
    // The modified code can be accessed via result.s.toString()