如何使用 Electron 运行和打包外部可执行文件?

Posted

技术标签:

【中文标题】如何使用 Electron 运行和打包外部可执行文件?【英文标题】:How to run and pack external executable using Electron? 【发布时间】:2018-08-06 19:32:16 【问题描述】:

例如,我有一个已编译的二进制文件cudaDeviceQuery,它以 JSON 形式返回设备列表。这是一段代码:

export default function cudaDeviceQuery(): Promise<CollectorResponse> 
  const throwError = () => 
    throw new Error("Unfortunately your platform isn't yet unsupported");
  ;

  const file = __DARWIN__
    ? path.join(__dirname, 'darwin', 'cudaDeviceQuery')
    : __WIN32__
      ? path.join(__dirname, 'win', 'cudaDeviceQuery.exe')
      : throwError();

  const descriptor = spawn(file);

  return new Promise((resolve, reject) => 
    let outerData = '';
    descriptor.stdout.on('data', data => 
      outerData += data;
    );

    descriptor.on('close', () => 
      try 
        resolve(JSON.parse(outerData));
       catch (e) 
        reject(e);
      
    );
  );

但是当我从渲染器进程中使用这个函数时,__dirname/,所以我得到spawn /darwin/cudaDeviceQuery ENOENT 错误。在开发环境中生成它并将其打包到生产环境中的正确方法是什么?

一个 webpack 配置:

webpack.config.base.js:

/**
 * Base webpack config used across other specific configs
 */
const webpack = require('webpack');
const path = require('path');
const getReplacements = require('./app/app-info').getReplacements;
const  dependencies: externals  = require('./app/renderer/package.json');

module.exports = 
  module: 
    noParse: [path.join(__dirname, 'node_modules/ws')],
    rules: [
      
        test: /\.tsx?$/,
        use: [
          
            loader: 'babel-loader',
          ,
          
            loader: 'ts-loader',
          ,
        ],
        exclude: /node_modules/,
      ,
    ],
  ,

  output: 
    path: path.join(__dirname, 'app', 'renderer'),
    filename: 'bundle.js',
    libraryTarget: 'commonjs2',
  ,
  // https://webpack.github.io/docs/configuration.html#resolve
  resolve: 
    extensions: ['.js', '.ts', '.tsx', 'json'],
    modules: [path.join(__dirname, 'app', 'renderer'), 'node_modules'],
  ,
  plugins: [new webpack.DefinePlugin(getReplacements())],

  externals: [...Object.keys(externals || ), 'ws'],
;

webpack.config.development.js:

/**
 * Build config for development process that uses Hot-Module-Replacement
 * https://webpack.github.io/docs/hot-module-replacement-with-webpack.html
 */

const webpack = require('webpack');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.config.base');
const getReplacements = require('./app/app-info').getReplacements;

const port = process.env.PORT || 3000;

module.exports = merge(baseConfig, 
  devtool: 'inline-source-map',

  entry: [
    'react-hot-loader/patch',
    `webpack-hot-middleware/client?path=http://localhost:$port/__webpack_hmr&reload=true`,
    './app/renderer/index',
  ],

  output: 
    publicPath: `http://localhost:$port/dist/`,
  ,

  module: 
    rules: [
      // Css, SCSS, woff loaders are here
    ],
  ,

  plugins: [
    // https://webpack.github.io/docs/hot-module-replacement-with-webpack.html
    new webpack.HotModuleReplacementPlugin(),

    new webpack.LoaderOptionsPlugin(
      debug: true,
    ),
  ],

  // https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
  target: 'electron-renderer',
);

webpack.config.electron.js:

/**
 * Build config for electron 'Main Process' file
 */

const webpack = require('webpack');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.config.base');
const getReplacements = require('./app/app-info').getReplacements;

module.exports = merge(baseConfig, 
  devtool: 'source-map',

  entry: ['./app/main/index.ts'],

  // 'main.js' in root
  output: 
    path: __dirname,
    filename: './app/main/main.js',
  ,

  plugins: [
    // Add source map support for stack traces in node
    // https://github.com/evanw/node-source-map-support
    // new webpack.BannerPlugin(
    //   'require("source-map-support").install();',
    //    raw: true, entryOnly: false 
    // ),
  ],

  /**
   * Set target to Electron specific node.js env.
   * https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
   */
  target: 'electron-main',

  /**
   * Disables webpack processing of __dirname and __filename.
   * If you run the bundle in node.js it falls back to these values of node.js.
   * https://github.com/webpack/webpack/issues/2010
   */
  node: 
    __dirname: false,
    __filename: false
  ,
);

