首页
/ Nuxt 自动导入(Auto-imports)完整指南:从内置预设、目录扫描到源码级实现原理

Nuxt 自动导入(Auto-imports)完整指南:从内置预设、目录扫描到源码级实现原理

2026-09-06 19:22:00作者:平淮齐Percy

本文围绕 Nuxt 的 Auto-imports 机制展开:它如何让组件、composables、工具函数和 Vue API 无需显式导入即可全局可用,并深入 Nuxt 源码中 nuxt:imports 模块的实际实现,讲清楚预设(presets)、目录扫描、#imports 虚拟模块与禁用控制的底层原理。读完后,你既能正确地在 nuxt.config 中配置各类自动导入选项,也能理解 Nuxt instance is unavailable 这类上下文错误的根源与修复方式。

什么是 Nuxt 自动导入

Nuxt 会自动导入(auto-import)组件、composables 和 Vue.js API,使它们在整个应用中无需显式 import 语句即可直接使用:

<script setup lang="ts">
const count = ref(1) // ref 被自动导入,无需 import { ref } from 'vue'
</script>

得益于约定优于配置的目录结构,Nuxt 会自动扫描并注册以下目录中的文件:

与传统的"全局声明"(如把函数挂到 window/globalThis)不同,Nuxt 的自动导入保留完整的 TypeScript 类型、IDE 补全和提示,并且只把真正在代码中被使用的导入注入到产物中。从源码结构看,这由 unimport 库的按需注入机制实现——编译器在构建期把用到的标识符替换为真实的 import 语句,未使用的绑定不会进入生产代码。

官方文档约定:文档中所有未显式 import 的函数都由 Nuxt 自动导入,可直接使用;完整的自动导入组件、composables 和工具函数参考见 API 章节

两点补充说明:

  • server/ 目录中,Nuxt 会自动导入 server/utils/ 导出的函数和变量(服务端由 Nitro 处理,详见 server 目录说明)。
  • 通过 nuxt.configimports 配置节,还可以为自定义文件夹或第三方包添加自动导入。

内置自动导入清单:预设(Presets)在源码中的位置

Nuxt 内置了大量自动导入的函数和 composables,覆盖数据获取应用上下文运行时配置访问、状态管理,以及组件与插件定义:

<script setup lang="ts">
/* useFetch() 是自动导入的 */
const { data, refresh, status } = await useFetch('/api/hello')
</script>

Vue 暴露的响应式 API(refcomputed 等)以及生命周期钩子、辅助函数也由 Nuxt 自动导入:

<script setup lang="ts">
/* ref() 和 computed() 均被自动导入 */
const count = ref(1)
const double = computed(() => count.value * 2)
</script>

这些"内置"导入并非魔法,而是显式声明的预设列表,集中定义在 presets.ts 中,最终汇聚到 defaultPresets 导出:

// packages/nuxt/src/imports/presets.ts
export const defaultPresets: InlinePreset[] = [
  ...commonPresets,    // vue-demi 兼容:isVue2 / isVue3
  ...granularAppPresets, // 细粒度的 Nuxt 应用内预设
  routerPreset,         // onBeforeRouteLeave / onBeforeRouteUpdate
  vuePreset,            // 来自 'vue' 的响应式 API 与生命周期钩子
  vueTypesPreset,       // 仅类型:Ref、ComputedRef、PropType 等
]

其中 granularAppPresetspresets.ts 第 15-124 行)按功能模块从 #app/composables/* 逐个声明,例如:

来源模块 自动导入的函数
#app/nuxt useNuxtApptryUseNuxtAppdefineNuxtPluginuseRuntimeConfigdefineAppConfig
#app/composables/asyncData useAsyncDatauseLazyAsyncDatauseNuxtDatarefreshNuxtDataclearNuxtDatacreateUseAsyncData
#app/composables/fetch useFetchuseLazyFetchcreateUseFetch
#app/composables/router abortNavigationaddRouteMiddlewaredefineNuxtRouteMiddlewarenavigateTouseRouteuseRouter
#app/composables/state useStateclearNuxtState
#app/composables/error clearErrorcreateErrorisNuxtErrorshowErroruseError
#app/composables/ssr onPrehydrateprerenderRoutesuseRequestHeader(s)useResponseHeaderuseRequestEventuseRequestFetchsetResponseStatus
#app/composables/head useHeaduseSeoMetauseServerHeadinjectHead

