news 2026/8/14 14:18:33

Node.js入门教程(二十):模块导入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Node.js入门教程(二十):模块导入

一、模块系统概述

当你开始写 Node.js 项目时,最先遇到的问题之一就是——如何导入模块(module)。

在 Node.js 里,模块就是可以重复使用的 JavaScript 文件,它们之间通过导入(import)和导出(export)互相通信。

Node.js 生态系统主要支持两种模块系统:

模块系统规范文件扩展名导入方式导出方式
CommonJSNode.js 早期使用.jsrequire()module.exports/exports
ES Module (ESM)ECMAScript 标准.mjs"type": "module"importexport/export default

二、CommonJS 模块系统

CommonJS 是 Node.js 最早也是最广泛使用的模块系统,它采用同步加载的方式,这意味着模块在加载时会阻塞程序的执行,直到加载完成。

导出模块

在 CommonJS 中,使用module.exportsexports对象来导出模块。

// math.js function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } // 方式一:使用 module.exports 导出对象 module.exports = { add, subtract }; // 方式二:使用 exports 逐个导出 // exports.add = add; // exports.subtract = subtract;

导入模块

使用require()函数来导入模块:

// app.js const math = require('./math.js'); console.log(math.add(2, 3)); // 5 console.log(math.subtract(5, 2)); // 3 // 也可以解构导入 const { add, subtract } = require('./math.js'); console.log(add(2, 3)); // 5

module.exports 与 exports 的区别

// user.js const name = 'Alice'; const age = 30; // 方式一:使用 module.exports 导出单个对象 module.exports = { name: name, age: age, sayHello: () => { console.log(`Hello, my name is ${name}.`); } }; // 方式二:使用 exports 导出多个具名变量 // exports 是 module.exports 的一个引用 // exports.name = name; // exports.age = age; // exports.sayHello = () => { // console.log(`Hello, my name is ${name}.`); // };
// main.js const user = require('./user.js'); console.log(user.name); // 输出: Alice user.sayHello(); // 输出: Hello, my name is Alice. // 也可以直接解构 const { name, age } = require('./user.js'); console.log(name); // 输出: Alice

CommonJS 特点

特点说明
同步加载适合服务器端环境,模块通常都在本地文件系统中,加载速度快
运行时加载require()可以在代码的任何位置调用,支持条件动态加载
缓存机制require()加载的模块会被缓存,第二次导入时直接从缓存中读取,避免重复加载

三、ES Module(ESM)规范

ESM 是 JavaScript 官方的模块标准,它采用异步加载,是浏览器和现代 Node.js 应用的首选。

启用 ESM

要在 Node.js 中使用 ESM,有两种方式:

方式一:在package.json中添加"type": "module"

{ "type": "module" }

方式二:将文件扩展名更改为.mjs

导出模块

ESM 支持两种导出方式:具名导出默认导出

// math.mjs // 具名导出 export function add(a, b) { return a + b; } export function subtract(a, b) { return a - b; } export const PI = 3.14159; // 默认导出 export default function multiply(a, b) { return a * b; }

导入模块

// app.mjs // 导入具名导出 import { add, subtract, PI } from './math.mjs'; // 导入默认导出(可以自定义名称) import multiply from './math.mjs'; // 同时导入具名和默认导出 import multiply, { add, subtract } from './math.mjs'; console.log(add(2, 3)); // 5 console.log(subtract(5, 2)); // 3 console.log(PI); // 3.14159 console.log(multiply(2, 3)); // 6 // 导入所有具名导出,作为对象的属性 import * as math from './math.mjs'; console.log(math.add(2, 3)); // 5 console.log(math.default(2, 3)); // 6(默认导出作为 default 属性)

ESM 特点

特点说明
异步加载默认是异步加载,不会阻塞主线程,更适合浏览器环境
静态分析importexport语句在代码执行前就可以确定模块的依赖关系,支持 Tree Shaking 等优化
严格模式ESM 模块默认在严格模式下运行

四、CommonJS 和 ESM 的对比

项目CommonJSESM
语法require/module.exportsimport/export
加载机制运行时同步加载编译时静态加载
默认支持Node.js 默认支持.mjs"type": "module"
适合场景后端脚本、老项目前后端现代项目、Tree-shaking
是否可混用不能直接混用(需额外配置)不能直接混用(需额外配置)

五、混合使用

Node.js 在较新版本中支持两种模块系统共存。可以在同一个项目中同时使用 CommonJS 和 ESM,但需要注意以下几点:

  • ESM 中不能直接使用require()module.exports

  • CommonJS 中不能直接使用importexport

ESM 中导入 CommonJS 模块

ESM 会将 CommonJS 模块视为默认导出:

// commonjs_module.js module.exports = { data: 'hello' };
// esm_module.mjs import commonModule from './commonjs_module.js'; console.log(commonModule.data); // 输出: hello

CommonJS 中导入 ESM 模块

