electron打包make后的exe模块运行不正常

产生的问题:我使用nodejs和electron开发应用,make后生成的exe可执行文件没有nodejs引入的模块涉及的功能。

左图是开发环境使用命令“npm start”正常运行的界面,右图是make后产生的exe文件运行界面。引入的模块是child_process(经测试,任何nodejs引入的模块都无法使用)。

img

开发环境:

开发使用的操作系统:windows 11企业版22H2
node版本:19.6.0
npm版本:9.4.1
electron版本:23.0.0

相关代码如上图所示,我在electron项目中的preload.js文件中添加了子进程模块child_process,在make后并没有起作用。preload.js具体代码如下:

const { fork } = require('child_process')
const netcheck = fork('./netcheck.js')

window.addEventListener('DOMContentLoaded', () => {
    const status = document.getElementById('status')
    netcheck.on('message', (m)=>{
        netcheck.send('check')
        status.innerText = m.data
    })
    netcheck.send('check')
})

子进程文件netcheck.js的代码如下:

const dns = require('node:dns')
process.on('message',()=>{
    setTimeout(getNetstatus,3000)
})

function getNetstatus(){
    dns.lookup('cloud.tencent.com',(err)=>{
        if (err){
            msg = {code:0,data:"网络出错,请检查网络连接"}
            process.send(msg)
        }else{
            msg = {code:1,data:"网络连接正常"}
            process.send(msg)
        }
    })
}

前端html、javascript、css都正常,仅仅是nodejs部分没有起作用。

上面看到的“正在检测网络状态”的字样是预先在html里设定好的。

以下是入口程序main.js的代码:

// main.js
const { app, BrowserWindow} = require('electron')
const { join } = require('path')
const createWindow = () => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegrationInWorker: true,
      preload: join(__dirname, 'preload.js')
    }
  })
  mainWindow.loadFile('index.html')
  mainWindow.webContents.openDevTools()
}

app.whenReady().then(() => {
  createWindow()
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

以下是index.html文件:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    <title>检测</title>
    <link type="text/css" rel="stylesheet" href="resources/bootstrap-icons.css">
    <link type="text/css" rel="stylesheet" href="resources/main.css">
  </head>
  <body>
    <div id="brand">
      <i class="bi bi-globe2"></i><div><span>好抓</span>网络抓取客户端</div>
    </div>
    <div id="status">正在检测网络状态</div>
    <div id="list" class="list-normal"></div>
    <script type="text/javascript" src="resources/require.js" data-main="resources/index.js"></script>
  </body>
</html>

打包过程:

  1. 下载electron-forge并导入项目
    npm install --save-dev @electron-forge/cli
    npx electron-forge import
    
  1. 然后make
    npm run make
    

根据你提供的信息,我推测这是因为 'child_process应用使用了不同的运行时(Chromium 浏览器)。如果没有正确打包 Node.js 核心模块,这些模块就不能在 Electron 应用中运行。

为了正确地打包 Node.js 核心模块,你可以使用electron-forge的一些插件,例如@electron-forge/plugin-webpack或@electron-forge/plugin-webpack-rc.这些插件可以在打包时将 Node.js 核心模块打包到 Electron 应用中。

以下是使用@electron-forge/plugin-webpack的步骤:

1.安装@electron-forge/plugin-webpack:

npm install --save-dev @electron-forge/plugin-webpack

2.在 '包文件中,添加以下配置:

"config": {
    "forge": {
      "packagerConfig": {},
      "makers": [
        {
          "name": "@electron-forge/maker-squirrel",
          "config": {
            "name": "your-app-name"
          }
        }
      ],
      "plugins": [
        [
          "@electron-forge/plugin-webpack",
          {
            "mainConfig": "./webpack.main.config.js",
            "renderer": {
              "config": "./webpack.renderer.config.js",
              "entryPoints": [
                {
                  "html": "./src/index.html",
                  "js": "./src/renderer.ts",
                  "name": "main_window"
                }
              ]
            }
          }
        ]
      ]
    }
  }

3.在项目根目录下创建 'webpack.renderer.config.js

const path = require('path')

module.exports = {
  target: 'electron-renderer',
  entry: {
    renderer: './src/renderer.ts'
  },
  resolve: {
    extensions: ['.js', '.ts', '.jsx', '.tsx', '.json']
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}

4.修改 'preload.js中加载child_process模块的方式,改为使用require加载,如下所示:

window.child_process = require('child_process');

5.重新运行npm run make,等待打包完成。

如果你需要使用其他插件打包,可以参考它们的文档进行配置。

你会不会没有权限啊?
没有权限保存,或者没有权限写入
你检查下看看

这个问题可能是由于在打包时未将所需的模块打包到可执行文件中导致的。在 Electron 打包应用时,需要确保所有依赖的模块都被打包到可执行文件中,否则应用程序可能会出现运行时错误,如缺少模块的错误。

您可以尝试使用 Electron 打包工具中提供的命令行选项来打包所有依赖的模块。例如,使用 --asar 选项可以将应用程序和所有依赖的模块打包成一个 asar 文件,以便更好地管理和分发应用程序。

另外,您可能需要检查您的代码中是否存在引用本地文件的情况。在打包后,这些本地文件可能无法正确加载,从而导致应用程序无法正常工作。在这种情况下,您可以使用 Node.js 的内置模块 path 来动态获取文件的路径,而不是使用硬编码的本地路径。

最后,您可以尝试在开发模式下使用 Electron 运行应用程序,并查看是否存在任何错误或警告信息。

提供一个参考讨论实例:https://segmentfault.com/q/1010000022996984?utm_source=tag-newest

看看在打包应用程序时是否包含了子进程模块,可以尝试在electron-forge的构建配置文件中添加asarUnpack选项,以便在构建过程中将模块解压到应用程序包中。