vuePresetpresets.ts 第 183-263 行)则列出了来自 vue 包的完整名单:withCtx/withDirectives<script setup> 辅助、onMounted/onUnmounted 等生命周期钩子、ref/computed/watch/reactive 等响应式 API、effectScope/onScopeDispose 等 effect 工具,以及 defineComponenthinjectnextTickuseModeluseId 等组件级 API。

此外还有两个可选预设(同样在 presets.ts 中):

  • appCompatPresets:为 requestIdleCallbacksetInterval 等注入兼容 polyfill,由 imports.polyfills(默认 true)控制,在 module.ts 的 setup 中按需并入;
  • scriptsStubsPreset:一组 useScript* 的"桩"函数,当检测到代码引用了它们时会自动安装 @nuxt/scripts 模块(见 transform.ts 第 50-52 行)。

pages 模块还会注入 pagesImportPresetsrouteRulesPresets,与默认预设合并为 allNuxtPresetsmodule.ts 第 19-23 行)。

Composables 的上下文规则:理解 "Nuxt instance is unavailable"

使用 Vue 和 Nuxt 内置的 Composition API composables 时,必须意识到其中许多依赖在**正确的上下文(context)**中被调用。

在组件生命周期期间,Vue 通过一个全局变量跟踪当前组件的临时实例(Nuxt 同样跟踪 nuxtApp 的临时实例),并在同一个 tick 结束后将其清除。这在服务端渲染中尤为关键:既能避免跨请求的状态污染(两个用户之间泄漏共享引用),也能避免不同组件之间的泄漏。

这意味着(除极少数例外),不能在 Nuxt 插件、Nuxt 路由中间件或 Vue setup 函数之外使用它们。而且必须同步使用——在调用 composable 之前不能出现 await,唯一的例外是 <script setup> 块、defineNuxtComponent 声明的组件的 setup 函数、defineNuxtPlugindefineNuxtRouteMiddleware 内部,Nuxt 会对这些位置做编译期转换,在 await 之后仍然保持同步上下文。

如果看到类似 Nuxt instance is unavailable 的错误(对应 错误 E1001),基本可以断定是在 Vue 或 Nuxt 生命周期之外的错误位置调用了 Nuxt composable。

错误示例(在模块顶层调用 composable):

// composables/example.ts
// 试图在 composable 外部访问运行时配置
const config = useRuntimeConfig()

export const useMyComposable = () => {
  // 在这里访问运行时配置
}

正确示例(在 composable 内部调用,由调用方保证上下文正确):

// composables/example.ts
export const useMyComposable = () => {
  // 因为你的 composable 在生命周期的正确位置被调用,
  // useRuntimeConfig 在这里可以正常工作
  const config = useRuntimeConfig()

  // ...
}

从源码看,这条规则的边界在 nuxt.ts 中体现得很直接:tryUseNuxtApp() 会先尝试 Vue 注入上下文(hasInjectionContext() + getCurrentInstance()),再回退到 getNuxtAppCtx(id).tryUse(),两者都失败返回 null;而 useNuxtApp() 在拿不到实例时会直接抛出 NUXT_E1001 诊断——也就是你看到的 "Nuxt instance is unavailable"。

实用建议:

  • 在非 SFC 组件中需要 Nuxt 上下文的 composable 时,用 defineNuxtComponent 代替 defineComponent 包装组件;
  • 想在异步函数中安全使用 Nuxt composables,可以关注 asyncContext 实验特性

目录级自动导入:composables/、utils/ 是如何被扫描的

Nuxt 直接自动导入约定目录中的文件:

  • app/components/ —— Vue 组件;
  • app/composables/ —— Vue composables;
  • app/utils/ —— 辅助函数和其他工具。

官方示例可参考 examples 目录 中的 features/auto-imports

注意:自动导入的 refcomputed 在组件 <template>不会被自动解包。这是 Vue 对非模板顶层 ref 的工作方式决定的,可参见 Vue 官方文档中 "Caveat when unwrapping in templates" 一节。

