一、问题
二、解决方案
三、如何处理commonJS
一、问题vite
运行时使用esbuild
,基于esm
大部分三方包为UMD
规范,输出的是CommonJS
的包(比如react
、lodash
)
// react 入口文件
// 只有 CommonJS 格式
if (process.env.NODE_ENV === "production") {
module.exports = require("./cjs/react.production.min.js");
} else {
module.exports = require("./cjs/react.development.js");
}
二、解决方案
vite
提供了预构建阶段,主要用于处理两种情况:
将其他格式(如 UMD
和 CommonJS
)的产物转换为 ESM
,以react
为例,本文主要记录这种情况的处理。
解决esm
包请求瀑布流的问题,以lodash-es
为例
vite
自动开启了预构建,启动成功后可以在 node_modules/.vite/deps/react.js
看到预构建以后的react(esm)包
很简单一句,调用了chunk
中的require_react
方法,让我们进入chunk
文件。
此处可以看到require_react
传入了一个方法给__commonJS
,并返回了一个新的方法__require
。
这里有个令人迷惑的点,就是用到了,
逗号表达式,总会返回后面的内容,这句猜测是因为压缩代码导致的,其效果相当于:
function __require() {
// 压缩后
return mod || (0, test)((mod = { exports: {} }).exports, mod), mod.exports;
// 压缩前,仅推测
if (mod) {
return mod
} else {
test(mod, mod.exports)
return mod.exports
}
};
function test(exports, mod) {
console.log('exports, mod', exports, mod)
}
在接近 1800 行的require_react_development
中,主要是把react
的导出内容cv
了一遍,并赋值给了mod.exports
:
最后看回来到node_modules/.vite/deps/react.js
:
这句相当于 export default mod.exports
,将react
的模块用esm
的方式输出。
commonJS
和esm
的区别在哪里?
让我们先看一段esm
的代码
// Named export/import
export { name }
import { name } from "name"
// Default export/import
export default name
import name from "name"
再看一段CommonJS
let name = {
firstName,
lastName
}
module.exports = name
mudule.export.firstName = 'z'
exports.lastName = 'zz'
不难看出,在CommonJS
中的导出方式都是基于module.exports
的,而在ESM
中,有两种不同的导入/导出方式,分别是export { name }
,export default name
。
因此在把CommonJS
转换为ESM
时,需要同时导出两种形式,这样很麻烦。(如果不同时导出两种形式,会导致引入时,有一种对应情况无法使用,理论上只用其中一种对应的方式也可以使用)
如何兼容两种ESM
的导入/导出形式
此处参考了别的大佬的笔记(vite
预构建的代码也是这么实现的):
var esm$1 = { exports: {} };
(function (module, exports) {
module.exports = () => {};
exports.a = 3;
exports.b = 4;
})(esm$1, esm$1.exports);
var esm = esm$1.exports;
export { esm as default };
以上就是详解vite如何支持cjs方案示例的详细内容,更多关于vite支持cjs方案的资料请关注软件开发网其它相关文章!