Nuxt 4 中 shared/ 目录深度解析:在 Vue 应用与 Nitro 服务器之间共享工具与类型

Nuxt 4 中 shared/ 目录深度解析:在 Vue 应用与 Nitro 服务器之间共享工具与类型 Nuxt 4 中 shared/ 目录深度解析在 Vue 应用与 Nitro 服务器之间共享工具与类型【免费下载链接】nuxtthe full-stack Vue framework项目地址: https://gitcode.com/GitHub_Trending/nu/nuxt本文围绕 Nuxt 的shared/目录展开它是自 Nuxt v3.14 起引入的官方目录约定让你把可以被Vue 应用客户端 服务端渲染和 Nitro 服务器API 路由、服务端中间件、服务端插件同时使用的工具函数与类型放在同一处并在两侧自动导入。读完本文你将理解shared/的目录扫描规则、#shared别名机制、共享代码的导入边界为什么不能混用 Vue 与 Nitro 代码以及多层layers场景下的共享目录行为——所有结论均对应 Nuxt 开源仓库中的实际源码与测试。shared/ 目录解决什么问题Nuxt 在构建时会产出两个独立的 bundleVue 应用包括客户端代码与服务端渲染SSR代码依赖 Vue 运行时和 Nuxt 上下文Nitro 服务器承载server/api路由、server/middleware、server/plugins等运行在服务端 Node 环境。两者独立打包、运行在不同上下文。过去如果你想在应用和服务器间共用一段纯函数或类型只能手动重复维护或用别名互相引用。shared/目录就是为此设计的共享边界其中的代码可以被两个 bundle 同时使用但它自身不能从任何一个 bundle 导入任何东西。// 一个典型的共享工具无 Vue、无 Nitro 依赖的纯函数 export const capitalize (input: string) { return input[0] ? input[0].toUpperCase() input.slice(1) : }为什么不能混用 Vue 与 Nitro 代码这是使用shared/前必须理解的硬性约束shared/目录中的代码不能导入任何 Vue 或 Nitro 代码。官方文档docs/2.directory-structure/1.shared.md给出的理由在源码层面有明确支撑。把 Vue 应用代码带进 Nitro组件与 composables 依赖 Vue 应用运行时和 Nuxt 上下文如useNuxtApp()、useRoute()这些在 Nitro 环境中都不存在。把它们导入服务器代码会导致构建或运行时错误还可能把 Vue 应用的依赖拉进服务器 bundle。把 Nitro 代码带进 Vue 应用服务端专用代码Node API、Nitro 工具、服务器路由处理器绝不能跑在浏览器里。把它们导入应用会破坏客户端构建、在浏览器中引发运行时错误或让服务端逻辑泄漏进客户端 bundle。类型导入的边界import type会在编译期被擦除不会把运行时代码带入另一个 bundle因此跨边界只导入类型表面上可以工作。但 Nuxt 仍建议把共享类型如 API 响应类型放进shared/types/——它们会在两个上下文中被自动导入。这样既保持边界清晰、避免日后把类型导入误改为值导入也与 Nuxt 为 app、server、shared 代码区分的独立类型上下文见 docs/3.guide/1.concepts/8.typescript.md保持一致。只被单侧使用的类型应放在对侧旁边app/types/仅在 Vue 应用中被自动导入server/types/见 docs/2.directory-structure/1.server.md仅在 Nitro 服务器中被自动导入只有两侧都需要时才用shared/types/。源码级证据导入保护import protectionNuxt 并非只靠文档约束这一边界而是在构建层面强制执行。从源码结构看packages/nuxt/src/core/plugins/import-protection.ts 定义了三种上下文nuxt-app | nitro-app | shared并为shared上下文生成双向禁止规则shared代码中禁止导入 Vue 应用别名#app和#buildVue app aliases are not allowed in the #shared directory.shared代码中禁止从server/api、server/routes、server/middleware、server/plugins或#server别名导入Server aliases are not allowed in the #shared directory.并提示改用$fetch()/useFetch()调用服务端端点或把共享逻辑移到shared/目录。该保护器通过ImpoundPlugin挂入构建管线分别匹配#shared/、shared绝对路径与相对路径三种写法见 packages/nuxt/src/core/nuxt.ts 中的addBuildPlugin调用因此无论你的共享文件用哪种方式引用外部代码越界都会在构建期被拦截而不只是文档上的一行警告。基本用法命名导出与默认导出在shared/utils/或shared/types/下创建工具文件Nuxt 会在应用与服务器两侧自动导入其导出无需手动 import。文档给出两种写法方式一命名导出export const capitalize (input: string) { return input[0] ? input[0].toUpperCase() input.slice(1) : }方式二默认导出export default function (input: string) { return input[0] ? input[0].toUpperCase() input.slice(1) : }创建后你可以直接在 Nuxt 应用和server/目录中使用这个自动导入的工具script setup langts const hello capitalize(hello) /script template div {{ hello }} /div /templateexport default defineEventHandler((event) { return { hello: capitalize(hello), } })自动导入的底层扫描逻辑两侧自动导入是两套扫描共同作用的结果从源码看可以确认应用侧packages/nuxt/src/imports/module.ts 在收集自动导入目录时遍历所有 layer把shared/utils与shared/types一并推入composablesDirs与composables、utils、types同列随后通过imports:dirs钩子交由 auto-imports 机制处理。因此shared/utils/shared/types的扫描方式与app/composables/和app/utils/完全一致详见 docs/3.guide/1.concepts/3.auto-imports.md。服务器侧packages/nitro-server/src/index.ts 中会把每个 layer 的shared/utils与shared/types加入 Nitro 的importDirs让 Nitro 同样自动导入这些导出。也就是说你不需要写任何额外配置capitalize在app/与server/中都是开箱即用的。文件是如何被扫描的只有两个子目录参与自动导入只有shared/utils/和shared/types/目录中的文件会被自动导入。这两个目录的子目录里嵌套的文件默认不会被自动导入除非你把对应子目录加入imports.dirs应用侧和nitro.imports.dirs服务器侧配置。-| shared/ ---| capitalize.ts # 不会被自动导入 ---| formatters -----| lower.ts # 不会被自动导入 ---| utils/ -----| lower.ts # 会被自动导入 -----| formatters -------| upper.ts # 不会被自动导入 ---| types/ -----| bar.ts # 会被自动导入这张图传达了一个容易踩坑的细节只有一层有效——utils/直接子文件自动导入但utils/formatters/里的文件不会shared/根目录下的文件如capitalize.ts也不会。需要深层文件时有两条路扩大扫描范围将子目录加入imports.dirs与nitro.imports.dirs让两侧都扫描到手动导入更常用使用 Nuxt 自动配置的#shared别名见下一节。使用 #shared 别名手动导入在shared/下创建的其他文件不在自动导入范围内的文件必须通过#shared别名手动导入这个别名由 Nuxt 自动配置。别名解析逻辑在 packages/schema/src/config/common.ts 的alias.$resolve中#shared被解析为resolve(rootDir, dir.shared)并带尾部斜杠——也就是说它指向项目根目录下的 shared 目录可通过dir.shared配置项改名无论你的文件位于app/还是server/导入路径都保持一致// 直接位于 shared 根目录的文件 import capitalize from #shared/capitalize // 嵌套目录中的文件 import lower from #shared/formatters/lower // utils 内嵌套文件夹中的文件 import upper from #shared/utils/formatters/upper多层Layers场景下的 shared/如果你使用 Nuxt 的 layers /extends机制每一层都有自己的shared/目录它们会被逐层合并扫描。从源码结构看packages/kit/src/layers.ts 在归一化每层目录时会为每个 layer 解析shared目录相对该层 root 解析支持别名前述应用侧与 Nitro 侧的扫描循环都是for (const layer of nuxt.options._layers)即按 layer 顺序收集每层的shared/utils与shared/types。这一点有测试直接验证packages/nuxt/test/shared-dir-config.test.ts 断言最终生效的导入目录包含根目录与各 extends/layers 层如extends/bar/shared/utils、layers/bar/shared/types的shared/utils与shared/types路径并特别注明 shared/types在两个上下文中都可用server/types则仅限服务器。类型测试 fixture test/fixtures/basic-types/shared/shared-types.ts 也展示了在双上下文共享类型的实际用法。关键配置与规则速查配置/规则说明默认值/取值dir.shared共享目录名相对 rootDirshared见 packages/schema/src/config/common.ts 中$resolve#shared别名手动导入共享代码的统一入口自动配置指向resolve(rootDir, dir.shared)自动导入目录应用侧与 Nitro 侧共同扫描仅shared/utils/与shared/types/一层深层文件不自动导入加入imports.dirsnitro.imports.dirs或用#shared手动导入导入边界shared代码禁止导入#app/#build/#server/ 服务器目录由 import protection 在构建期强制packages/nuxt/src/core/plugins/import-protection.ts版本要求shared/目录自 Nuxt v3.14 可用当前仓库为 Nuxt 4.x 文档体系小结shared/目录的本质是 Nuxt 官方为双 bundle 架构划出的中立共享区把跨端复用的纯函数与类型集中管理靠shared/utils与shared/types的双侧自动导入省去样板代码靠#shared别名覆盖自动导入之外的所有文件靠 layers 机制让 monorepo 式的多层项目各自扩展共享代码再由构建期的 import protection 确保这条边界不会被误用。对开发者而言实践建议很简单共享的逻辑放shared/utils共享的契约放shared/types任何依赖 Vue 或 Nitro 运行时的代码都留在各自一侧通过 HTTP$fetch/useFetch而非 import 通信。【免费下载链接】nuxtthe full-stack Vue framework项目地址: https://gitcode.com/GitHub_Trending/nu/nuxt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考