扫描行为的核心逻辑在 module.ts 的 setup 中:

  1. 遍历所有 layer:对每个 layer 收集 srcDir 下的 composables/utils/types/,以及 shared/utils/shared/types/,再加上该 layer 配置的 imports.dirs 自定义目录;
  2. 支持 layer 级关闭:如果某个 layer 的 config.imports.scan === false,则跳过该 layer 的扫描;
  3. 模块扩展点:通过 imports:dirs 钩子允许其他模块(如 pages 模块)追加目录;
  4. 热重启保护:监听 builder:watch,当这些目录本身被创建或删除addDir/unlinkDir)时触发 restart 钩子重启 Nuxt——因为目录级的变化无法靠增量更新覆盖。

真正的导出扫描发生在 regenerateImportsmodule.ts 第 152-186 行)中:调用 unimport 的 scanDirExports(composablesDirs, { fileFilter: file => !isIgnored(file) }) 提取各文件导出的名称,并按 layer 优先级(priorities)为扫描到的导入赋予 priority。随后触发 imports:extend 钩子让模块注册自己的导入,并做命名冲突检测——若第三方/自定义导入与 Nuxt 内置导入同名且优先级不足,会输出 NUXT_B6002 诊断(module.ts 第 170-178 行)提醒开发者。

开发时,composables/ 目录下的任何文件变化都会触发 regenerateImports 重新扫描并更新 imports.mjstypes/imports.d.ts 等模板(module.ts 第 197-210 行),这就是"新增一个 composable 保存后 IDE 立即可用"的原因。

显式导入:#imports 别名

Nuxt 通过 #imports 别名暴露所有自动导入的符号,需要显式导入时可以这样写:

<script setup lang="ts">
import { computed, ref } from '#imports'

const count = ref(1)
const double = computed(() => count.value * 2)
</script>

其实现分两步(见 module.ts 第 122-128 行):

  • 生成 build/imports.mjs 模板,内容就是当前全部自动导入的 re-export(toExports(await ctx.getImports()));
  • #imports 别名指向 buildDir/imports

TransformPlugin(transform.ts) 会在编译期把 #imports 的导入进一步替换为真实的源模块导入IMPORTS_RE 匹配 '#imports');如果产物中仍出现未经转换的 #imports,模板会打印警告 [nuxt] #imports should be transformed with real imports。值得注意的细节是:对 node_modules 中的依赖,该插件只处理 #imports 替换,不做隐式自动导入注入transform.ts 第 43-47 行),避免污染依赖代码。

禁用与控制自动导入

imports 配置的完整类型定义在 types/imports.ts 中(ImportsOptions 接口),关键开关如下。

完全禁用自动导入

imports.autoImport 设为 false

// nuxt.config.ts
export default defineNuxtConfig({
  imports: {
    autoImport: false,
  },
})

这会彻底禁用隐式自动导入,但仍可从 #imports 显式导入。从源码看,autoImport 同时影响两处:TransformPlugin 调用 injectImports 时传入的 autoImport 参数(控制是否注入),以及生成 types/imports.d.ts 时——被禁用后该文件只会输出一行注释 // Implicit auto importing is disabled, you can explicitly import from #imports instead.module.ts 第 277-291 行),从而移除全局类型声明。

模块默认值(module.ts 第 30-45 行)供参考:

defaults: nuxt => ({
  autoImport: true,
  scan: true,
  presets: defaultPresets,
  global: false,
  imports: [],
  dirs: [],
  transform: { include: [new RegExp('^' + escapeRE(nuxt.options.buildDir))] },
  virtualImports: ['#imports'],
  polyfills: true,
})

部分禁用:关闭目录扫描

希望框架级函数(refcomputed 等)保持自动导入,但关闭对自己代码(自定义 composables 等)的自动扫描时,把 imports.scan 设为 false

// nuxt.config.ts
export default defineNuxtConfig({
  imports: {
    scan: false,
  },
})

此配置下:

  • refcomputedwatch 等框架函数依然无需手动导入;
  • 自定义 composables 等需要在文件中手动 import。

注意事项:该配置有明确的局限——

  • 使用 layers 的项目需要显式导入每个 layer 中的 composables,无法再依赖自动扫描;
  • 它会破坏 layer 系统的覆盖(override)机制(扫描到的导入正是靠 layer 优先级实现覆盖的),使用前请确认理解这一副作用。

其他控制手段

