返回专题首页

JavaScript 专题

工程化入门:npm、脚本、ESLint、Prettier 与构建工具基础

当 JavaScript 代码不再只是一个小脚本,而是要进入多人协作、持续迭代、上线部署的项目时,工程化就变成了基础设施。很多初学者会把工程化理解成“工具很多、配置很复杂”,甚至觉得它和语言学习无关。其实工程化真正解决的是:如何让代码在团队里可安装、可运行、可检查、可构建、可交付

JavaScript 专题第 13 篇 / 25 篇7 分钟

当 JavaScript 代码不再只是一个小脚本,而是要进入多人协作、持续迭代、上线部署的项目时,工程化就变成了基础设施。很多初学者会把工程化理解成“工具很多、配置很复杂”,甚至觉得它和语言学习无关。其实工程化真正解决的是:如何让代码在团队里可安装、可运行、可检查、可构建、可交付。

这一篇的目标,是把几个最常见的工程化元素放回正确位置:npm 管理依赖和脚本,Lint 和格式化负责质量护栏,构建工具负责把源码转换成适合目标环境执行的产物。它们不是彼此孤立的工具集合,而是一整条项目交付链。

npm 为什么不仅仅是“装包工具”?

很多人最先学 npm install,于是以为 npm 只是下载依赖的命令。实际上它还承担了脚本入口、依赖版本管理、项目元信息维护等重要职责。一个 JavaScript 项目能否稳定复现,很大程度上取决于包管理是否清晰、锁文件是否统一、脚本入口是否规范。

所以你在学习 npm 时,不能只记命令,而要理解几个核心点:

  • 依赖为什么会写入项目元信息;
  • 锁文件为什么对团队协作重要;
  • 脚本命令为什么要统一收口;
  • 开发依赖和运行依赖为什么要区分。

很多项目后期混乱,不是代码逻辑太难,而是工程入口从一开始就没收住。

为什么脚本系统很重要?

脚本是团队把常用操作标准化的入口。启动开发环境、执行测试、跑 Lint、做构建、生成代码、清理缓存,这些动作如果全靠每个人手写命令,不仅容易出错,也不利于协作。统一写在脚本里,可以让团队对“怎么运行项目”形成一致约定。

更重要的是,脚本本质上是在描述项目流程。谁先谁后、哪些步骤是必须的、哪些命令给谁用,都会在这里沉淀下来。所以脚本设计得好,能显著降低团队接手成本。

一个最小工程闭环通常包含什么?

对很多 JavaScript 项目来说,一个真正可交付的最小闭环通常至少包括这几步:装依赖、启动本地开发、执行最小检查、构建产物、在接近线上环境下预览。只有这几步能顺畅串起来,你才真的拥有了一套能持续演进的项目底座。

很多人会把工程化理解成“先把工具装上”,但如果这些步骤之间没有形成清晰闭环,工具再多也只是零散堆放。

ESLint 和 Prettier 为什么不能只理解成“格式工具”?

Prettier 更偏向格式统一,解决的是“长什么样”的问题;ESLint 更偏向规则约束,解决的是“这样写合不合理”的问题。两者配合的意义,并不是让代码看起来整齐,而是减少低价值争论、尽早暴露明显问题、把一部分团队约定自动化。

真正重要的是理解它们在工程里的角色:

  • 格式统一,降低阅读切换成本;
  • 规则前置,减少低级错误和不一致写法;
  • 让“团队约定”从口头规范变成可执行检查。

如果只把它们看成“保存时自动改格式”,你就会低估工程化对协作质量的价值。

为什么团队最好尽快收敛到一套默认规则?

因为规则长期摇摆会直接增加协作摩擦。有人习惯一种导入顺序,有人喜欢另一种;有人默认单引号,有人偏双引号;有人接受某种简写,有人坚持显式写法。如果这些问题一直悬而未决,团队会不断把注意力浪费在低价值争论上。

所以工程化的一个现实收益,就是帮团队尽快把“默认写法”固定下来,把精力留给真正重要的设计和业务问题。

构建工具到底在做什么?

很多人知道 Vite、Webpack、Rollup、esbuild 这些名字,却不清楚构建工具到底干了什么。简单说,它们负责把源码世界转成目标运行环境可接受的产物,并在这个过程中处理模块依赖、资源引用、环境变量、代码拆分、压缩优化等问题。

也就是说,构建工具不是“为了复杂而复杂”,而是在源码与运行环境之间做翻译和组织。你写的是现代模块化源码,浏览器上线时拿到的是经过处理的产物,这中间就需要构建系统。

为什么“本地能跑”和“构建能过”是两种不同能力?

因为本地开发环境往往更宽容,很多问题会在构建阶段才真正暴露出来,比如路径解析差异、环境变量注入缺失、某些包的构建兼容问题、动态导入或资源引用方式不规范等。也正因为如此,工程化学习不能只停留在“开发服务器能打开页面”,还要形成“经常验证构建链”的习惯。

工程化最容易踩的坑,不是工具不熟,而是边界不清

真实项目里,很多工程化问题看起来像配置细节,实际上是边界没想清楚。例如:

  • 哪些命令属于开发流程,哪些属于 CI;
  • 哪些依赖必须进入生产,哪些只在本地用;
  • 哪些规则是硬性约束,哪些只做建议;
  • 构建失败应该在哪里拦住;
  • 环境变量应该由谁提供、在哪注入。

如果这些边界不清楚,工具再多也只会把复杂度放大。

为什么很多团队最后会把 CI 拉进工程化主线?

因为只有把本地规则和 CI 规则尽量收敛到一起,工程化才不会分裂成“两套世界”。如果开发者本地只跑一部分检查,CI 上再临时补一堆脚本,那么问题就会不断后移,大家也会越来越依赖“等流水线报错再说”。更稳的做法,是尽量让本地和 CI 使用同一批关键入口,只是执行时机不同。

常见误区

这一章最常见的误区有:

  • 以为工程化就是“会配一堆工具”;
  • 只会执行命令,不理解依赖、脚本、构建之间的关系;
  • 把规则全堆给 ESLint,希望它替代设计和评审;
  • 构建报错就只看表面日志,不理解源码和产物之间的转换;
  • 团队脚本入口不统一,导致每个人各跑一套命令。

和下一篇的关系

这一篇是工程化总入口,下一篇我们会进一步进入项目内 JavaScript 的组织方式,讲模块边界、配置管理和质量护栏如何真正落到代码结构里,而不仅停留在工具层。

写在最后

工程化的本质,是让 JavaScript 项目具备稳定交付能力。它不是脱离业务的“额外复杂度”,而是帮助团队把语言能力、安全性能和协作流程真正落到项目中的桥梁。下一篇我们继续沿着这个方向走,把工程化从工具层推进到项目结构层。