无意间发现他们两个导入模块的方式不一样。在好奇心的驱使下,我开始一探究竟。1.以vue.config方式打开项目的package.json,找到脚本所在位置。找到vue-cli-service命令,通常命令位于当前项目的node_modules下的.bin文件夹下(这里没有全局命令)找到@vue/cli-service/bin/vue-cli-service.js下node_modules最重要的是红框中的语句。继续往下看。service.js文件比较长,重要的是下面这句话。打开loadFileConfig这个文件很短,只有38行,但是很重要。大致思路是先查找是否有自定义配置文件路径,如果有则加载自定义配置文件;如果没有,使用默认的vue.config.xx。找到配置文件后,通过is-file-esm模块判断配置文件是es模块加载的还是commonjs模块加载的。is-file-esm不判断其他任何东西。通过nodejs官方定义的文件扩展名和package.json中的type来判断。这里如果有兴趣可以阅读nodejs官方对commonjs和esm的支持和定义。is-file-esm模块会先根据文件扩展名进行判断。.mjs是esm,.js和.cjs是commonjs模块。如果没有扩展名,则通过判断package.json的类型"type":"module",是esm,"type":"commonjs",如果扩展名和type同时出现,则为esm时间,扩展具有更高的优先级。因此,如果不指定类型,vue.config.js以js结尾,则加载commonjs,以commonjs方式启动vue.config.js。模块只能通过require引入,不能import。如果改成import,就会报错。我们可以尝试把扩展名改成.mjs(也可以在package.json中指定类型,我们随便挑一个,有兴趣的可以试试)启动后发现import识别正常,但未定义要求。请注意,vue.config.mjs是作为es模块启动的。2.以vite.config方式打开项目的package.json,找到脚本所在位置。同样,找到node_module下的.bin目录,找到vite模块下的bin.vite.js,然后找到dist/node/cli。在cli.js文件中,找到/chunks/dep-c9998dc6.js(不同版本名称可能不同,但一定要在createServer所在的位置)在dep-c9998dc6.js文件中,找到loadConfigFromFile方法.可以发现这里的isESM变量不是通过模块来判断的,而是直接通过代码中package.json的类型或者vite.config.xx的扩展名来判断的。只是多了一个ts,如果扩展名是ts,也是一个es模块。如果配置文件是vite.config.js。然后isESM为false,userConfig为undefined,然后执行bundleConfigFile方法将es模块翻译成commonjs模块(见注释)//Bundleconfigfileandtranspileittocjsusingesbuild.constbundled=awaitbundleConfigFile(resolvedPath);这就是为什么vite.config.js即使不是es模块也可以使用import的原因。因为它被翻译了。当然也可以将vite.config.js修改为vite.config.mjs。最后的结果和vue.config.js类似,都是先判断模块类型,然后通过不同的loader加载。
