前端架构: 脚手架通用框架封装之CommonJS和ESM混合开发兼容解决(教程五)

死磕Node模块兼容性,ESM和CJS我全都要! 在Node版本13.2.0(2019年)之前,我们一般使用CJS(CommonJS)模式在代码中引入包,它的加载是同步的,在整个模块加载完成后,才会执行后续代码。而ESM(ECMAScript Modules)最早在2015年就被使用在浏览器中,在script标签中增加type="module"这个属性,然后引入模块进行使用。在Node 13.2版本后,Node也支持使用ESM进行导入模块的操作,那么如何对其二者进行一个兼容?请接着往下看。 阅读详情

CommonJS 和 ESModule 混合开发

  • 接上文,仍旧在 abc-cli 项目中
  • 参考:https://blog.youkuaiyun.com/Tyro_java/article/details/136433159
  • 现在要在脚手架项目中安装 chalk 依赖,因为在 abc-cli 项目几乎都是 CommonJS的实现
  • 而 chalk 这个依赖源码是基于 ESModule 的,所以现在要解决的是两者的兼容
  • 先安装 chalk 到 cli 包中,在 abc-cli 目录下,$ npm i chalk -w packages/cli
  • 但是,在使用 chalk 的时候,就会报错,不能使用 require,现在有几种解决方案
    • 第一种,降级 chalk 到低版本, 大概在4.0左右,但是这就无法使用 chalk 的新特性了
    • 第二种,修改自己的代码,将之前的 require 全部修改成 import, 并且package.json中添加 "type":"module"
      • 这种会造成更大的问题:一是,之前的语法全部要修改,包括 module.exports
      • 二是,如果要使用一些只有 CommonJS 的依赖就会有问题
    • 第三种,在CommonJS中允许使用 import 来加载依赖,但是 import 返回了一个 Promise
      • 这种,只能异步拿到真实的依赖,就不好处理了
  • 现在遇到了一个问题,就是如何兼容 CommonJS 和 ESModule, 怎样才能最佳实践
  • npm 模块有的使用CommonJS, 有的使用 ESM, 两者混合开发成为 Nodejs 项目必须考虑的问题

1 )CommonJS

  • CommonJS 单独使用有两种方式
    • 1 )在 package.json 中指定 "type": "common" 这个不指定也是默认的
    • 所有js文件的的导入都用 require 语法来引用模块
    • 所有js文件的导出都用 module.exports 语法来导出
    • 2 )不管 package.json 中指定的是 "type": "common" 亦或是 "type": "module"
    • 只要js文件的后缀是 .cjs 都可以使用 require 和 module.exports 语法
    • 这样,默认走的就是 CommonJS 规范
  • 注意,module.exports 和 exports.xx 不能混用,两者混用,后者不生效
  • CommonJS规范默认通过自执行函数实现,比如require源码,它可以做一些变量注入
  • 比如 __dirname, __filename 都是通过注入的方式来显示的
  • 可以把它们直接打印出来

2 )ESModule

  • ESModule 也有两种使用方式
    • 1 )在package.json中定义 "type": "module",包内所有 .js 文件会被认为是 ESModule
    • 2 ).mjs 后缀的文件,强制被认定为 ESModule
  • 在ESModule中导出 export default {},导入 import
  • 在这里,__dirname, __filename 这种API,统统不支持,但是网上也有兼容方案, 这里提供两种
    • 第一种,使用 node 原生API node:url

      import { fileURLToPath } from 'node:url';
      const __filename = fileURLToPath(import.meta.url)
      
    • 第二种,使用第三方库来解决 dirname-filename-esm

      import { filename } from 'dirname-filename-esm';
      const __filename = filename(import.meta);
      

3 )CommonJS 和 ESModule 混用

  • 原则上,不应该混用,一般我们开发包的时候,需要指定一种
  • 单个模块,必须指定CommonJS 或 ESM, 如果混用,必须用webpack或babel来解决
  • 另外,package.json 的 type 可以不写,如果写就必须指定一种,默认是 commonjs
  • 越来越多的模块采用了 ESModule, 也就是指定 type 为 module

