10

image.pngimage.png

偶然一次发现,他们两个的引入模块的方式不一样,在好奇心的驱使下,便开始一探究竟。

1、vue.config方式

打开项目的package.json,找到 scripts位置。
image.png

找到 vue-cli-service 命令,通常命令都位于当前项目的node_modules下的 .bin文件夹中(全局命令不在此处)

image.png
image.png

在node_modules下找到 @vue/cli-service/bin/vue-cli-service.js
image.png

最重要是红色框内语句。继续往下找。
image.png

service.js文件比较长,重要的是下面这句。
image.png

打开 loadFileConfig
image.png

这个文件很短,只有38行,却非常重要。

大意是首先去找是否有自定义配置文件路径,如果有,就加载自定义配置文件;
如果没有,就用默认的 vue.config.xx。

找到配置文件后,通过 is-file-esm 模块来判断配置文件是用es模块方式,还是 commonjs模块方式加载。

而 is-file-esm判断没有别的。就是通过nodejs官方定义的文件 拓展名 和 package.json中的 type 去判断。这里感兴趣,可以阅读nodejs官方对于 commonjsesm 的支持和定义。

is-file-esm模块会先通过文件扩展名判断,

.mjs 为esm , 
.js, .cjs为commonjs模块,

如果没有扩展名,则通过判断package.json的type判断
"type":"module",   为esm,
"type":"commonjs",   为esm,

如果扩展名和type同时出现,则扩展名优先级高。

所以,如果type没指定,vue.config.js以 js 结尾,那么加载的就是 commmonjs,vue.config.js是以 commonjs 方式启动,模块引入只能用 require,而不是import,如果改成import,就会报错.
image.png

我们可以将扩展名换成 .mjs试试 (同样可以在package.json中指定type,我们只是挑一种,你有兴趣,可以去试试)
image.png
image.png

启动后,发现import正常识别,但是 require没有被定义。说明 vue.config.mjs是以 es模块的方式启动的。

2、vite.config方式

打开项目的package.json,找到 scripts位置。
image.png

同样,找到 node_module下的 .bin 目录
image.png
image.png

找到 vite模块下的 bin.vite.js
image.png
image.png

再找到dist/node/cli
image.png

在cli.js这个文件中,找到 /chunks/dep-c9998dc6.js(名称可能版本不同会变,但肯定是位于 createServer 位置处)
image.png
image.png

在 dep-c9998dc6.js文件中,找到 loadConfigFromFile方法。
image.png
image.png

可以发现,这里的 isESM 变量,并不是通过模块去判断,而是直接在代码中通过 package.json的type或者 vite.config.xx 的扩展名判断的。只不过多了个额外的ts, 如果扩展名是ts,则也是es模块。

如果配置文件是 vite.config.js。那么isESM为false, userConfig 为undefined, 之后执行 bundleConfigFile 方法将 es模块转译为 commonjs模块(看注释)

// Bundle config file and transpile it to cjs using esbuild.
const bundled = await bundleConfigFile(resolvedPath);

这就是为什么,vite.config.js 即使不是 es 模块,也可以在里面使用import的原因。因为被转译了。

当然修改 vite.config.js 为 vite.config.mjs也是可以的。

最终结果和 vue.config.js大同小异,都是先判断模块类型后,再通过不同的加载器,将其加载进来。


寒水寺一禅
2.3k 声望119 粉丝

人生短短急个球!