结合 ImportsOptions 类型定义,还有几个实用选项:

  • imports.dirs:追加额外需要扫描的目录(相对 srcDir,支持 ~/ 别名);
  • imports.dirsScanOptions.filePatterns:扫描文件模式的 glob,默认 *.{ts,js,mjs,cjs,mts,cts,tsx,jsx}
  • imports.transform.include/exclude:正则数组,控制哪些文件参与自动导入转换;
  • imports.commentsDisable:魔法注释,默认支持 @unimport-disable@imports-disable,在单个文件头部写上即可对该文件跳过注入;
  • imports.commentsDebug:默认 @unimport-debug/@imports-debug,对指定文件打印注入详情,便于调试;
  • imports.global:将工具函数挂载到 globalThis(替代构建期转换),默认 false

禁用组件自动导入

组件的自动导入与 composables/工具的自动导入是分别配置的。禁用 ~/components 目录的组件自动导入,把 components.dirs 设为空数组(注意:这不影响模块注册的组件):

// nuxt.config.ts
export default defineNuxtConfig({
  components: {
    dirs: [],
  },
})

从第三方包自动导入

Nuxt 支持为第三方包配置自动导入。提示:如果该包有对应的 Nuxt 模块,模块通常已经替你配好了自动导入,不必重复配置。

例如为 vue-i18n 包启用 useI18n 的自动导入:

// nuxt.config.ts
export default defineNuxtConfig({
  imports: {
    presets: [
      {
        from: 'vue-i18n',
        imports: ['useI18n'],
      },
    ],
  },
})

imports.presets 接受三种形式(见 types/imports.ts):

  1. 行内预设NuxtImportPreset):from + imports 数组,如上例,也可用元组写法 ['useI18n', 'alias', 'vue-i18n']
  2. 包扫描预设NuxtPackageImportPreset):{ package: 'some-lib' },Nuxt 会扫描该包的导出自动注册,支持 ignore 排除与 cache 缓存;
  3. unimport 内置预设名NuxtImportPresetName):直接传预设名字符串。

每个预设还支持 priority(同名导入时高优先级胜出,默认 1)、disableddtsDisabled(不参与类型声明)、type/typeFrom(仅类型导入)等选项。用户配置的预设会与 Nuxt 默认预设合并——模块 setup 中先 klona 深拷贝 defaultPresets(防止被 hook 订阅者原地修改),再经过 imports:sources 钩子允许模块扩展,最后交给 createUnimport 建立统一的注入上下文(module.ts 第 46-120 行)。

工作原理小结:一次构建中发生了什么

把上述源码证据串起来,Nuxt 自动导入的完整链路是:

  1. 注册nuxt:imports 模块在 modules:done 时创建 unimport 上下文(createUnimport,parser 使用 oxc),合并默认/模块/用户预设;
  2. 扫描:对 composables/utils/ 等目录执行 scanDirExports,叠加 imports:extend 钩子注册的导入,并做冲突诊断;
  3. 产物模板:生成 build/imports.mjs#imports 别名目标)与 types/imports.d.ts(全局类型声明)、types/shared-imports.d.ts(client/server 共享上下文的类型);
  4. 编译期注入nuxt:imports-transform 插件(enforce: 'post')对 Vue SFC 与 JS 文件调用 ctx.injectImports,把用到的标识符替换为真实 import;
  5. 类型系统generateTypeDeclarations 输出全局声明,配合 resolveTypePathsfrom 解析为构建产物相对路径,保证 IDE 补全与跳转准确。

这套"按需注入 + 全局类型"的设计,正是 Nuxt 能在保留类型安全与 IDE 体验的同时,做到"生产代码只包含实际使用内容"的根本原因。

参考路径速查

内容 仓库路径
官方文档(本文骨架来源) docs/3.guide/1.concepts/3.auto-imports.md
模块实现(扫描、模板、类型) packages/nuxt/src/imports/module.ts
内置预设清单 packages/nuxt/src/imports/presets.ts
编译期转换插件 packages/nuxt/src/imports/transform.ts
imports 配置类型定义 packages/schema/src/types/imports.ts
useNuxtApp / tryUseNuxtApp 实现 packages/nuxt/src/app/nuxt.ts
E1001 错误说明 docs/errors/e1001.md
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
918
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.6 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
517
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389