3.1 在 CommonJS 中引用 ESM

  • 如果一个模块是ESM, 比如,它叫 “esm” 来举例
    import('esm').then(esm => esm.default())
    
  • 这种做法非常别扭
  • CommonJS 本身是一个同步的规范,require 它的实现是一个同步加载模块的方案
  • ESM 本身用的是 import 用的是异步方式来加载,和CommonJS是完全不同的两种实践方案
  • 如果是 在 CommonJS 中引用 ESM,那么代码就会非常的奇怪
  • 要想实现同步操作,就必须加一个自执行函数,并将这个函数指定为 async 方式
    (async function() {
      const esm = await import('esm');
      esm.default();
    })()
    
    • 这样,很麻烦,也很奇怪
    • 但是能解决问题

3.2 在 ESM 中引用 CommonJS

  • 在 ESM 包中,不管依赖是 ESM还是CommonJS方案开发的,都可以直接 import
  • 假设 “cjs” 是一个 CommonJS 模块的方案
    imort cjs form 'cjs';
    
  • 所以,推荐把源码全部移植到ESM模块中

常见的报错问题和解决

  • 1 )未指定 package.json 中的 type, 但是使用了 import 和 export 语法

    • 这是缺失了 package.json 中 type 默认是 commonjs 的知识点造成的
  • 2 )require 语法无法加载ESM模块

    • 必须使用 import 来加载ESM模块
  • 3 )ESM 去加载其他ESM模块时会有找不到模块的报错

    • 没有构建工具时,import的时候需要添加后缀,不能省略

综上

  • 通过以上对比,我们一开始发布ESM的包比commonjs包用途会更加广泛
  • 所以,这里提供以下版本的源码,如下
  • v_commonjs
    • 这是 commonjs 版本的代码
  • v_esm
    • 这是 es module 版本的代码
  • v_enhanced
    • 这是基于 esm 的增强版本: 错误处理,代码优化
ESM和CommonJS详解 阅读详情

相关推荐

web前端面试-- 模块化的几种规范CMD、COMMONJS、AMD、ESM以及UMD模块化解决方案,export *的写法

JavaScript 目前有四种模块规范:CMD、COMMONJS、AMD 和 ESM。CMD 是 JavaScript 最早的模块规范,它使用 require 函数来导入模块。CMD 模块是 JavaScript 最早的模块规范,但它存在一些缺陷,比如模块的导入顺序不受控制,模块的依赖关系无法被管理,等等。COMMONJS 是 JavaScript 模块的另一种,它使用 require 函数来导入模块。COMMONJS 模块在解决CMD。

Penk的博客 1836

CommonJS和ESM

CommonJs和ESM

qq_48930989的博客 943

玄机-Linux权限维持-后门

玄机-Linux权限维持-后门

m0_46439803的博客 767

高级前端理解的CommonJS模块和ESM模块

前端Q我是winty,专注分享前端知识和各类前端资源,乐于分享各种有趣的事,关注我,一起做个有趣的人~公众号点击上方前端Q,关注公众号回复加群,加入前端Q技术交流群阮一峰在ES6 入门中提到 ES6 模块与 CommonJS 模块有一些重大的差异:CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。再细读...

LuckyWinty的博客 1189

手把手教你用THS4551搭建全差分放大器电路(附ADC驱动实战)

本文详细介绍了如何使用TI的THS4551全差分放大器搭建高性能ADC驱动电路,涵盖芯片选型、电路配置、PCB布局及实战调试等关键环节。THS4551凭借其优异的共模抑制比和宽电源电压范围,成为驱动16位及以上精度ADC的理想选择,特别适合工业应用场景。

weixin_30338481的博客 282

Cube生成定时器2触发双ADC同步采集并用DMA传输

前言 用cube生成一个用定时器触发ADC1,ADC2同步采集的程序,单片机选择的是STM32L476RGT6,用定时器2进行ADC采集触发,更改定时器2的定时周期便可以更改ADC的采样周期,ADC1和ADC2使用同步规则模式,并用DMA进行数据的传输。 STM32的ADC采样完成总共需要的时间是 ADC完成采样时间=采样周期+12个转换周期 举个例子,假如ADC的时钟是15MHz,采样周期是3个周期,3个采样周期加上12个转换周期,一共是15个周期,因为时钟是15MHz,所以完成一次ADC转换总共需要的时

