Unified utils for auto importing APIs in modules, used in nuxt and unplugin-auto-import
- Auto import register APIs for Vite, Webpack or esbuild powered by unplugin
- TypeScript declaration file generation
- Auto import for custom APIs defined under specific directories
- Auto import for Vue template
# npm npm install unimport # yarn yarn add unimport # pnpm pnpm install unimport
Powered by unplugin, unimport provides a plugin interface for bundlers.
// vite.config.js / rollup.config.js import Unimport from 'unimport/unplugin' export default { plugins: [ Unimport.vite({ /* plugin options */ }) ] }
// webpack.config.js import Unimport from 'unimport/unplugin' module.exports = { plugins: [ Unimport.webpack({ /* plugin options */ }) ] }
// ESM import { createUnimport } from 'unimport' // CommonJS const { createUnimport } = require('unimport')
const { injectImports } = createUnimport({ imports: [{ name: 'fooBar', from: 'test-id' }] }) // { code: "import { fooBar } from 'test-id';console.log(fooBar())" } console.log(injectImports('console.log(fooBar())'))
imports: [ { name: 'ref', from: 'vue' }, { name: 'useState', as: 'useSignal', from: 'react' }, ]
Will be injected as:
import { useState as useSignal } from 'react' import { ref } from 'vue'
imports: [ { name: 'default', as: '_', from: 'lodash' } ]
Will be injected as:
import _ from 'lodash'
imports: [ { name: '*', as: '_', from: 'lodash' } ]
Will be injected as:
import * as _ from 'lodash'
This is a special case for libraries authored with TypeScript's export = syntax. You don't need it the most of the time.
imports: [ { name: '=', as: 'browser', from: 'webextension-polyfill' } ]
Will be injected as:
import browser from 'webextension-polyfill'
And the type declaration will be added as:
const browser: typeof import('webextension-polyfill')
Presets are provided as a shorthand for declaring imports from the same package:
presets: [ { from: 'vue', imports: [ 'ref', 'reactive', // ... ] } ]
Will be equivalent as:
imports: [ { name: 'ref', from: 'vue' }, { name: 'reactive', from: 'vue' }, // ... ]
unimport also provides some built-in presets for common libraries:
presets: [ 'vue', 'pinia', 'vue-i18n', // ... ]
You can check out src/presets for all the options available or refer to the type declaration.
Since unimport v0.7.0, we also support auto scanning the examples from a local installed package, for example:
presets: [ { package: 'h3', ignore: ['isStream', /^[A-Z]/, /^[a-z]*$/, r => r.length > 8] } ]
This will be expanded into:
imports: [ { from: 'h3', name: 'appendHeader', }, { from: 'h3', name: 'appendHeaders', }, { from: 'h3', name: 'appendResponseHeader', }, // ... ]
The ignore option is used to filter out the exports, it can be a string, regex or a function that returns a boolean.
By default, the result is strongly cached by the version of the package. You can disable this by setting cache: false.
Unimport.vite({ dts: true // or a path to generated file })
Unimport.vite({ dirs: [ './composables/*', ] })
Scan for modules under ./composables and auto-import the named exports.
Unimport.vite({ dirs: [ './composables/**/*', { glob: './composables/nested/**/*', types: false // disable scan the type declarations } ] })
Named exports for modules under ./composables/**/* will be registered for auto imports, and filter out the types in ./composables/nested/**/*.
You can also provide custom options for directory scan, for example:
Unimport.vite({ dirsScanOptions: { filePatterns: ['*.ts'], // optional, default `['*.{ts,js,mjs,cjs,mts,cts}']`, glob patterns for matching files fileFilter: file => file.endsWith('.ts'), // optional, default `() => true`, filter files types: true, // optional, default `true`, enable/disable scan the type declarations cwd: process.cwd(), // optional, default `process.cwd()`, custom cwd for directory scan }, dirs: [ './composables/**/*', { glob: './composables/nested/**/*', types: false } ] })
You can opt-out auto-import for specific modules by adding a comment:
// @unimport-disableIt can be customized by setting commentsDisable:
Unimport.vite({ commentsDisable: [ '@unimport-disable', '@custom-imports-disable', ] })
By default, unimport uses RegExp to detect unimport entries. In some cases, RegExp might not be able to detect all the entries (false positive & false negative).
For a more accurate result, you can switch to an AST-based parser:
acorn— powered by acorn. Assumes the input is valid vanilla JavaScript, so it should usually be used after transformations and transpilation. Requires installingacornas an optional peer dependency.oxc— powered by oxc-parser. Much faster thanacornand accepts TypeScript and JSX. Requires installing eitherrolldownoroxc-parseras an optional peer dependency. (If both are installed,rolldownis preferred.)
Unimport.vite({ parser: 'oxc' // or 'acorn' or 'regex' (default) })
To use the oxc parser, install rolldown or oxc-parser alongside unimport:
npm install rolldown
# or
npm install oxc-parserTo use the acorn parser, install acorn alongside unimport:
npm install acorn
In Vue's template, the usage of API is in a different context than plain modules. Thus some custom transformations are required. To enable it, set addons.vueTemplate to true:
Unimport.vite({ addons: { vueTemplate: true } })
When auto-import a ref, inline operations won't be auto-unwrapped.
export const counter = ref(0)
<template> <!-- this is ok --> <div>{{ counter }}</div> <!-- counter here is a ref, this won't work, volar will throw --> <div>{{ counter + 1 }}</div> <!-- use this instead --> <div>{{ counter.value + 1 }}</div> </template>
We recommend using Volar for type checking, which will help you to identify the misusage.
In Vue's template, the usage of directives is in a different context than plain modules. Thus some custom transformations are required. To enable it, set addons.vueDirectives to true:
Unimport.vite({ addons: { vueDirectives: true } })
When including directives in your presets, you should:
- provide the corresponding imports with
meta.vueDirectiveset totrue, otherwise,unimportwill not be able to detect your directives. - use named exports for your directives, or use default export and use
asin the Import. - set
dtsDisabledtotrueif you provide a type declaration for your directives.
import type { InlinePreset } from 'unimport' import { defineUnimportPreset } from 'unimport' export const composables = defineUnimportPreset({ from: 'my-unimport-library/composables', /* imports and other options */ }) export const directives = defineUnimportPreset({ from: 'my-unimport-library/directives', // disable dts generation globally dtsEnabled: false, // you can declare the vue directive globally meta: { vueDirective: true }, imports: [{ name: 'ClickOutside', // disable dts generation per import dtsEnabled: false, // you can declare the vue directive per import meta: { vueDirective: true } }, { name: 'default', // you should declare `as` for default exports as: 'Focus' }] })
If you add a directory scan for your local directives in the project, you need to:
- provide
isDirectivein thevueDirectives:unimportwill use it to detect them (will never be called for imports withmeta.vueDirectiveset totrue). - use always named exports for your directives.
Unimport.vite({ dirs: ['./directives/**'], addons: { vueDirectives: { isDirective: (normalizedImportFrom, _importEntry) => { return normalizedImportFrom.includes('/directives/') } } } })
- Clone this repository
- Enable Corepack using
corepack enable(usenpm i -g corepackfor Node.js < 16.10) - Install dependencies using
pnpm install - Run interactive tests using
pnpm dev
Made with 💛
Published under MIT License.