# 关于 exports is not defined 报错的乱解,最后解决了问题

参考文献

一篇文章搞清楚 exports is not defined 为什么又出现了 https://github.com/natsu0728/blog/issues/22

# 原因

导致这个 exports is not defined 问题的理由有很多种,但是原因只有一个:

直接上原因:webpack 没有识别出 CommonJs 写法的模块

JS 的模块系统主要分为 CommonJSES modules (区别看最下面拓展)

抱怨一下,这个问题我花了一天时间来找解决方案,有点恼火,主要是对 Webpack 使用和编译原理不熟悉

说一下我的报错产生的情景

  • 采用 vue-cli 搭建项目
  • 使用 webpack 开发模式-采用热更新
  • webpack 编译时未报错,运行到浏览器输出了报错

此文分析得出的解决方案,仅对此文情形有效,若对你的项目无效,还需要自行具体分析, 可参考 一篇文章搞清楚 exports is not defined 为什么又出现了 (opens new window)

# 报错分析

# 报错日志

index.mjs:9 Uncaught ReferenceError: exports is not defined
    at ./node_modules/normalize-wheel-es/dist/index.mjs (index.mjs:9:1)
    at __webpack_require__ (bootstrap:22:1)
    at fn (hot module replacement:61:1)
    at ./node_modules/element-plus/lib/directives/mousewheel/index.js (index.ts:66:1)
    at __webpack_require__ (bootstrap:22:1)
    at fn (hot module replacement:61:1)
    at ./node_modules/element-plus/lib/directives/index.js (index.ts:66:1)
    at __webpack_require__ (bootstrap:22:1)
    at fn (hot module replacement:61:1)
    at ./node_modules/element-plus/lib/components/time-picker/src/time-picker-com/basic-time-spinner.js
1
2
3
4
5
6
7
8
9
10
11

看第一行, 这里指出了 exports is not defined 是由于在引入 ./node_modules/normalize-wheel-es/dist/index.mjs (index.mjs:9:1) 文件时报错的

index.mjs:9 Uncaught ReferenceError: exports is not defined
    at ./node_modules/normalize-wheel-es/dist/index.mjs (index.mjs:9:1)
1
2

index.mjs 是一个 JS 文件,但是 .mjs 的后缀说明他本身是一个采用 ES modules 模块系统语法编写的文件

同理 index.cjs 就是 采用 CommonJS 模块系统语法编写的文件

再看 ./node_modules/normalize-wheel-es/dist/index.mjs (index.mjs:9:1) 说明这是一个依赖的引入

从报错日志调用栈来看 normalize-wheel-eselement-plus调用的,属于 element-plus 的依赖(即依赖的依赖)

我就是在这里卡住的,然后采用了许多连我自己的不清楚的解决方案,依旧不行

所以上面的分析似乎没有什么作用

但是在思考中我还是想到了一个问题:'webpack 在开发模式下的热更新编译采用的 CommonJS 还是 ES Modules 呢?'

热更新的实现主要是插件 webpack-dev-server 提供的

也就是 webpack-dev-server 采用的 CommonJS 还是 ES Module?

很遗憾,网上没有搜到,怎么办

果断问了一下 G 老师

我:webpack-dev-server 采用的 CommonJS 还是 ES Module?

chatgpt:webpack-dev-server 主要使用 CommonJS 模块格式来处理其内部代码。虽然 Webpack 本身支持 ES Modules (import/export),许多与 Webpack 相关的工具和库,包括 webpack-dev-server,仍然使用 CommonJS 格式。
1
2
3

原来如此,姑且相信 G 老师

去官网的 webpack-dev-server https://webpack.js.org/api/webpack-dev-server/ 介绍中 也说了这么一句话

webpack-dev-server provides a Node.js API which can be used directly in Node.js runtime.

译文:Webpack-dev-server 提供了一个 Node.js API,这个 API 可以直接在 Node.js 运行时中使用。

那 nodejs 本身是采用什么模块系统呢

我:nodejs 支持哪一种 模块系统?

chatgpt:
CommonJS: 这是 Node.js 的默认模块系统。它使用 require() 来导入模块,使用 module.exports 来导出模块。
Node.js 从版本 12 开始支持 ESM(ES Modules),但要完全支持,需要 Node.js 14 及以上版本,并且需要在文件名中使用 .mjs 扩展名,或者在 package.json 中设置 "type": "module"。
1
2
3
4
5

所以结合两次G老师的答案,猜测webpack 使用 Webpack-dev-server 热更新编译后的代码文件是使用 CommonJS

所以产生报错的链路就是,热更新编译的代码采用CommonJS,但是依赖库的 normalize-wheel-es 提供的是 ES modules的 .mjs文件,然后就报错了

然后, 就没有然后

我又卡住了

既然 编译后的代码文件使用 CommonJS 模块,而依赖库的 normalize-wheel-es 确实ES modules 文件,该如何解决呢

但是此时瞎猫碰到死耗子, 编译时采用排除 node_modules 依赖库的办法成功解决了报错

# 解决方案

vue.config,js 中手动配置 babel-loader 处理器,并将 node_modules 排除在外






 
 
 
 
 











module.exports = {
  chainWebpack: (config) => {
    // ... 其他配置

    // 排除 node_modules 依赖的编译
    config.module
      .rule("js")
        .test(/\.(js|mjs)$/)
      .exclude.add(/node_modules/)
        .end()
      .use("babel-loader") // 修改 babel-loader 的配置选项
        .loader("babel-loader")
        .tap((options) => {
            return {
            ...options,
            presets: ["@babel/preset-env"],
            };
        });
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 拓展

先要明确的是 exports 本身是 CommonJS 的用法, CommonJS 基础用法如下:

  • CommonJS
// 导出
module.exports = { XXX: "HIHI" };

// 导入
const { XXX } = require("/filePath");
1
2
3
4
5

相对于 CommonJS ,就是 ES modules 模块, ES modules 基础用法如下:

  • ES modules
// 用法一: 多个导出,多个导入
// 导出
export {XXX:'HIHI'}
// 导入
import { XXX } from '/filePath'

// 用法二: 整体导出,整体导入
// 导出
export default {XXX:'HIHI'}
// 导入
import YYY from '/filePath'
console.log(YYY.XXX) // 'HIHI'

1
2
3
4
5
6
7
8
9
10
11
12
13

若有遗漏及错误描述,望指出,接受拷打🤓