WEBKT

别再纠结了!Node.js 新手选模块方案:require 还是 import?一文帮你做决定

8 0 0 0

在 Node.js 开发中,最让新手(甚至老手)头疼的问题之一就是:到底该用 require (CommonJS) 还是 import (ESM)?

尤其是在写一些自动化脚本、小型爬虫或者个人博客后端这种“普通小项目”时,这种纠结感尤为强烈。如果你去搜教程,有的教你 const express = require('express'),有的教你 import express from 'express'

今天我们不谈太深奥的底层原理,直接从实战效率未来趋势的角度,给你的小项目一个明确的参考答案。


一、 先给结论:普通小项目,我建议优先选 import (ESM)

如果你的 Node.js 环境在 v14.13.0 以上(现在一般都 v18 或 v20 了),新项目请无脑选择 ESM (import)

为什么?

  1. 浏览器标准对齐:JavaScript 的官方模块标准是 ESM。你在前端框架(Vue/React)里写的是 import,后端也写 import,能保持思维的高度统一。
  2. 支持顶级 await (Top-level await):这是 ESM 的杀手锏。在 import 模式下,你可以直接在文件顶层写 const data = await fetch(...),而不需要包裹在一个异步匿名函数 (async () => { ... })() 里。这对于写小工具、脚本非常爽。
  3. 生态趋势:越来越多的顶级开源库(如 node-fetch, chalk, del)在最新版本中已经彻底放弃了 CommonJS,只支持 ESM。如果你坚持用 require,你会被迫停留在这些库的旧版本上。

二、 如何在 Node.js 小项目里开启 import?

默认情况下,Node.js 认为 .js 文件是 CommonJS。要切换到 ESM,最简单的方法只需要一步:

在你的项目根目录执行 npm init -y 后,打开 package.json,添加一行:

{
  "name": "my-small-project",
  "type": "module",  // <--- 关键是这一行
  "dependencies": { ... }
}

添加这一行后,该目录下所有的 .js 文件都会被视为 ESM,你就可以愉快地使用 import 了。


三、 避坑指南:切到 ESM 后最常见的 3 个“坑”

很多同学从 require 转到 import 会报错,通常是因为以下三个原因:

1. 变量 __dirname__filename 消失了

在 CommonJS 里,这两个变量随处可用。但在 ESM 里,它们不存在
解决方法:手动通过 import.meta.url 获取。

import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

2. 引入本地文件必须带后缀

require 里,你可以写 require('./tools')。但在 ESM 中,你必须写全路径:import { myFunc } from './tools.js'注意那个 .js 不能省)。

3. 引入 JSON 文件变麻烦了

以前直接 const data = require('./config.json')。现在 ESM 下,官方标准的 JSON 导入还在实验阶段,建议这样写:

import { readFileSync } from 'fs';
const config = JSON.parse(readFileSync(new URL('./config.json', import.meta.url)));

四、 什么时候该退守使用 require?

虽然我极力推荐 import,但在以下几种情况,用 require 反而更简单:

  1. 极简的单文件脚本:如果你只想写一个不到 50 行的 .js 脚本,且不想创建 package.json,那么直接用 require 最快,不需要任何配置。
  2. 维护老旧项目:如果项目里已经有成百上千个 require,没必要为了“新潮”去大面积重构。
  3. 对启动速度极度敏感:在某些极端场景下,CommonJS 的同步加载可能比 ESM 稍快那么一点点(但在普通小项目中可以忽略不计)。

五、 核心差异一览表

特性 CommonJS (require) ESM (import)
官方状态 事实上的旧标准 ECMAScript 官方标准
加载方式 运行时同步加载 编译时静态加载(支持异步)
顶级 await 不支持 支持
默认注入 __dirname, module 无(需自行实现)
浏览器兼容 不支持(需 Webpack 等工具) 原生支持

总结

对于现在的开发者来说,import 是投资未来,require 是守望过去。

在你的下一个 Node.js 小项目里,尝试在 package.json 中加入 "type": "module",习惯 import 的节奏。你会发现,这种与前端无缝衔接的编程体验,真的非常丝滑。

架构师老李 NodejsJavaScript后端开发

评论点评