引入纯 ESM 模块化的第三方包

2023-11-18

CSDN中文章不一定能及时更新,欢迎点击前往我的博客查看最新版本:许盛的博客

背景

今天要做个 CLI 工具,一路调研学习加实践都比较顺利,但是在引入 globby 这个库时,就开始报错了。

40pLrj.png

/Users/xusheng/workspace/test/mit-cli/dist/lib/utils/zip.js:4
var globby_1 = require("globby");
               ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/xusheng/workspace/test/mit-cli/node_modules/globby/index.js from /Users/xusheng/workspace/test/mit-cli/dist/lib/utils/zip.js not supported.
Instead change the require of index.js in /Users/xusheng/workspace/test/mit-cli/dist/lib/utils/zip.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/Users/xusheng/workspace/test/mit-cli/dist/lib/utils/zip.js:4:16)
    at Object.<anonymous> (/Users/xusheng/workspace/test/mit-cli/dist/lib/publish.js:5:13)
    at Object.<anonymous> (/Users/xusheng/workspace/test/mit-cli/dist/lib/index.js:5:17) {
  code: 'ERR_REQUIRE_ESM'

错误信息简化一下就是 require() of ES Module xxxx from xxxxx not supported

字面意思来理解,就是不支持 require 一个 ES Module 的包。

这个时候就很迷了,我的 tsconfig 中设置的 module: "commonjs" ,检查了一下 tsc 编译后的文件,也都转换为了 commonjs 模块化方案。

虽然说目前 nodejs 已经原生支持了 esm ,浏览器也提供 type="module" 来支持 esm,但是考虑到兼容性问题,一般我们在编译项目时,还是会输出 commonjs 模块标准的代码,所以一开始压根就没往第三方库的问题上去想。

问题定位

经过一番检索和思考,发现 globby 这个库居然直接发布的 esm 模块标准的代码,也就是说,我的代码虽然 tsc 转换为了 commonjs 标准,但是引入的 globby 还是 esm 标准的代码,这就导致了错误。

这个时候引入一个概念 Pure ESM package,也就是纯 ESM 模块化的包,如果要使用这种第三方库,可以阅读文档:https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

如果一个库是 Pure ESM package 的话,它就没办法再被 commonjs 标准的代码使用 require 引用了,如果要解决这个问题,文档中提出了三种方案:

  1. Use ESM yourself. **(preferred)**Use import foo from 'foo' instead of const foo = require('foo') to import the package. You also need to put "type": "module" in your package.json and more. Follow the below guide.
  2. If the package is used in an async context, you could use [await import(…)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports) from CommonJS instead of require(…).
  3. Stay on the existing version of the package until you can move to ESM.

关于 nodejs 中如何处理 ES6 模块的,可以参考:https://www.ruanyifeng.com/blog/2020/08/how-nodejs-use-es6-module.html

尝试解决

参考上面文档中的三种解决方式。

1. Use ESM yourself

第一种方式比较扯,就是把你自己的库也改成 ESM 标准,这就很坑了,这不是扩大了兼容性的问题了嘛。

2. use await import(…)

第二种方式,就是将静态的 import 语句,改为动态的 import() 方法,例如:

// before
import { xxx } from 'globby';

// after
const { xxx } = await import('globby');

理论上讲好像可以,但是我实际尝试的时候,发现如果 tsc 编译后为 commonjs 标准的话, import() 方法会被转化为一个 __importStar(require('globby')) 方法,本质上还是 require() ?所以还是会报错。

需要进一步调研看看。

3. Stay on the existing version of the package until you can move to ESM

这个方法也很扯淡,就是在你可以将你的项目改为 ESM 标准之前,使用旧版本的 commonjs 标准的第三方库。

解决方法

上面的三种方式,都没有解决问题,只能采取一种治标不治本的方式了。

既然第三方库是 ESM 标准,那么我们在 tsc 编译时,把它也编译一下好了。

globby 为例,在 tsconfig 文件中加入以下代码:

{
    "compilerOptions": {
        ...
        // 因为 globby 是用 js 写的,所以在 tsconfig 中要将 allowJs 设置为 true
        "allowJs": true
    },
	"include": [
		"node_modules/globby/**/*"
	]
}

此时再运行 tsc 编译,会发现在输出的 dist 目录中,新增了一个 node_modules 目录,其中包含了编译后的 globby 包代码。

但是这里需要注意下,再次运行项目,发现还是报同样的错,只是报错的库由 globby 变成了 array-union,这是因为 globbypure ESM package,经过 tsc 编译后变成了 commonjs 标准,但是 globby 引用了 array-union,而 array-union 也是 pure ESM package

以此类推,需要把所有的 pure ESM package 都编译一下:

{
	"include": [
        "node_modules/globby/**/*",
        "node_modules/array-union/**/*",
        "node_modules/slash/**/*"	
	]
}

完美,问题解决。

这里要吐槽一下,array-union 这个库,其实就一行代码:
constarrayUnion = (...arguments_) => [...newSet(arguments_.flat())];
就这还引入一个额外的库,坑!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

引入纯 ESM 模块化的第三方包 的相关文章

  • chai-http/superagent : 设置多部分表单字段的 Content-Type

    在集成测试中上传文件如下 chai request server instance post profile photo 0 set Access Token accessToken set API Key testConfig apiKe
  • 使用通过 (document.getElementById('ID')) 添加到数组的元素

    为什么这段代码不起作用 var all obj element new Array all obj element 0 document getElementById Img3 alert all obj element 0 style w
  • WebPack 源映射令人困惑(重复文件)

    我决定在我今天正在启动的一个新项目上尝试 WebPack 并且我从源映射中得到了非常奇怪的行为 我在文档中找不到任何相关信息 在浏览 StackOverflow 时也找不到其他人遇到此问题 我目前正在查看由以下公司制作的 HelloWorl
  • JavaScript 原型继承和 html canvas

    我是一名 Ruby 开发人员 最终决定认真学习 JavaScript 所以我买了一些书 开始深入研究 但当我试图理解原型继承时 我很快就陷入了困境 这本书的例子之一如下 给定一个 Shape 其原型有一个绘制方法 以及两个子形状 一个 Tr
  • Puppeteer 的行为与开发者控制台不同

    我正在尝试使用 Puppeteer 提取此页面的标题 https www nordstrom com s zella high waist studio pocket 7 8 leggings 5460106 https www nords
  • webrtc - 获取网络摄像头的宽高比

    我正在尝试学习如何开发 webRTC 应用程序 我想知道是否可以获得相机的宽高比 我不知道它是否有帮助 但我正在使用 webrtc io 但是 if更好 我可以停止使用它 From MDN https developer mozilla o
  • 传单圆圈绘制/编辑问题

    我第一次制作传单 并面临绘制圆圈和编辑 更改圆圈位置 的问题 我面临的问题是 编辑 移动 圆从一个位置到另一位置会改变其半径 Note 请尝试在给定的小提琴中在地图顶部创建圆圈 然后通过单击编辑按钮将其移动到底部 如果我在地图的顶部创建圆圈
  • 如何在没有数据库的情况下创建AJAX分页?

    是否可以在没有 MySQL 帮助的情况下获取 AJAX 分页页面 难道我不能只添加一个包含我需要显示的文本和标记的 PHP 文件 然后通过单击页码将该内容提供给用户吗 那么可以用纯 jQuery 和 PHP 来实现吗 您会使用什么代码方法来
  • Bootstrap shown.bs.tab 事件不起作用

    我正在使用灵活的模板 http the8guild com themes html flexy v1 7 stylesPage html 使用引导程序 并且我无法让选项卡上的 shown bs tab 事件正常工作 我已经成功让它发挥作用J
  • 如何将多个文件上传到Firebase?

    有没有办法将多个文件上传到 Firebase 存储 它可以在一次尝试内上传单个文件 如下所示 fileButton addEventListener change function e Get file var file e target
  • Node.js 循环发送 http 请求

    我实际上遇到了使用 node js 执行的 javascript 代码的问题 我需要循环发送http请求到远程服务器 我在代码中设置了www google ca 这是我的代码 var http require http var option
  • JavaScript - 类根据条件扩展

    事情是这样的 我有一个名为 A 的主课 我希望这个班级能够扩展 B 级 class A extends B 但事实上 我希望 B 类在特定条件下扩展 C D 或 E class B extends B1 or class B extends
  • 如何比较两个对象数组并更改两个数组中找到的对象的值?

    假设我有两个对象数组 let array1 id 1 name snow id 4 name jo id 8 name bran id 12 name gondo id 13 name peter
  • 输入和文本区域可以拖动吗?

    MDN 规范以及我能通过 Google 找到的每个网站都说所有 HTML 元素都可以拖动 然而 在实践中 我发现我无法拖动文本输入或文本区域 即使它们已被禁用 例如 使用以下代码 img src http www placehold it
  • 在流星收集加载时显示加载程序

    我有一个模板 task list 看起来像这样 each tasks gt task each Template task list tasks返回一个集合 在用户界面中 加载似乎需要一些时间 当集合正在加载时 我想显示一个加载指示器 关于
  • Array.indexOf 如何比 Array.some 更高效

    这个问题的灵感来自于这个问题的竞争答案 具有多个参数的indexOf https stackoverflow com questions 39000151 indexof with multiple arguments 用户想知道一种有效的
  • 将命令行参数传递给 emscripten 生成的应用程序

    当使用 Emscripten 编译 C 程序时 会生成一个 HTML 页面来显示程序的结果 我想知道如何将命令行参数传递给应用程序 例如 对于原始的 C 程序 它是 bfs 32 1 我能够通过向生成的 html 文件添加一行来传递命令行参
  • 关于 Node.js Promise then 和 return?

    我对承诺感到困惑 I use 那么就答应没有返回像这样 new Promise resolve reject gt resolve 1 then v1 gt console log v1 new Promise resolve reject
  • 如何使用正则表达式解析 OCC 选项符号?

    OCC 选项符号由 4 部分组成 标的股票或 ETF 的根代码 用空格填充至 6 个字符 到期日期 6 位数字 格式为 yymmdd 期权类型 P 或 C 用于看跌或看涨期权 执行价格 为价格 x 1000 前面填充 0 至 8 位数字 举
  • 为什么 JavaScript 默认导出不可用?

    为什么默认导出不像命名导出那样实时 lib js export let counter 0 export function incCounter counter export default counter main1 js import

随机推荐

  • 查看linux服务器内存信息

    查看服务器内存信息 dmidecode grep P A5 Memory s Device grep Size root localhost home dmidecode grep P A5 Memory s Device grep Siz
  • 【leetcode刷题】--- 21.合并两个有序链表(C++递归)

    21 合并两个有序链表 原题链接 https leetcode cn com problems merge two sorted lists 题目 将两个升序链表合并为一个新的 升序 链表并返回 新链表是通过拼接给定的两个链表的所有节点组成
  • 关于ApplicationContext的getBean()方法发现

    假定 Son类实现father接口 在Son类定义声明式事务后 通过ApplicationContext接口的getBean Class arg0 方法获取注入好的bean会报异常 方法参数Son class Son已声明bean org
  • 18. 线性代数 - 线性变换

    文章目录 线性空间 线性变换 线性变换的几何意义 特征值与特征向量 NumPy的矩阵操作 Hi 你好 我是茶桁 经历了几节线性代数课程之后 终于咱们到了最后一节课了 本节课的内容说多不多 说少也不少 我们先是要理解一下线性空间和线性变换 并
  • uml之Robustness Diagram

    Robustness Diagram 从需求分析到架构设计 转载自 http www dotblogs com tw jed archive 2010 11 21 robustness diagram aspx 什么是Robustness
  • Java IO流

    目录 一 认识Java的流 二 使用字节流读写文本文件 三 使用字符流读写文本文件 四 读写二进制文件 五 序列化和反序列化 六 总结 一 认识Java的流 1 读文件是指把文件中的数据读取到内存中 2 写文件是把内存中的数据写到文件中 3
  • 2023高教社杯 国赛数学建模E题思路 - 黄河水沙监测数据分析

    1 赛题 E 题 黄河水沙监测数据分析 黄河是中华民族的母亲河 研究黄河水沙通量的变化规律对沿黄流域的环境治理 气候变 化和人民生活的影响 以及对优化黄河流域水资源分配 协调人地关系 调水调沙 防洪减灾 等方面都具有重要的理论指导意义 附件
  • spring boot 之 kotlin语言开发,用一次就想放弃Java,爽歪歪~~~

    废话少说 上视频 spring boot 之 kotlin用一次就想放弃java 爽歪歪 1 启动入口 SpringBootApplication EnableDiscoveryClient class TawuziAuthServerDb
  • LVGL V8学习之键盘按键样式重绘(二)

    这一篇继续研究一下基于btnmatrix的键盘按键重绘 是对上一篇LVGL V8学习之键盘按键样式重绘 一 的代码的优化 还是通过codeblock来模拟代码的运行 代码如下 按键矩阵的事件回调函数 static void btnmatri
  • vue后台管理系统—— 模糊查询和列表分页展示

    1 效果显示 通过输入作品名称或者开始时间或者结束时间来显示数据列表 这里的三项选择可以输入其一 也可以都输入 2 分页代码 用的是element组件 包括表格 上面的搜索 div class personalident top div
  • pycharm scrapy 爬取“文章”(文章阅读网)

    import scrapy import re from urllib import parse from scrapy http import Request from Article spider Article spider item
  • nvm使用大全nvm如何动态切换node版本

    注意 nvm use node版本时 要使用管理员权限打开cmd输入命令 否则报错 常用命令 nvm ls 列出所有已安装的 node 版本 nvm list 列出所有已安装的 node 版本 nvm list available 显示所有
  • java基础:日志框架

    文章目录 一 日志技术的概述 二 日志技术体系 三 Logback日志框架 四 Logback快速入门 五 Logback 配置详解 5 1 输出位置 格式设置 5 2 对日志不同内容是否输出的控制 一 日志技术的概述 程序中的日志可以用来
  • Linux 数据库备份与恢复

    1 备份数据主要使用dump命令 格式为 mysqldump u db user p db passwd db name gt backup dir db name time sql p 和 db passwd之间没有空格 不然 db pa
  • 加解密和签名验签简述

    文章目录 一 数字加密算法 1 对称加密 2 非对称加密 3 对称加密和非对称加密的区别 二 使用keytool生成证书 1 创建证书 2 查看密钥库 2 1 keytool list 命令 2 2 keytool list v 命令 3
  • Transformer:Attention is All You Need

    Transformer论文逐段精读 论文精读 https www bilibili com video BV1pu411o7BE share source copy web vd source 30e93e9c70e5a43ae75d429
  • 分析 ExitCode 定位 Pod 异常退出原因

    使用kubectl describe pod
  • vue 表单校验不通过时拦截提交表单

    上代码
  • JSP 弹出框 子页面给父页面回传参数

    做一个jsp的页面 然后又弹出一个对话框 并且把输入框的值返回到文本中 具体代码如下 1 父页面 写道
  • 引入纯 ESM 模块化的第三方包

    CSDN中文章不一定能及时更新 欢迎点击前往我的博客查看最新版本 许盛的博客 背景 今天要做个 CLI 工具 一路调研学习加实践都比较顺利 但是在引入 globby 这个库时 就开始报错了 Users xusheng workspace t