我正在尝试使用电子应用程序包含预编译的二进制文件。我从电子快速启动应用程序开始,修改了我的renderer.js
文件,以包含在文件被放置在正文上时触发的代码:
spawn = require('child_process').spawn,
ffmpeg = spawn('node_modules/.bin/ffmpeg', ['-i', clips[0], '-an', '-q:v', '1', '-vcodec', 'libx264', '-y', '-pix_fmt', 'yuv420p', '-vf', 'setsar=1,scale=trunc(iw/2)*2:trunc(ih/2)*2,crop=in_w:in_h-50:0:50', '/tmp/out21321.mp4']);
ffmpeg.stdout.on('data', data => {
console.log(`stdout: ${data}`);
});
ffmpeg.stderr.on('data', data => {
console.log(`stderr: ${data}`);
});
我已将预编译的 ffmpeg 二进制文件放在node_modules/.bin/
中。在开发面板中一切都很好用,但是当我使用电子打包器来设置应用程序时,它会在触发时向控制台抛出spawn error ENOENT
。我确实在SO上找到了very similar question,但这个问题似乎没有得到明确的回答。 npm page on electron-packager确实显示它们可以捆绑,但我找不到任何有关如何操作的文档。
答案 0 :(得分:23)
问题是electron-builder
或electron-packager
会将您的依赖项捆绑到asar
文件中。似乎如果依赖项有一个二进制文件node_modules/.bin
,它就足够聪明,不能打包它。
这是该主题electron-builder
的{{3}}。它说
将自动检测必须解压缩的节点模块
我了解它与node_modules/.bin
中的现有二进制文件有关。
如果您使用的模块未自动解压缩,您可以完全禁用asar
存档,或明确告诉electron-builder
不要打包某些文件。您可以在package.json
文件中执行此操作:
"build": {
"asarUnpack": [
"**/app/node_modules/some-module/*"
],
我与ffmpeg
遇到了同样的问题,这就是我所做的:
require('ffmpeg-static').path
告诉electron-builder
不要打包ffmpeg-static
模块:
" build":{ " asarUnpack":[ " ** /应用/ node_modules / ffmpeg的静电/ *" ],
现在我们需要稍微更改代码,以便使用以下代码获取ffmpeg
的正确路径:require('ffmpeg-static').path.replace('app.asar', 'app.asar.unpacked')
(如果我们正在开发replace()
赢了&#39} t替换任何好的东西。)
我遇到了require('ffmpeg-static').path
在渲染器进程中返回相对路径的问题。但问题似乎是webpack改变了模块的需求方式,并阻止ffmpeg-static
提供完整路径。在开发工具中,require('ffmpeg-static').path
在手动运行时工作正常,但是当在捆绑代码中执行相同操作时,我总是得到相对路径。所以这就是我所做的。
BrowserWindow
:global.ffmpegpath = require('ffmpeg-static').path.replace('app.asar', 'app.asar.unpacked')
之前添加此内容。在主进程中运行的代码没有被webpack捆绑,所以我总是得到这个代码的完整路径。require('electron').remote.getGlobal('ffmpegpath')
答案 1 :(得分:3)
我知道我有点迟了但只是想提一下我刚才为此创建的ffbinaries
npm包。
它允许您在应用程序启动期间(因此您不需要将其与应用程序捆绑在一起)或在CI设置中将ffmpeg / ffplay / ffserver / ffprobe二进制文件下载到指定位置。它可以自动检测平台,您也可以手动指定它。
答案 2 :(得分:2)
如果有人碰巧需要回答这个问题:我确实有解决方法,但我不知道这是否是最佳实践。我无法找到包含第三方预编译二进制文件的任何好文档,所以我只是摆弄它直到它最终起作用。这就是我所做的(从电子快速启动开始,node.js v6):
在app目录中,我运行了以下命令,将ffmpeg二进制文件包含为模块:
mkdir node_modules/ffmpeg
cp /usr/local/bin/ffmpeg node_modules/ffmpeg/
ln -s ../ffmpeg/ffmpeg node_modules/.bin/ffmpeg
(将/ usr / local / bin / ffmpeg替换为您当前的二进制路径,从此处下载)放置链接允许electron-packager包含我保存到node_modules / ffmpeg /的二进制文件。
然后,为了获得捆绑的应用程序路径,我通过运行以下命令安装了npm包app-root-dir:
npm i -S app-root-dir
因为我可以获得应用程序路径,所以我只是附加了我的二进制文件的子文件夹并从那里生成。这是我放在renderer.js中的代码:。
var appRootDir = require('app-root-dir').get();
var ffmpegpath=appRootDir+'/node_modules/ffmpeg/ffmpeg';
console.log(ffmpegpath);
const
spawn = require( 'child_process' ).spawn,
ffmpeg = spawn( ffmpegpath, ['-i',clips_input[0]]); //add whatever switches you need here
ffmpeg.stdout.on( 'data', data => {
console.log( `stdout: ${data}` );
});
ffmpeg.stderr.on( 'data', data => {
console.log( `stderr: ${data}` );
});
答案 3 :(得分:0)
这就是我要做的:
根据tsuriga's answer的提示,这是我的代码:
注意:相应地替换或添加 OS 路径。
'use strict'; import path from 'path'; import { remote } from 'electron'; import getPlatform from './get-platform'; const IS_PROD = process.env.NODE_ENV === 'production'; const root = process.cwd(); const { isPackaged, getAppPath } = remote.app; const binariesPath = IS_PROD && isPackaged ? path.join(path.dirname(getAppPath()), '..', './Resources', './bin') : path.join(root, './resources', getPlatform(), './bin'); export const execPath = path.resolve(path.join(binariesPath, './exec-file-name'));
'use strict'; import { platform } from 'os'; export default () => { switch (platform()) { case 'aix': case 'freebsd': case 'linux': case 'openbsd': case 'android': return 'linux'; case 'darwin': case 'sunos': return 'mac'; case 'win32': return 'win'; } };
"build": { .... "extraFiles": [ { "from": "resources/mac/bin", "to": "Resources/bin", "filter": [ "**/*" ] } ], .... },
import { execPath } from './binaries'; #your program code: var command = spawn(execPath, arg, {});
为什么这样更好?
大多数答案都需要一个名为 app-root-dir
原始答案无法正确处理(env = production) build 或预包装版本。他/她只负责开发和后期打包版本。