Node.js模块化 | 青训营

178 阅读3分钟

前言

nodejs模块化规范有两套,分别为CommonJS规范和ESModule规范!

注意:在一个项目中要使用不同的规范可以通过在项目的package.json文件中配置type即可!

{
  "name": "npm-demo",
  "version": "1.0.0",
  "description": "npm test",
  "main": "index.js",
  "type": "commonjs",// 配置这个就可以了(若没有配置type,则默认使用ESModule规范)
}

image.png

CommonJS规范

引入

CommonJS规范有五种模式引入

  1. 引入自身编写的模块
// test1.js
console.log('test1')

// index.js
require('./test1.js') 

// 最后运行node index.js,控制台打印test1
  1. 引入第三方模块
// 例子:
// 先执行npm i md5

// index.js
const md5 = require('md5')
console.log(md5(123))

// 202cb962ac59075b964b07152d234b70
  1. 引入nodejs内置模块(fs,http,net…)
const fs = require('fs')
console.log(fs)
  1. 引入C++扩展

CommonJS规范还支持引入C++扩展模块,需要使用node-gyp编译生成.node文件,然后使用require引入。例如:

const addon = require('./build/Release/addon.node');
console.log(addon.hello());
  1. 引入JSON文件
// test.json
{
  "name": "John",
  "age": 30,
  "city": "New York"
}

// index.js
const data = require('./test.json')
console.log(data.name) // John

导出

// test.js
module.exports = {
  audit: 1,
  pass: 2,
  fail: 0
}

// index.js
const expres = require('./test.js')
console.log(expres) // { audit: 1, pass: 2, fail: 0 }

ESModule规范

ESModule规范使用import和export进行模块的导入和导出,支持静态编译和Tree Shaking等高级特性,但需要使用Babel等工具转换为CommonJS规范才能在Node.js中使用。

// test.js
export const age = 18
export default{
  audit: 1,
  pass: 2,
  fail: 0
}

// index.js
import expres,{age} from './test.js'
console.log(expres) // { audit: 1, pass: 2, fail: 0 }
console.log(age) // 18

// 如果想要全部导入则可以如下操作
import * as allData from './test.js'
console.log(allData)
// [Module: null prototype] {
//  age: 18,
//  default: { audit: 1, pass: 2, fail: 0 }
//}

ESModule规范不支持引入JSON文件(nodejs 18版本以下)!

// data.json
{
  "name": "zs",
  "age": "18"
}

// index.js
import json from './data.json'
console.log(json)

运行结果如下图:

image.png

// nodejs高版本可以引入JSON文件(nodejs 18以上),但会警告
import json from './data.json' assert { type: 'json' }
console.log(json)

两大规范区别

  1. ESModule规范基于编译时异步加载,CommonJS规范基于运行时同步加载(运行方式不一样)

因此,我们可以按照以下写法来写

// 优点:CommonJS规范下可以这样写,即和逻辑代码混在一起写
// 但是这样写的话会有个缺点:由于基于运行时同步加载,当引入这个模块过大,就会阻塞后面的代码
if (true) {
  const md5 = require('md5')
}

// 但是ESModule规范就不能这样写了,import导入声明只能在模块的顶层使用
if (true) {
  import md5 from 'md5'
}

// ----------------------------------------------------
// 如果import非要写在逻辑里面也可实现,使用import函数模式
// index.js
if (true) {
  import('./test.js').then((module) => {
    console.log(module)
  })
}
// 运行 结果: 
// [Module: null prototype] {
//  age: 18,
//  default: { audit: 1, pass: 2, fail: 0 }
//}

// test.js
export const age = 18
export default{
  audit: 1,
  pass: 2,
  fail: 0
}
  1. ESModule规范下引入的模块是只读的(不可修改),而CommonJS规范下引入的模块是可读可写的
  2. ESModule规范支持Tree Shaking优化,而CommonJS规范不支持!
  3. ESModule规范下的顶层this指向undefined,而CommonJS规范下的顶层this指向模块本身.

总结

模块化对于大型项目的开发尤其重要,可以将功能划分为多个独立的模块,每个模块负责处理特定的业务逻辑。这有助于提高代码的可维护性和可测试性,也有利于团队协作和代码重用。🚗🚓🚕🛺🚙

千淘万漉虽辛苦,吹尽狂沙始到金!