Skip to content

工程化?

当项目规模变大时,就会出现很多问题,这就是工程化要解决的问题。

出现的问题

全局污染问题

  • 随着JS文件数量和代码量的增加
  • 全局变量同名的几率将会陡然上升
  • 开发人员不得不耗费大量的精力来规避

依赖混入问题

在js中先引入哪个模块,后引入哪个模块

模块化

用来解决全局污染和依赖混入问题

  • 官方标准:ES Module
  • 社区标准:CommonJS、AMD、CMD、UMD
特性AMDCMDUMD
全称Asynchronous Module DefinitionCommon Module DefinitionUniversal Module Definition
依赖声明依赖前置(开头声明)依赖就近(用时 require)兼容多种方式
加载方式异步异步根据环境决定(异步或同步)
主要用途浏览器模块化浏览器模块化(已式微)通用库,多环境兼容
代表工具RequireJSSea.js无特定工具,是一种写法模式
是否主流曾主流,现逐渐被 ES Module 取代已不常用仍广泛用于第三方库兼容

包管理

模块化出现后,出现了大量的第三方库,这么多第三方库,如何管理?

  • npm
  • yarn
  • pnpm

Question

ES Module 库适配 CommonJS 环境

开发的 ESM 规范工具库(使用 export/import),下游用户基于 CommonJS 环境(使用 require/module.exports)无法直接引用,请问:

该问题的核心原因是什么?

ESM 和 CommonJS 是两种不兼容的模块化规范,ESM 依赖静态分析(export/import),CJS 是动态加载(require/module.exports),Node.js 无法直接用 require 加载纯 ESM 模块,会抛出 ERR_REQUIRE_ESM 错误

给出至少两种可行的解决方案,并详细说明实现步骤和优缺点。

  • 方案 1:双格式打包。通过 Rollup/tsup 等工具将库同时打包为 ESM 和 CJS 格式,在 package.json 中用 main 声明 CJS 入口、module 声明 ESM 入口
  • 方案 2:代码适配。在库入口文件中判断环境,同时通过 export 适配 ESM、module.exports 适配 CJS(仅适合简单库)

推荐最优方案,并解释理由。

双格式打包。理由:符合开源库最佳实践,对用户无感知,同时兼容 ESM/CJS 环境,可处理复杂依赖,扩展性强

JS 库适配低版本 Node.js 环境

封装的 JS 库仅适配 Node.js 24 版本,但公司老项目基于 Node.js 16,无法直接使用该库。请问:

核心适配难点是什么?

Node.js 24 与 16 存在 API / 语法差异(如 24 支持的新语法、内置 API,16 可能未实现或行为不同),且依赖的运行时特性、模块兼容逻辑也存在版本鸿沟

给出两种可行解决方案(简要说明);

  • 方案 1:代码降级兼容。使用 Babel 转译新语法,通过 polyfill 补充缺失 API,移除 Node.js 24 专属 API,确保代码在 16 环境可运行
  • 方案 2:版本分支维护。为老项目单独维护适配 Node.js 16 的库分支,核心逻辑同步更新,打包时指定目标环境为 Node.js 16

推荐最优方案并说明理由。

代码降级兼容。理由:无需维护多分支,通过工具统一适配,成本更低,且能一次性解决语法 / API 兼容问题,适配效率更高

ESM 与 CommonJS 选型决策

  • 优先选 ESM:项目基于 Node.js 14.13.0+(ESM 支持成熟)、前端工程化项目(Vite/Webpack5+)、需使用顶级 await/ES 模块特性、追求静态分析 / 树摇优化、开源库需多环境兼容
  • 选 CJS:老项目 / 依赖仅支持 CJS、Node.js 版本<14.13.0、需动态加载模块(如require(${path}/file.js))、依赖大量 CJS 专属模块(如__dirname未适配 ESM)
  • Node.js 14.13.0 是 ESM 支持从「实验性」转向「稳定版」的关键版本

By Modify.