网站上内容列表怎么做的无锡建设执业资格注册中心网站
CommonJS 和 ESModule 混合开发
- 接上文,仍旧在 abc-cli 项目中
 - 参考:https://blog.csdn.net/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 规范
 
 - 1 )在 package.json 中指定 
 - 注意,
module.exports和exports.xx不能混用,两者混用,后者不生效 - CommonJS规范默认通过自执行函数实现,比如require源码,它可以做一些变量注入
 - 比如 
__dirname,__filename都是通过注入的方式来显示的 - 可以把它们直接打印出来
 
2 )ESModule
- ESModule 也有两种使用方式 
- 1 )在package.json中定义 
"type": "module",包内所有 .js 文件会被认为是 ESModule - 2 ).mjs 后缀的文件,强制被认定为 ESModule
 
 - 1 )在package.json中定义 
 - 在ESModule中导出 
export default {},导入import - 在这里,
__dirname,__filename这种API,统统不支持,但是网上也有兼容方案,这里先不研究- 除了网上的一些解决方案,这里暂时提供一个第三方库来解决 
dirname-filename-esm 
 - 除了网上的一些解决方案,这里暂时提供一个第三方库来解决 
 
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 它的实现是一个同步加载模块的方案 
- 它在模块外围包一层自执行函数,是同步方案实现的
 - 参考:https://blog.csdn.net/Tyro_java/article/details/53574887
 
 - 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的时候需要添加后缀,不能省略
 - 注意,还有导出用 
export default时,引入时别忘记了这个default 
 
