You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Electron+Vite项目集成SerialPort时出现__dirname相关ES模块兼容错误

Electron+Vite项目集成SerialPort时出现__dirname相关ES模块兼容错误

我太懂这种踩坑的烦躁感了——Electron+Vite的组合本身就有模块格式的兼容门槛,再加上SerialPort这类还没完全适配ES模块的Node.js库,很容易触发这种"ES模块/CommonJS冲突"的报错。先帮你拆解下问题根源,再给你两个可落地的解决方案:

问题根源

你的项目根目录package.json里设置了"type": "module",这会让Node.js把所有.js文件默认当作ES模块处理。但SerialPort内部大量使用了CommonJS的写法,再加上你在主进程里手动模拟__dirname(ES模块环境下原本没有这个变量),多重因素叠加就触发了报错。


解决方案一:用createRequire兼容引入SerialPort(最小改动)

这个方案不用改项目整体的模块格式,只调整主进程里引入SerialPort的方式:

  1. 在你的main.ts里,把原本直接import SerialPort的代码,改成用createRequire来引入(你已经在文件里引入了createRequire,刚好可以用上):
// 替换原来的 import { SerialPort, ReadlineParser } from 'serialport';
const require = createRequire(import.meta.url);
const { SerialPort, ReadlineParser } = require('serialport');
  1. 保留你当前的__dirname模拟代码(ES模块环境下这个写法是合规的):
import { fileURLToPath } from 'url';
import path from 'path';

const __filename = fileURLToPath(import.meta.url);
globalThis.__dirname = path.dirname(__filename); // Cria uma variável global __dirname

这个思路的核心是:在ES模块环境下,用Node.js提供的createRequire工具,以CommonJS的方式加载SerialPort这类未完全适配ES模块的库,直接避开模块格式冲突。


解决方案二:拆分主/渲染进程的模块格式(更彻底的长期方案)

如果方案一还是有问题,建议把主进程和渲染进程的模块格式彻底分开:主进程用CommonJS(适配SerialPort这类Node.js库),渲染进程用ES模块(适配Vite+React的开发习惯)。

  1. 修改项目根目录的package.json

    • 删除"type": "module"字段(这样默认所有.js文件会被当作CommonJS处理)
    • "main"字段改成"dist-electron/main.cjs"(对应主进程编译后的CommonJS输出文件)
  2. 给主进程单独配置TypeScript编译规则:
    在项目根目录新建tsconfig-electron.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "CommonJS",
    "target": "ES2020",
    "outDir": "dist-electron"
  },
  "include": ["electron/**/*.ts"] // 假设你的主进程代码在electron目录下
}
  1. 调整vite.config.ts里的electron插件配置,让主进程输出为CommonJS:
import { defineConfig } from 'vite'
import electron from 'vite-plugin-electron'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react(),
    electron({
      main: {
        entry: 'electron/main.ts',
        vite: {
          build: {
            outDir: 'dist-electron',
            rollupOptions: {
              output: {
                format: 'cjs', // 指定主进程输出为CommonJS
                entryFileNames: 'main.cjs' // 对应package.json里的main字段
              }
            },
            tsconfig: 'tsconfig-electron.json' // 用单独的TS配置
          }
        }
      },
      preload: {
        entry: 'electron/preload.ts'
      }
    })
  ]
})
  1. 简化主进程里的__dirname写法(CommonJS环境下默认存在这个变量,不需要手动模拟):
// 删掉原来的__dirname模拟代码,直接使用原生__dirname
import path from 'path';
process.env.APP_ROOT = path.join(__dirname, '..')

验证方案

改完之后,先运行npm run dev测试开发环境是否正常,再执行npm run build验证打包流程是否能通过。如果还有问题,可以检查serialport的版本(你用的v12.0.0是比较新的版本,大概率兼容,但也可以尝试降级到v11.x版本测试)。

备注:内容来源于stack exchange,提问作者João Vitor

火山引擎 最新活动