死磕Node模块兼容性,ESM和CJS我全都要!

简介: 死磕Node模块兼容性,ESM和CJS我全都要!

前言

在Node版本13.2.0(2019年)之前,我们一般使用CJS(CommonJS)模式在代码中引入包,它的加载是同步的,在整个模块加载完成后,才会执行后续代码。而ESM(ECMAScript Modules)最早在2015年就被使用在浏览器中,在script标签中增加type="module"这个属性,然后引入模块进行使用。

在Node 13.2版本后,Node也支持使用ESM进行导入模块的操作,那么在发布npm包时如何对其二者进行兼容?请接着往下看

想直接看解决方式的同学空降这里

一些概念

上面提到的两种模式,需要简单介绍一下

CJS(CommonJS)

CJS (CommonJS)是一种在 JavaScript 中实现模块系统的规范。CJS模块是单独的JavaScript文件,每个模块可以导出一个或多个值,其他模块可以使用require()函数导入这些值。CJS比较适合在服务端使用,因为它可以访问文件系统并直接加载模块,但是由于无法异步加载和编译的关系,使其不适合运行在浏览器中

以下是使用CJS模式导入,导出模块的示例

params.js

module.exports = {
  a: 1,
  b: 2,
};

index.js

const params = require("./params");
const fn = function (params) {
  const { a, b } = params;
  console.log(a + b);
};
fn(params);

此外,CJS还支持exports的方式导出

exports.params = {
  a: 1,
  b: 2,
};

ESM(ECMAScript Modules)

说完了CJS,我们来看看ESM

ECMAScript(ES)模块是JavaScript的一种模块系统,是从ECMAScript6(ES6)开始引入的。与CJS不同,ES模块是异步加载的,CJS在运行时加载模块,而ESM是静态的,其在编译时就定义了模块

用法示例

export default {
  a: 1,
  b: 2,
};
import params from "./params.js";
const fn = function (params) {
  const { a, b } = params;
  console.log(a + b);
};
fn(params);

除此之外,ESM还支持以下语法:

  • export const a :将一个模块导出
  • import a from :导入模块所有内容
  • import() :动态导入模块
  • export * from :导出模块中所有导出的内容
  • import { a, b } from :模块中的部分内容
  • import { a as c } from :将导入的内容重命名

注意:在node中使用ESM需要把package中的type属性改成module

那么由于上述的操作,导致在node环境下只能使用ESM或者CJS,有没有什么方法可以得二者求其全?

兼容操作

首先我们需要明确:在一个文件夹下新建一个package.json文件,该文件夹下的文件都会遵循这个json的配置

那么有了上述的概念,我们就可以在打包时新建两个文件夹分别用来编译CJS和ESM了

举个例子:

我需要写一个工具包发布到npm上,由于两种模式的局限性,我不得不使用esm或者cjs其中一种进行打包,此时可以进行如下操作:

新建如下文件夹

具体配置如下:其中主目录的package.json是工具包的默认配置,不写type默认取commonjs,esm目录下则会读取package配置,获得module

具体配置可以参考utils-lib-js这个工具包

效果演示

在未配置时,工具包中的type是module,使用require引入会报错

Error [ERR_REQUIRE_ESM]: require() of ES Module xxxxxxxxxx.js from xxxxxxx.js not supported.

而工具包中的type如果使用commonjs或者不写,使用import引入时会报

Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)

此时我们试试在主目录下将type设置为module,在cjs中新建package将type设置成commonjs后就可以解决上述兼容问题

使用ESM的import

使用CJS的require

总结

文章介绍了两种模块系统,并且实现了在同一个项目中同时使用二者进行引入,在保证功能的前提下进行兼容。

以上就是文章所有内容了,希望对你有帮助,感谢你看到最后,喜欢文章的朋友还请点赞支持一下,感谢!

相关文章
|
1月前
|
缓存 JavaScript 安全
nodejs里面的http模块介绍和使用
综上所述,Node.js的http模块是构建Web服务的基础,其灵活性和强大功能,结合Node.js异步非阻塞的特点,为现代Web应用开发提供了坚实的基础。
101 62
|
2月前
|
JavaScript 前端开发
Vue、ElementUI配合Node、multiparty模块实现图片上传并反显_小demo
如何使用Vue和Element UI配合Node.js及multiparty模块实现图片上传并反显的功能,包括前端的Element UI组件配置和后端的Node.js服务端代码实现。
34 1
Vue、ElementUI配合Node、multiparty模块实现图片上传并反显_小demo
|
1月前
|
缓存 JSON JavaScript
Node.js模块系统
10月更文挑战第4天
34 2
|
1月前
|
JavaScript 应用服务中间件 Apache
Node.js Web 模块
10月更文挑战第7天
29 0
|
1月前
|
JavaScript 网络协议
Node.js 工具模块
10月更文挑战第7天
19 0
|
1月前
|
JavaScript 前端开发 应用服务中间件
Node.js Web 模块
Node.js Web 模块
|
3月前
|
存储 缓存 JSON
Node.js有哪些模块系统
【8月更文挑战第12天】Node.js有哪些模块系统
39 3
|
3月前
[译] Node 模块中的 peer dependencies 是什么?
[译] Node 模块中的 peer dependencies 是什么?
|
4月前
|
存储 JavaScript 安全
Node中的AsyncLocalStorage 使用问题之AsyncLocalStorage与node:async_hooks模块的问题如何解决
Node中的AsyncLocalStorage 使用问题之AsyncLocalStorage与node:async_hooks模块的问题如何解决
|
3月前
|
存储 JavaScript 前端开发
nodejs os模块
nodejs os模块
42 0