为什么vue里面可以写module.exports,一般不是es6吗?export或者export default?

作者站长头像
站长
· 阅读数 10

为什么vue里面可以写module.exports,一般不是es6吗?export或者export default?

回复
1个回答
avatar
test
2024-07-13

纠正:这个其实是构建工具赋予的能力

前置相关知识

在原生支持的模块规范下。例如node 的commonjs / esm,浏览器的esm1.node 环境下, 默认设置

// a.js
module.exports='a'
// main.js
import a from "./a.js" 
console.log(a)

// ❌ SyntaxError: Cannot use import statement outside a module
// node说,我在使用commonjs的规范在解析执行你的代码,但是我不认识 import这个字。
// 甚至提醒你 To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

好,我们听它的提醒,我们尝试在package.json 设置 type:module现在import 他认识了,但是又报错了

// ❌ ReferenceError: module is not defined in ES module scope
// node说你没有声明module,是的在esm规范下,并不存在全局的module

现在好像不管怎么操作,我们都没办法混用它们。但是转念一想,它node不是说我还可以使用.mjs后缀吗?试试吧,去掉刚刚设置的type:module,我们单一的使用文件后缀,让node自动去区分模块规范,修改main.js -> main.mjs

// a.js
module.exports='a'
// main.mjs
import a from "./a.js" 
console.log(a)

// 💯 a
// 终于通了
// 这一次,我们做到了import 一个 module.exports='a'
// 得益于node可以针对单一的文件,采用不同的规范类型

回到问题

回到你的问题,在webpack 或 vite的构建体系下,我们又是为什么可以以module.exports的方式导出我们的组件对象呢?

module.exports={
    name:"MyComponent"
}

我们知道,构建简单的说是一个从src源文件 -> dist产物的过程,也就是说,构建重新组织了我们的代码,使得我们的js模块化编码下的代码,在浏览器不支持js模块化的基础上也能正常运行。

webpack支持很多模块类型,最初的commonjs,umd,amd,还有后来的esm,它都支持,得益于他的runtime运行时requireimport 对于webpack来说,只是一个特殊的关键字,这些关键词告知webpack,当前模块的依赖者。然后寻找模块之间的依赖关系,是webpack的工作重点。例如,还是我们上面的源码

// a.js
module.exports='a'
// main.js
import a from "./a.js" 
console.log(a)

这段源码会被重新组织为类似如下,读者需要了解webpack产物是如何运行起来的,才能理解,有相关文章不再赘述

// a.js
function(module,require){
  module.exports='a' // 我们的模块代码被函数包裹,函数提供module参数,作为供你导出的挂钩
}

const a=magicRequire("a") // 可以简单理解为magicRequire函数是webpack提供的拥有可以获得一个模块的导出的能力的函数
console.log(a)

vite 的依赖查找是基于esm的,所以当你引用飞esm的模块,你需要用到rollup-commonjs的插件,vite的构建跟rollup如出一辙,就是把各个分散的模块,重新组合到一个,变量冲突了就重新命名,再区分导出和内部变量,因为esm的静态分析能力,这一切的转换过程都是可控的。所以在vite下。module.exports 被rollup-commonjs之类的插件给重写成export default 了。

结论 TL.DR

构建工具帮你做到了这点,但是不建议混着用,这个使用本身没有问题,但是不是很规范。除非你懂为什么,对于构建工具,真正不被允许的模块混用是这样的,就是在一个文件内,你混用了

// a.js
import b from "./b.js"
module.exports ="a"+b 

// 这个代码会导致构建工具无法区分应该用esm还是commonjs来处理这个模块

补充

为什么构建工具要做这一点功能?你自己的代码,我想很少人会esm 跟commonjs 混在一起用。但是很多npm包,他可能commonjs 也可能是umd,他们早在esm出来之时就存在了,是一些历史悠久的但功能强大的库,有人可能还在用旧的版本,就需要去兼容他们

以上。

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容