一行代码的博客 4515

CommonJS和ESM:JavaScript模块化规范对比

在现代的JavaScript开发中,模块化是一个至关重要的概念,它有助于将代码拆分为独立的、可维护的部分,使开发过程更加高效和可靠。在JavaScript社区中,有两种主要的模块化规范:CommonJS(通用模块化规范)和ESM(ECMAScript模块)规范。本文将深入探讨这两种规范的异同点、应用场景以及注意事项。

CreatorRay的博客 1315

Xilinx FPGA MultiBoot实战:7Series与UltraScale的SPI Fallback配置详解

本文深入解析了Xilinx FPGA的MultiBoot(多启动)与Fallback(回退)功能,针对7系列与UltraScale/UltraScale+系列,提供了从约束文件编写、看门狗集成到镜像烧录的完整实战配置指南。文章重点对比了两个系列在SPI Fallback配置上的关键差异与注意事项,旨在帮助工程师构建高可靠、永不宕机的FPGA系统。

weixin_29197051的博客 547

前端模块化CommonJs、ESM、AMD总结

历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。通过对 CommonJs、CMD、AMD 进一步处理,它没有自己专有的规范,是集结了 CommonJs、CMD、AMD 的规范于一身。语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。

Tiny2017的博客 1546

io_uring vs epoll ,谁在网络编程领域更胜一筹?

简介:从定量分析的角度,通过量化 io_uring 和 epoll 两种编程框架下的相关操作的耗时,来分析二者的性能差异。 本文作者:王小光,「高性能存储技术SIG」核心成员。 背景 io_uring 在传统存储 io 场景已经证明其价值,但 io_uring 不仅支持传统存储 io,也支持网络 io。io_uring 社区有众多的开发者尝试将 io_uring 用于网络应用。我们之前也在《你认为 io_uring 只适用于存储 IO?大错特错!》中也探索过 io_uring 在网络场景的应用及其

阿里云云栖号 3036

以ATT&CK为例构建网络安全知识图

随着攻击工具、方法的逐渐升级和复杂化,安全数据的大规模融合,攻防对抗愈加激烈。安全团队如何在浩瀚数据中有效发现高级威胁的蛛丝马迹,如何把网络安全专家的经验、知识有效转化为可复制可扩展的数据分析能力,如何将对抗高级威胁的“炼金术”逐步升级为科学淘金指南,如何将安全从业者从繁重的体力劳动中解放出来,愈发成为安全能力亟需突破的难点和重点,也是我们正在探索的方向。正如医疗行业中治疗疑难杂症依赖医疗专家,网络空间高级威胁的防护和处置也依赖安全专家的经验与知识。

2401_88752684的博客 1092

commonjs 与 esm 的区别

js 社区存在多种模块化规范,其中最常使用到的是 node 本身实现的 commonjs 和 es6 标准的 esm。 commonjs 和 esm 存在多种根本上的区别,详细的比较在阮一峰的《es6标准入门》已经写得很详细了,这里我想用自己的思路重新总结一下。同时分析一下 babel 对于 esm 的编译转换,存在的局限。 commonjs 和 esm 的主要区别可以概括成以下几点: 输出拷贝...

weixin_33816300的博客 6417

海思ISP实战:YUV Sharpen参数调试全解析

本文深入解析了在海思ISP平台上进行YUV Sharpen参数调试的实战经验。文章以海思3516EV300芯片为例,详细拆解了EdgeFiltStr、TextureFreq等核心参数的作用与协同策略,并重点阐述了如何通过ISO联动调试,在图像清晰度与噪声抑制之间取得最佳平衡,为图像调试工程师提供了宝贵的避坑指南和实战参考。

grape的博客 214

ESM对比CommonJS

ESM和CommonJS对比解析。

letterTiger的博客 1565

AUTOSAR从入门到精通-诊断事件管理模块(DEM)(四)

