You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron+React项目使用ipcRenderer存储数据时模块找不到报错求助

解决Electron + React中ipcRenderer引入导致的fs/path模块找不到问题

问题背景

开发跨端应用(PC端基于Electron,Web端用Firebase),PC端计划用electron-store做本地存储,在React组件中尝试引入ipcRenderer时触发模块找不到错误,项目未手动配置Webpack,使用react-scripts默认配置。

相关代码

package.json

{
  "name": "app",
  "version": "0.0.1",
  "main": "public/electron.js",
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^14.4.3",
    "concurrently": "^7.4.0",
    "cowsay": "^1.5.0",
    "cross-env": "^7.0.3",
    "electron": "^21.1.1",
    "electron-is-dev": "^2.0.0",
    "electron-store": "^8.1.0",
    "firebase": "^9.9.4",
    "jquery": "^3.6.1",
    "jquery-ui": "^1.13.2",
    "node-polyfill-webpack-plugin": "^2.0.1",
    "path-browserify": "^1.0.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.3.0",
    "react-scripts": "^5.0.1",
    "react-use-draggable-scroll": "^0.4.7",
    "regexp": "^1.0.0",
    "typescript": "^4.8.4",
    "util": "^0.12.4",
    "uuid": "^9.0.0",
    "wait-on": "^6.0.1",
    "web-vitals": "^3.0.1"
  },
  "scripts": {
    "react-start": "react-scripts start",
    "react-build": "react-scripts build",
    "react-test": "react-scripts test",
    "react-eject": "react-scripts eject",
    "electron-builder": "electron-builder",
    "build": "npm run react-build && npm run electron-build",
    "start": "concurrently \"cross-env BROWSER=none npm run react-start\" \"wait-on http://localhost:3000 && electron . --no-sandbox\""
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

electron.js

const path = require("path");
const isDev = require("electron-is-dev");
const { FETCH_DATA_FROM_STORAGE, PUSH_DATA_TO_STORAGE } = require("../src/utils/Constants");

const electron = require('electron');
const app = electron.app;
const ipcMain = electron.ipcMain;
const BrowserWindow = electron.BrowserWindow;
const Store = require('electron-store');

const createWindow = () => {
    const win = new BrowserWindow({
        width: 1080,
        height: 720,
    })

    win.loadURL(
        isDev ? 'http://localhost:3000' : "file://" + path.join(__dirname, "../build/index.html")
    )
}

let store = new Store();
ipcMain.on('FETCH_DATA_FROM_STORAGE', (event, arg) => {
    console.log('store', store.get('contests'));
});

app.whenReady().then(() => {
    createWindow()
})

ContestHandlerApp.js

import { auth, firestore } from "../firebase/firebase-config";
import { Tools } from '../utils/Tools';
import { AbstractContestHandler } from "./AbstractContestHandler.ts";
import { FETCH_DATA_FROM_STORAGE, PUSH_DATA_TO_STORAGE } from "../utils/Constants";

const { ipcRenderer } = require('electron');

export class ContestHandlerApp extends AbstractContestHandler {

    createContest(contest) {
    }

    deleteContest(uid: string) {

    }

    updateContest(contest) {

    }

    getContest(uid: string) {
        return null;
    }

    getContests() {
        window.Electron.ipcRenderer.send(FETCH_DATA_FROM_STORAGE, "contests")
        return [];
    }
}

报错信息

ERROR in ./node_modules/electron/index.js 1:11-24
Module not found: Error: Can't resolve 'fs' in '/home/username/Desktop/NextPetanque/app/node_modules/electron'

ERROR in ./node_modules/electron/index.js 2:13-28
Module not found: Error: Can't resolve 'path' in '/home/username/Desktop/NextPetanque/app/node_modules/electron'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
    - add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
    - install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
    resolve.fallback: { "path": false }

解决方案

1. 配置Electron预加载脚本(官方推荐安全方案)

在public目录下新建preload.js,用contextBridge将ipcRenderer的方法暴露给渲染进程:

const { ipcRenderer, contextBridge } = require('electron');

// 暴露指定API给前端,避免直接暴露ipcRenderer
contextBridge.exposeInMainWorld('ElectronAPI', {
  fetchDataFromStorage: (arg) => ipcRenderer.send('FETCH_DATA_FROM_STORAGE', arg)
});

2. 修改Electron主进程配置

更新electron.js中的BrowserWindow创建代码,添加预加载脚本路径和安全配置:

const createWindow = () => {
    const win = new BrowserWindow({
        width: 1080,
        height: 720,
        webPreferences: {
            // 指定预加载脚本路径
            preload: path.join(__dirname, 'preload.js'),
            // 开启上下文隔离,防止渲染进程篡改主进程API
            contextIsolation: true,
            // 禁用Node集成,提升安全性
            nodeIntegration: false
        }
    })

    win.loadURL(
        isDev ? 'http://localhost:3000' : "file://" + path.join(__dirname, "../build/index.html")
    )
}

3. 修正React组件代码

移除直接引入electron的代码,改用预加载脚本暴露的全局API:

// 删掉这一行:const { ipcRenderer } = require('electron');

export class ContestHandlerApp extends AbstractContestHandler {
    // ...其他方法保持不变
    getContests() {
        // 使用暴露的ElectronAPI
        window.ElectronAPI.fetchDataFromStorage("contests")
        return [];
    }
}

4. 可选:禁止Webpack解析electron模块

在package.json中添加以下配置,防止Webpack尝试打包electron模块:

"browser": {
    "electron": false
}

原理说明

报错原因是在React代码中直接require('electron'),Webpack会尝试解析electron模块的依赖(如Node.js核心模块fs、path),但这些模块在浏览器/渲染进程环境中不存在。使用预加载脚本+contextBridge是Electron官方推荐的方式,既能安全地向渲染进程暴露主进程API,又能避免Webpack打包时解析Node.js核心模块导致的错误。

内容的提问来源于stack exchange,提问作者Antox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:40:29