Angular与Electron IPC通信报错:无法解析fs/path模块
Electron + Angular IPC通信报错:无法解析fs/path模块
报错内容
./node_modules/electron/index.js:1:11-24 - Error: Module not found: Error: Can't resolve 'fs' in '/home/user/Desktop/project/node_modules/electron' ./node_modules/electron/index.js:2:13-28 - Error: Module not found: Error: Can't resolve 'path' in '/home/user/Desktop/project/node_modules/electron'
主进程代码(main.js)
const {app, ipcMain} = require('electron'); const {BrowserWindow} = require('electron'); const url = require("url"); const path = require("path"); let window function createWindow () { window = new BrowserWindow({ width: 800, height: 600, autoHideMenuBar: true, webPreferences: { nodeIntegration: true } }); window.setMinimumSize(800, 600); window.loadURL( url.format({ pathname: path.join(__dirname, `/dist/music-converter/index.html`), protocol: "file:", slashes: true }) ); } app.on('ready', createWindow); app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit() }) app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) ipcMain.on('message-from-renderer', (event, arg) => { console.log(arg); event.reply('message-from-main', 'Message received in main process'); });
Angular组件代码
import { Component, OnInit } from '@angular/core'; import { ipcRenderer } from 'electron' @Component({ selector: 'file-browser', templateUrl: './file-browser.component.html', styleUrls: ['./file-browser.component.scss'] }) export class FileBrowserComponent implements OnInit { constructor() { } ngOnInit() { ipcRenderer.send('message-from-renderer', 'test'); } }
环境信息
- Electron: 30.0.1
- Angular: 16.2.0
已尝试但无效的方案
- 更换导入方式,使用
window.require:
或if ((<any>window).require) { this.ipcRenderer = (<any>window).require('electron').ipcRenderer; }ngOnInit() { if ((<any>window).require) { const electron = (<any>window).require('electron'); electron.ipcRenderer.send('message-from-renderer', 'test'); } else { console.error('Electron is not available'); } } - 配置webpack.config.js(已安装path-browserify):
或const webpack = require('webpack'); module.exports = { plugins: [ new webpack.ProvidePlugin({ fs: 'empty', path: 'empty' }) ] };const path = require('path'); module.exports = { resolve: { fallback: { fs: false, path: require.resolve('path-browserify') } } }; - 修改package.json添加配置:
"requires": true, "browser": { "fs": false, "path": false, "os": false } - 使用预加载脚本(未正确暴露IPC):
preload.js:
修改main.js的BrowserWindow配置:const fs = require('fs'); const path = require('path');window = new BrowserWindow({ width: 800, height: 600, autoHideMenuBar: true, webPreferences: { preload: path.join(__dirname, 'preload.js'), nodeIntegration: true } });
正确解决方案
1. 禁用Angular构建时对Electron模块的解析
在Angular项目根目录创建extra-webpack.config.js,添加如下配置:
module.exports = { externals: { electron: 'commonjs electron' } };
安装@angular-builders/custom-webpack以支持自定义Webpack配置:
npm install @angular-builders/custom-webpack --save-dev
修改angular.json中的构建配置,将builder替换为自定义Webpack:
找到projects -> [你的项目名] -> architect -> build,修改:
"builder": "@angular-builders/custom-webpack:browser", "options": { "customWebpackConfig": { "path": "./extra-webpack.config.js" }, // 保留原有其他配置 }
同样修改serve配置的builder为@angular-builders/custom-webpack:dev-server。
2. 使用预加载脚本安全暴露IPC(符合Electron安全规范)
Electron 12+推荐关闭nodeIntegration,通过预加载脚本暴露必要API,而非直接开启node集成。
步骤1:编写预加载脚本(preload.js)
const { ipcRenderer, contextBridge } = require('electron'); // 通过contextBridge安全暴露IPC方法到渲染进程 contextBridge.exposeInMainWorld('electronAPI', { sendMessage: (channel, data) => { ipcRenderer.send(channel, data); }, receiveMessage: (channel, callback) => { ipcRenderer.on(channel, (event, ...args) => callback(...args)); } });
步骤2:修改main.js的BrowserWindow配置
关闭nodeIntegration,启用上下文隔离:
window = new BrowserWindow({ width: 800, height: 600, autoHideMenuBar: true, webPreferences: { preload: path.join(__dirname, 'preload.js'), nodeIntegration: false, // 关闭node集成,符合安全规范 contextIsolation: true // 启用上下文隔离,默认开启 } });
步骤3:修改Angular组件代码
通过全局window.electronAPI调用IPC方法,无需直接导入electron模块:
import { Component, OnInit } from '@angular/core'; // 声明全局类型,避免TypeScript报错 declare global { interface Window { electronAPI: { sendMessage: (channel: string, data: any) => void; receiveMessage: (channel: string, callback: (...args: any[]) => void) => void; }; } } @Component({ selector: 'file-browser', templateUrl: './file-browser.component.html', styleUrls: ['./file-browser.component.scss'] }) export class FileBrowserComponent implements OnInit { constructor() { } ngOnInit() { // 发送消息到主进程 window.electronAPI.sendMessage('message-from-renderer', 'test'); // 监听主进程回复 window.electronAPI.receiveMessage('message-from-main', (message) => { console.log(message); }); } }
3. 重新构建并启动项目
ng build electron .
内容的提问来源于stack exchange,提问作者Zipity
相关产品推荐
相关产品推荐

