Node Modules 模块系统

模块化

有过的解决方案:

  • CMD/AMD/require.js
  • CommonJS
  • ES Module

nodejs 默认支持CommonJS模块化,从版本 12.0.0 开始支持 ES Modules (ESM)。

CommonJS

导入

const variable = require('*');
1

导出

module.exports = {};
1

require

require 支持加载的类型:

  1. .js
  2. .json
  3. .node
  4. 任何类型的文件,都会视为.js去解析

针对不同的文件类型,有不同的处理方式:

  1. 如果是.js文件,里面需要使用module.exportsexports输出一个模块。

  2. 如果是.json文件,会使用JSON.parse解析为 json 对象

  3. 如果是.node文件,会使用process.dlopen打开一个 C++插件

ES Module

  • 导入:import

  • 导出:export

Node 项目如何支持 ES Module

解决方案:

  1. 使用 webpack

  2. 通过 Node 原生支持(版本号大于 12.0.0)

1.使用 webpack

ES Module的语法转换成CommonJS,打包成普通的 js 文件。

为了兼容低版本 node,需要使用bable,如果使用了async/await还需要添加@babel/plugin-transform-runtime

配置webpack.config.js文件:

{
  target: 'node', // 默认是web,需要改为node,去加载node内置库
}
1
2
3

2.通过 Node 原生支持

  1. 方案一:将.js文件后缀名改为.mjs
  2. 方案二:修改package.json文件
  3. 方案三:在文件的顶部添加 "type": "module" 的语句

1. 方案一:修改后缀名为.mjs

1.1 更改 js 文件后缀名为.mjs

1.2 import 的时候,不能省略后缀名

1.3 执行.mjs文件

# node版本`>= v14`,可以直接执行
node ./bin/index.mjs

# or

# node版本低于`v14`,需要配置开启:`--experimental-modules`
node --experimental-modules ./bin/index.mjs
1
2
3
4
5
6
7

2. 方案二:修改package.json文件

2.1 修改package.json

{
  "type": "module"
}
1
2
3

默认将 js 文件全部转换为ES Module模式,但是如果使用CommonJs规范就需要把文件改为*.cjs

2.2 执行:

node ./bin/index.mjs
1

需要注意的几个点:

  1. ES Module 中可以导入 CommonJs 模块

  2. CommonJs 中不能导入 ES Module 模块

  3. CommonJs 始终只会导出一个默认成员

  4. 注意 import 不能解构导出的对象

3. 方案三:在文件的顶部添加 "type": "module" 的语句

在 Node.js 中,使用 ES Modules 需要在文件的顶部添加 "type": "module" 的语句,表示该文件采用 ES Modules 格式。

// index.mjs

import { greet } from './module.js';

greet('world');
1
2
3
4
5
// module.js

export function greet(name) {
  console.log(`Hello, ${name}!`);
}
1
2
3
4
5

在 Node.js 中,使用 ES Modules 还需要注意以下事项:

  1. 在 ESM 中,没有全局的 require() 函数和 module.exports 对象,所以需要使用 import 和 export 语法来加载和导出模块。

  2. 在 ESM 中,不能使用动态导入语法,例如 import('module.js'),只能使用静态导入语法,例如 import { x } from 'module.js'。

  3. 在 ESM 中,模块的路径必须是相对路径或绝对路径,不能使用模块标识符,例如 import fs from 'fs'。

全局包

  1. 使用which node查看全局软链接路径: /Users/cass/.nvm/versions/node/v16.16.0/bin/node

  2. 进入 bin 文件夹,使用ls -la可以查看到所有命令具体执行的文件

目录结构

  • bin目录存放的是全局命令

  • lib -> node_modules目录存放的是全局包源码

模块的加载顺序

Node.js 模块的加载顺序是按照以下顺序来加载的:

  1. 首先,Node.js 会查找该模块是否已经被缓存,如果已经被缓存,则直接从缓存中加载。

  2. 如果没有被缓存,则按照模块的文件名来查找模块,如果文件名包含路径,则按照路径查找;否则,按照 Node.js 模块加载规则查找。

  3. Node.js 模块加载规则是按照以下顺序查找模块:

    3.1 先查找该模块是否是 Node.js 内置模块,如果是,则直接加载。

    3.2 如果不是内置模块,则按照 NODE_PATH 环境变量和当前模块的 node_modules 目录查找该模块。

    3.3 如果还没有找到该模块,则递归查找该模块的依赖模块。

模块的循环依赖

循环依赖是指两个或多个模块之间相互依赖的情况。在 Node.js 中,循环依赖会导致模块加载失败,因此需要谨慎处理循环依赖问题。可以通过延迟加载、重构代码和使用依赖注入等方式来解决循环依赖问题。

Last Updated: 2023/2/20 16:42:16
Contributors: licong96