在 Autosar 中,诊断事件是指在车辆电子系统中发生的特定事件,可以用于诊断和故障排除。DEM模块通过EventId和相关的EventName来表示每个诊断事件。诊断事件的状态代表了监控器的结果,DEM模块通过RTE或其他BSW模块从SW-C接收监控器的结果。DEM模块使用EventId来管理系统中每个诊断事件的状态,并对各个测试结果执行所需的操作,例如存储冻结帧/拓展帧。所有监控器和BSW模块使用EventId作为符号化的EventName来管理诊断事件。

getusushu的博客 1510

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

前端架构: 脚手架通用框架封装之添加测试框架(教程六)

jest 默认集成了 babel, 我们利用这个特性,创建 babel 的配置文件,新建 abc-cli/packages/cli/babel.config.cjs。之后,在 abc-cli/packages/cli/package.json 中的 scripts 进行修改。现在就可以继续完善了,修改 abc-cli/packages/cli/再次在 abc-cli/packages/cli 目录下,执行 $安装 babel, 在 abc-cli 目录中,$在 abc-cli/packages/cli/

Wang的专栏 1107

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

CommonJS 与 ESM 的区别与比较

CommonJS 是 Node.js 最早期的模块系统。它的设计目标是为 JavaScript 提供同步加载模块的机制,主要应用于服务器端开发。CommonJS 使用require()来导入模块,来导出模块。`);// app.js在这个示例中,greet.js模块通过导出一个函数,而app.js使用require()导入该模块并调用greet()函数。ESM 是JavaScript 官方引入的模块系统。

weixin_63726940的博客 1696

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

深入理解前端中的模块化体系:ESM、CommonJS、AMD 对比与应用场景

技术选型场景推荐模块体系现代前端项目(React/Vue)ESM微前端架构后端 Node 项目纯 ESM(推荐)或 CommonJS(兼容旧项目)npm 组件开发UMD + ESM + CJS 打包统一模块系统 = 提升团队协作效率 + 提高打包性能 + 减少模块混乱问题。

一名热衷于技术的全栈开发者,专注于前端与后端的全面技术探索。在这里,我将分享我在技术领域的学习与成长,助力更多开发者的进步。 1904

面试:CommonJs和ESM的区别

面试:CommonJs和ESM的区别

太阳与星辰的博客 763

CommonJS 和 ES Module (ESM)

ES6(ECMAScript 2015)引入了模块化的原生支持,这一规范允许开发者使用。

qq_52869537的博客 1593

【Js】易混淆的CommonJS和ESM(ES Module),及它们区别

CommonJs和ESM的概念和区别

m0_47814717的博客 1239

从报错到兼容:Serverless框架中ESM与CommonJS模块混用的完美解决方案

你是否在使用Serverless框架开发时遇到过`SyntaxError: Cannot use import statement outside a module`或`require is not defined`的报错?这些令人头疼的兼容性问题往往源于ECMAScript模块(ESM)与CommonJS模块的混用。本文将深入解析Serverless框架中的模块系统冲突,并提供一套完整的解决方案...

gitblog_00342的博客 393

从 CommonJS 到 ESM:cjstoesm 工具的全面解析与推荐

从 CommonJS 到 ESM:cjstoesm 工具的全面解析与推荐 项目介绍 在现代 JavaScript 开发中,模块化是不可或缺的一部分。然而,随着 ECMAScript 模块(ESM)的普及,许多旧项目仍然依赖于 CommonJS(CJS)模块系统。为了帮助开发者顺利迁移,cjstoesm 应运而生。cjstoesm 是一个强大的工具,能够将 CommonJS 模块转换为可摇树优化的 ...

gitblog_01108的博客 1100

从CommonJS到ESM:Node.js服务端应用的模块化革命

ESM不是“换个写法”,而是要求你从动态运行时思维转向静态设计思维。它让代码更可预测、更易优化,与现代前端生态无缝融合。Node.js官方已将ESM作为未来方向(v20+将默认启用),现在正是拥抱它的黄金期。

JakeMa1024的博客 2085
上一篇: 前端架构: 脚手架通用框架封装之启动检查功能开发(教程四)
下一篇: 前端架构: 脚手架通用框架封装之添加测试框架(教程六)
Wang's Blog
博客等级 码龄12年 7433粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值