# 为了解决 CommonJS 和 UMD 兼容性问题
CommonJS 和 UMD 兼容性: 开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此 Vite 必须先将作为 CommonJS 或 UMD 发布的依赖项转换为 ESM。
# 什么是 ESM
ES-Module 简称为 ESM, ESM 是浏览器原生支持模块功能, 浏览器能够最优化的方式加载模块,使它比使用库更有效率, 使用库通常需要做额外的客户端处理。
# 利用浏览器ESM加载方式
ESM 加载的方式与通常的 <script> 加载的机制一样, 但唯一的区别在于需要 <script> 起始标签加一个 type="module" 的属性, 这样就可以通过 import 和 export 这两个关健字进行模块化导入导出的管理。
# 错误加载示例
<script>
import HelloWorld from './index.js'
</script>
错误提示
Uncaught SyntaxError: Cannot use import statement outside a module
import 和 export 方式进行模块化方式导入与导出需要在 <script> 标签加上 type="module"
# 什么是CommonJS
CommonJS 简称为 CJS。
CommonJS 也是一种模块的形式, 其特性为: 核心思想是通过 require 方法来同步加载依赖的其他模块, 通过 module.exports 导出需要暴露的代码模块。
CommonJS 大多数用于 Node.js 环境下, 大多数 NPM 第三方模块采用了 CommonJS 规范, 但是这样的导入导出的方式无法运行在浏览器环境下。
# 浏览器环境下使用 import 语法导入 CommonJS 格式的模块
<script type="module">
const HelloWrold = require('./index.js')
</script>
错误提示
Uncaught ReferenceError: require is not defined
没有定义 require, 浏览器并没有全局实现 require 方法, 不支持此方法.
# 什么是UMD
由于 CommonJS 和 AMD 风格都同样流行,似乎还没有达成共识。这带来了对支持两种风格的通用模式的推动,这让我们想到了通用模块定义。
诚然,该模式很丑陋,但与 AMD 和 CommonJS 兼容,并且支持旧式的全局变量定义。
# 浏览器环境下使用 import 语法导入 UMD 格式模块
// index.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery', 'underscore'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之类的
module.exports = factory(require('jquery'), require('underscore'));
} else {
// 浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery, root._);
}
}(this, function ($, _) {
// 方法
function a(){}; // 私有方法,因为它没被返回 (见下面)
function b(){}; // 公共方法,因为被返回了
function c(){}; // 公共方法,因为被返回了
// 暴露公共方法
return {
b: b,
c: c
}
}));
<script type="module">
const HelloWrold = require('./index.js')
</script>
错误提示
Uncaught SyntaxError: The requested module './index.js?v=43ffb0a3' does not provide an export named 'default'
提示报错:
index.js 文件是一个umd 格式模块, 通过import的语法进行在浏览器导入, 则会提示没有提供默认的导出名称。
# 总结
以上三种方式可以得出只有通过 <script type="module"></script> 方式引入, 并且要符合 ESM 的导入导出规范, 浏览器才会符合预期效果进行模块加载, 其余的 CommonJS 规范还是 UMD 规范, 浏览器都不能进行识别,对于UMD 而言可以通过 <script src> 引入的方式可以达到全局变量预期。
所以 Vite 进行对模块的预构建也是同样的道理, 市面上的 NPM 三方模块包大多数都是 CommonJS 和 UMD 的规范, 为了让所有 NPM 模块包在浏览器下使用 ESM 的语法进行导入, 通过预构建的方式把 CommonJS 和 UMD 的模块包转化为 ESM 的导出的模式, 这样浏览器就可以使用 ESM 的模块加载机制。