I am trying to include a precompiled binary with an electron app. I began with electron quick start app and modified my renderer.js
file to include this code that is triggered when a file is dropped on the body:
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}`);
});
I have placed my precompiled ffmpeg binary in node_modules/.bin/
. Everything works great in the dev panel, but when I use electron-packager to set up the app, it throws a spawn error ENOENT
to the console when triggered. I did find a very similar question on SO, but the question doesn't seem to be definitively answered. The npm page on electron-packager does show that they can be bundled, but I cannot find any documentation on how to do so.
I know I'm a bit late but just wanted to mention
ffbinaries
npm package I created a while ago exactly for this purpose.It'll allow you to download ffmpeg/ffplay/ffserver/ffprobe binaries to specified location either during application boot (so you don't need to bundle it with your application) or in a CI setup. It can autodetect platform, you can also specify it manually.
This is how I would do it:
Taking cues from tsuriga's answer, here is my code:
Note: replace or add OS path accordingly.
Why this is better?
Most of the answers require an additional package called app-root-dir
The original answer doesn't handle the (env=production) build or the pre-packed versions properly. He/she has only taken care of development and post-packaged versions.
The problem is that
electron-builder
orelectron-packager
will bundle your dependency into theasar
file. It seems that if the dependency has a binary intonode_modules/.bin
it is smart enough to not package it.This is the documentation for asar packaging for
electron-builder
on that topic. It saysI understand that it is related to existing binaries in
node_modules/.bin
.If the module you are using is not automatically unpacked you can disable
asar
archiving completely or explicitly tellelectron-builder
to not pack certain files. You do so in yourpackage.json
file like this:For your particular case
I ran into the same issue with
ffmpeg
and this is what I've done:ffmpeg-static
. This package bundles statically compiled ffmpeg binaries for Windows, Mac and Linux. It also provides a way to get the full path of the binary for the OS you are running:require('ffmpeg-static').path
Tell
electron-builder
to not pack theffmpeg-static
module:"build": { "asarUnpack": [ "**/app/node_modules/ffmpeg-static/*" ],
Now we need to slightly change the code to get the right path to
ffmpeg
with this code:require('ffmpeg-static').path.replace('app.asar', 'app.asar.unpacked')
(if we are in development thereplace()
won't replace anything which is fine).If you are using webpack (or other javascript bundler)
I ran into the issue that
require('ffmpeg-static').path
was returning a relative path in the renderer process. But the issue seemed to be that webpack changes the way the module is required and that preventsffmpeg-static
to provide a full path. In the Dev Tools therequire('ffmpeg-static').path
was working fine when run manually, but when doing the same in the bundled code I was always getting a relative path. So this is what I did.BrowserWindow
:global.ffmpegpath = require('ffmpeg-static').path.replace('app.asar', 'app.asar.unpacked')
. The code that runs in the main process is not bundled by webpack so I always get a full path with this code.require('electron').remote.getGlobal('ffmpegpath')
If anyone happens to need an answer to this question: I do have a solution to this, but I have no idea if this is considered best practice. I couldn't find any good documentation for including 3rd party precompiled binaries, so I just fiddled with it until it finally worked. Here's what I did (starting with the electron quick start, node.js v6):
From the app directory I ran the following commands to include the ffmpeg binary as a module:
(replace /usr/local/bin/ffmpeg with your current binary path, download it from here) Placing the link allowed electron-packager to include the binary I saved to node_modules/ffmpeg/.
Then to get the bundled app path I installed the npm package app-root-dir by running the following command:
Since I could then get the app path, I just appended the subfolder for my binary and spawned from there. This is the code that I placed in renderer.js:.