让错误浮现

1 min read
Zekari
TypeScriptNext.js构建质量

构建悬挂了。

不是偶尔卡顿,而是彻底停止。进度条不动,终端无响应,只能强制退出。这种问题最令人沮丧,因为它不给你任何线索。

问题不在 Next.js,也不在 TypeScript。问题在于我们选择了掩盖。

掩盖的诱惑

打开 next.config.js,看到这行配置:

typescript: {
  ignoreBuildErrors: true
}

再看 tsconfig.json

{
  "compilerOptions": {
    "strict": false,
    "skipLibCheck": true
  }
}

这两个配置共同完成了一件事:让类型错误消失。不是修复,是隐藏。

ignoreBuildErrors: true 让构建继续,但不代表问题不存在。那些被忽略的错误会在运行时爆发,或者在构建过程的某个深层环节制造混乱。

strict: false 关闭了 TypeScript 的核心保护机制。它不会让你的代码运行得更快,只会让问题变得更隐蔽。

为什么会这样配置?通常是因为:

  • 遗留代码太多,类型错误修不完
  • 赶项目进度,先让它能跑起来
  • 不理解严格模式的价值,觉得它碍事

但掩盖问题从来不会让问题消失。它们只是转移到更难发现的地方。

错误的本质

错误不是敌人。错误是信号。

当 TypeScript 报告类型错误时,它在说:"这里的逻辑不够清晰,可能会出问题。"当构建系统悬挂时,它在说:"有些东西不对劲,我无法处理。"

如果我们选择忽略这些信号,系统就会进入一种混乱状态:

  • 类型系统无法提供准确的推导
  • 构建工具不知道如何处理不明确的代码
  • 运行时可能遇到意外的类型冲突

这不是工具的问题,是我们选择掩盖的结果。

参考 fast-type-checking 了解类型检查的性能优化方法,参考 extending-typescript-config 了解如何合理配置 TypeScript。

让错误浮现

修复的方法很简单:停止掩盖。

首先修改 next.config.js,移除或改为:

typescript: {
  ignoreBuildErrors: false
}

然后修改 tsconfig.json,启用严格模式:

{
  "compilerOptions": {
    "strict": true
  }
}

接下来运行类型检查:

npx tsc --noEmit

这个命令会暴露所有被掩盖的类型错误。可能有几十个,甚至几百个。这很正常。这些错误本来就在那里,只是被隐藏了。

现在你面对的是真实的问题清单。逐个修复它们。可能需要几个小时,甚至几天。但每修复一个错误,代码就变得更清晰、更安全。

当所有错误都解决后,再次运行构建:

npm run build

构建不会再悬挂。因为那些导致混乱的隐患已经被清除。

修复类型错误能解决大部分构建悬挂问题,但不是全部。如果启用严格模式并修复所有类型错误后,构建仍然悬挂,可能需要检查:

  • 依赖版本冲突(npm ls 查看依赖树)
  • 循环依赖(使用 madge 等工具检测)
  • 内存不足(尝试增加 Node.js 内存限制:NODE_OPTIONS=--max-old-space-size=4096
  • 构建工具配置问题(检查 Webpack、Babel 等配置)

但首要任务始终是让类型系统健康。只有在类型清晰的基础上,才能有效诊断其他问题。

如果错误太多难以一次性处理,可以采用渐进式策略:

  1. 先启用 ignoreBuildErrors: false,但保持 strict: false
  2. 修复所有当前可见的错误
  3. 逐步启用严格模式的单个选项(如 noImplicitAnystrictNullChecks
  4. 每启用一个选项,修复相应的错误
  5. 最终完全启用 strict: true

这种方法更温和,但需要更多耐心。关键是不要停下来,不要回退。

质量不是选项

严格类型检查不是额外的工作,而是基本的质量保证。它不会拖慢开发速度,反而会减少调试时间和线上问题。

当你选择 ignoreBuildErrors: true 时,你在说:"我不在乎这些错误。"但系统会在乎。它会用更隐蔽、更难修复的方式提醒你。

当你选择 strict: false 时,你在说:"我不需要类型安全。"但类型安全不是可有可无的装饰,它是代码可维护性的基础。

技术债不是欠了多少行代码要重写,而是欠了多少问题要解决。每一个被掩盖的错误都是一笔债。利息会复利增长。

让错误浮现,不是为了制造麻烦,而是为了面对真相。只有看到问题,才能解决问题。

最后

构建悬挂问题修复了。不是因为我们找到了某个神奇的配置,而是因为我们停止了掩盖。

那些被忽略的类型错误终于暴露出来,被逐个修复。代码变得更清晰,构建变得更稳定。

这不是一个关于技术的故事,而是关于选择的故事。每一次选择掩盖问题,我们都在为未来的混乱买单。每一次选择面对问题,我们都在为长期的质量投资。

质量不是一次性的行动,而是持续的选择。

选择让错误浮现,而不是让它们沉没。

Related Posts

Articles you might also find interesting

继承基础配置

2 min read

配置不需要重复书写。继承机制让每个层次只表达自己的差异。

TypeScript配置管理
Read More

Purikura的页面系统

3 min read

通过五层分层继承复用架构,实现零代码修改的页面生成系统。从类型定义到页面渲染,每一层专注单一职责,实现真正的数据驱动开发。

架构设计React
Read More

动态元数据生成:让机器读懂你的页面

2 min read

generateMetadata 不只是填写表单。它决定了搜索引擎、社交平台、AI 系统如何理解和呈现你的内容。

Next.jsSEO
Read More

tsc --noEmit:即时类型反馈

2 min read

类型错误不应该等到构建时才发现。最快的反馈来自最简单的命令。

TypeScript类型检查
Read More

Google Fonts 官方集成

2 min read

Next.js 提供了 next/font 模块,让字体加载变得简单且性能优化。Google Fonts 是最直接的商用免费字体选择。

Next.js字体
Read More

全局安装 TypeScript

1 min read

当 tsc 命令未找到时,你缺少的不是命令,而是编译器本身。

TypeScript开发工具
Read More

next-intl localePrefix:默认语言不显示前缀

2 min read

理解 next-intl 中 localePrefix 配置的设计哲学,以及为什么默认语言不应在 URL 中显现。

Next.jsi18n
Read More

next-intl 的服务端与客户端协同机制

3 min read

理解 next-intl 如何在 Next.js App Router 中协调服务端渲染和客户端交互,以及为什么需要显式设置 locale。

Next.jsi18n
Read More

减少 Next.js 启动时的工作量

2 min read

开发服务器启动缓慢不是偶然。它在做的事太多了。

Next.js性能优化
Read More

运行时类型契约

4 min read

TypeScript 的类型在编译后消失。真正的安全需要在边界处延续类型契约。

类型系统TypeScript
Read More

用静态导出控制视口

2 min read

Next.js 中的视口配置通过静态导出模式定义页面初始状态,理解其背后的设计约束能够更好地控制用户体验边界。

Next.js视口
Read More