如何使用 Electron 运行和打包外部可执行文件? [英] How to run and pack external executable using Electron?

查看:33
本文介绍了如何使用 Electron 运行和打包外部可执行文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

For example, I have a compiled binary cudaDeviceQuery which returns a list of devices as JSON. Here's a piece of code:

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 错误.在开发环境中生成它并将其打包到生产环境中的正确方法是什么?

But when I use this function from renderer process __dirname is /, so I get spawn /darwin/cudaDeviceQuery ENOENT error. What's proper way to spawn it in dev envivroment and pack it in production?

一个 webpack 配置:

A webpack config:

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:

As you see, I'm using dev server for hot module replacement, so maybe that is reason of this... I have server.js which create server with scripts and then I use it from main process. Here's 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 但没关系,我可以切换到另一个 builder.

Another words, I need to call cudaDeviceQuery library from electron renderer process. I'm using a electron-builder but it doesn't matter, I can switch to another builder.

推荐答案

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

There are two things. If you set __dirname: true in your web app config you will get the relative path of the file from your context directory

如果您设置 __dirname: false 那么 __dirname 将具有完整路径.

If you set __dirname: false then __dirname will have the full path.

开发模式

你有两个选择

  1. 设置 __dirname: true 并将其与 os.cwd()
  2. 连接
  3. 设置__dirname: false,直接使用__dirname
  1. Set __dirname: true and concatenate it with os.cwd()
  2. Set __dirname: false and use __dirname directly

生产模式

  1. 设置 __dirname: true 并使用 os.cwd().
  2. 设置 __dirname: true 并使用 process.resourcePath
  1. Set __dirname: true and use os.cwd().
  2. Set __dirname: true and use process.resourcePath

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

I will prefer 2 as the preferred approach in production

这篇关于如何使用 Electron 运行和打包外部可执行文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