需要使用动态import()函数:

// esm_module.mjs export const name = 'Bob'; export const age = 25;
// commonjs_module.js async function loadESM() { const { name, age } = await import('./esm_module.mjs'); console.log(name); // 输出: Bob console.log(age); // 输出: 25 } loadESM();

六、路径解析规则

相对路径导入

使用./../开头:

// 导入同目录下的模块 const mod = require('./myModule'); // 导入父目录下的模块 const mod = require('../lib/myModule');

绝对路径导入

使用/开头(指向文件系统根目录):

const mod = require('/path/to/module');

核心模块导入

直接使用模块名称:

const fs = require('fs'); const http = require('http');

第三方模块导入

使用模块名称(从node_modules中查找):

const express = require('express'); const lodash = require('lodash');

七、动态导入

CommonJS 中的动态导入

CommonJS 的require()本身就是动态的,可以在任何位置调用:

// 条件导入 if (condition) { const moduleA = require('./moduleA'); moduleA.doSomething(); } else { const moduleB = require('./moduleB'); moduleB.doSomething(); }

ESM 中的动态导入

ESM 使用import()函数进行动态导入,返回一个 Promise:

// 动态导入 async function loadModule(condition) { if (condition) { const moduleA = await import('./moduleA.mjs'); moduleA.doSomething(); } else { const moduleB = await import('./moduleB.mjs'); moduleB.doSomething(); } }

八、常见问题

1. Cannot find module 错误

当 Node.js 找不到模块时,会报Cannot find module错误。检查:

  • 路径是否正确

  • 模块是否已安装(第三方模块)

  • 文件是否存在

2. 循环依赖问题

当两个模块相互引用时,可能导致其中一个模块获取到不完整的导出对象。建议:

  • 避免循环依赖

  • 如果无法避免,使用module.exports提前导出

3. ESM 和 CommonJS 混用问题

  • 在 ESM 中导入 CommonJS 模块时,CommonJS 的module.exports会被视为默认导出

  • 在 CommonJS 中导入 ESM 模块时,必须使用动态import()

  • 文件扩展名很重要:ESM 使用.mjs,CommonJS 使用.js

九、本章小结

知识点说明
CommonJSNode.js 默认模块系统,使用require()/module.exports,同步加载
ES ModuleJavaScript 官方标准,使用import/export,异步加载
启用 ESM使用.mjs扩展名或在package.json中设置"type": "module"
具名导出export const name = ...,导入时需用{ name }
默认导出export default ...,导入时可自定义名称
混用规则ESM 中可导入 CommonJS;CommonJS 中需用import()导入 ESM
路径解析核心模块直接名称、本地模块用./、第三方模块从node_modules查找

最佳实践:对于新的项目,强烈推荐使用 ES Modules (ESM)。它不仅是 JavaScript 的官方标准,而且与现代前端工具链(如 Vite、Next.js)兼容性更好,能够充分利用 Tree Shaking 等优化技术,减少打包后的代码体积。如果你正在维护一个老旧的 CommonJS 项目,并且不需要 ESM 的特性,可以继续使用 CommonJS。如果需要引入新的依赖或利用 ESM 的新特性,可以考虑逐步迁移,或者使用混合模式来过渡。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/14 14:17:16

开发者 2026 检测书签栏:12 个链接应对 90% 网络故障

开发者 2026 检测书签栏:12 个链接应对 90% 网络故障工具地址:https://www.speedce.com 社区论坛:https://bbs.speedce.com 联系:speedceadsgmail.com写在前面 本文围绕「开发者 2026 检测书签栏」展开,提供可落地的技…

作者头像 李华
网站建设 2026/8/14 14:15:50

17CE vs SpeedCE:老牌表格派与新锐地图派实战对比

17CE vs SpeedCE:老牌表格派与新锐地图派实战对比工具地址:https://www.speedce.com 社区论坛:https://bbs.speedce.com 联系:speedceadsgmail.com写在前面 17CE 表格精确,SpeedCE 地图直观——看场景选。 本文是一份围…

作者头像 李华
网站建设 2026/8/14 14:15:27

3步搞定数据格式转换:把散落的抽卡记录统一成UIGF标准JSON

3步搞定数据格式转换:把散落的抽卡记录统一成UIGF标准JSON 【免费下载链接】HoYo.Gacha ✨ 一个非官方的工具,用于管理和分析你的 miHoYo 抽卡记录。(原神 | 崩坏:星穹铁道 | 绝区零)An unofficial tool for managing …

作者头像 李华
网站建设 2026/8/14 14:15:22

零基础用Redash搭建实时数据看板:从安装到告警的完整指南

零基础用Redash搭建实时数据看板:从安装到告警的完整指南 【免费下载链接】redash Make Your Company Data Driven. Connect to any data source, easily visualize, dashboard and share your data. 项目地址: https://gitcode.com/GitHub_Trending/re/redash …

作者头像 李华