错误点名导入方,但不总是根因
Failed to resolve import "./Button" 通常表示文件不在导入指定的位置,但差异可能很隐蔽:大小写、扩展名、TypeScript 与打包器解析不同的别名,或被 exports 阻止的包子路径。macOS 上能工作是因为文件系统不区分大小写;Linux CI 会在 Button 与 button 上失败。
src/components/button.tsx
import { Button } from './Button'; // works on macOS, fails on Linux
用解析调试运行打包器,并把尝试路径与 find src -iname 对比。把源码路径改成确切大小写,或一致地重命名文件。
别名必须一致
如果 @/components 只在 tsconfig.json 配置而没配在 vite.config.ts,编辑器通过但构建失败。应从单一来源在两处配置别名,或使用相对导入。Jest、Vitest 和任何独立解析模块的服务端运行时同理。
// vite.config.ts
resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }
检查包 exports
包可能已安装,却没有暴露你导入的子路径。exports 映射对现代 Node 和打包器具有权威性。即使文件存在于 node_modules,import 'pkg/internal/foo' 也可能失败。应导入文档化的入口,或通过包的公开 API 添加子路径。不要用深入 node_modules 的相对路径绕过 exports。
修复与验证
修正路径、别名、依赖或导入目标。在类 Linux 环境或 CI 中执行干净安装和构建,确认产物包含该模块且页面渲染。仅本地 macOS 构建不能作为证据,因为它没有检验大小写敏感解析。不要关闭解析检查或添加宽泛回退;它们会掩盖真实的不匹配,并可能加载错误实现。