如您所见,我正在使用开发服务器进行热模块更换,所以也许这就是原因...我有server.js 使用脚本创建服务器,然后我从主进程中使用它。这里是server.js

/**
 * Setup and run the development server for Hot-Module-Replacement
 * https://webpack.github.io/docs/hot-module-replacement-with-webpack.html
 */
const argv = require('minimist')(process.argv.slice(2));
const  spawn  = require('child_process');

async function createMiddleware(port, configPath) 
  const express = require('express');
  const webpack = require('webpack');
  const webpackDevMiddleware = require('webpack-dev-middleware');
  const webpackHotMiddleware = require('webpack-hot-middleware');

  const config = require(configPath);

  const app = express();
  const compiler = webpack(config);
  const PORT = process.env.PORT || port;

  const wdm = webpackDevMiddleware(compiler, 
    publicPath: config.output.publicPath,
    stats: 
      colors: true,
    ,
  );

  app.use(wdm);

  app.use(webpackHotMiddleware(compiler));

  const server = app.listen(PORT, serverError => 
    if (serverError) 
      return console.error(serverError);
    

    console.log(`Listening at http://localhost:$PORT`);
  );

  process.on('SIGTERM', () => 
    console.log('Stopping dev server');
    wdm.close();
    server.close(() => 
      process.exit(0);
    );
  );


createMiddleware(3000, './webpack.config.development'); // A main renderer process
createMiddleware(3010, './webpack.config.server'); // A backend for communicating between renderer and remote server

if (argv['start-hot']) 
  spawn('npm', ['run', 'start-hot'], 
    shell: true,
    env: process.env,
    stdio: 'inherit',
  )
    .on('close', code => process.exit(code))
    .on('error', spawnError => console.error(spawnError));

换句话说,我需要从电子渲染器进程中调用cudaDeviceQuery 库。我使用的是electron-builder,不过没关系,我可以切换到另一个构建器。

【问题讨论】:

请将您的 webpack 配置添加到问题中 @TarunLalwani 好的,已添加 有两种方法。您可以使用process.cwd()process.resourcePath,而不是依赖__dirname。在开发中,您可以在调用__dirname 时使用__dirname: true 获取完整路径。但是对于生产,您需要使用两种方法之一 不幸的是,如果我将webpack.config.electron.js 中的__dirname 设置为true,我会收到Not allowed to load local resource: file://app/renderer/app.html 错误。 process.cwd() 帮助!但我不确定这对生产有什么好处(如果应用程序不是从他们的目录中调用的)。我发现了另一种方法:__dirname 在主进程中完美运行,因此我可以通过 ipc 获取文件的完整路径。你能提交你的答案,然后我会接受吗? 【参考方案1】:

有两件事。如果您在 Web 应用配置中设置 __dirname: true,您将从上下文目录中获取文件的 relative 路径

如果您设置了__dirname: false,那么__dirname 将拥有完整路径。

开发模式

你有两个选择

    设置__dirname: true 并将其与os.cwd() 连接 设置__dirname: false,直接使用__dirname

生产模式

    设置__dirname: true并使用os.cwd()。 设置__dirname: true并使用process.resourcePath

我更喜欢 2 作为生产中的首选方法

【讨论】:

【参考方案2】:

将此添加到package.json

"scripts": 
    "start": "electron .", "install": "electron-rebuild",
    "package-osx": "electron-packager . Node-RED --platform=darwin --arch=x64 --   out=build --overwrite",
    "package-mac": "electron-packager . --overwrite --platform=darwin --arch=x64 --prune=true --out=release-builds",
    "package-win": "electron-packager . electron-serialport --overwrite --asar=true --platform=win32 --arch=x64 --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"CryptoApp\"",
    "package-linux": "electron-packager . electron-serialport --overwrite --asar=true --platform=linux --arch=x64 --prune=true --out=release-builds"
,

"dependencies": 
    "electron-packager": "^12.1.0",
    "electron-prebuilt": "^1.4.13",

如果不适用于 windows,请使用以下内容:

"package-win": "electron-packager . electron-serialport --overwrite --asar=true --platform=win32 --arch=ia32 --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"CryptoApp\"",

谢谢...

【讨论】:

以上是关于如何使用 Electron 运行和打包外部可执行文件?的主要内容,如果未能解决你的问题,请参考以下文章

electron在win上可运行后,如何打包到linux上运行?

Electron 应用部署

使用electron进行原生应用的打包

打包Electron项目

Electron打包优化

electron-packager打包报错