openSUSE:Packaging Electron
THIS IS AN UNFINISHED DRAFT
Build Service Tutorial · Tips & Tricks · Cross Distribution Howto · Packaging checks
Desktop menu categories · RPM Macros · Scriptlets · Init scripts · How to write good changes
Before you begin
Electron is not to be confused with nw.js, which is way less popular and (as of May 2024) not packaged by any distro. It is unknown whether Electron can run unmodified nw.js apps.
Download dependencies
Most (all?) apps have a package.json in the root and use a popular package manager such as npm or yarn. Both of these can usually execute arbitrary commands during vendoring dependencies
Avoid using the “offline cache” feature to call the package manager during build. It makes patching hard (npm) or impossible (yarn).
Instead, you must call your package manager in a way that it does not run build scripts (and preferably produces a reproducible result):
#npm (package-lock.json)
npm ci --verbose --ignore-scripts
#yarn (yarn.lock)
yarn install --frozen-lockfile --ignore-engines --ignore-platform --ignore-scripts --link-duplicates
Yarn can sometimes fail if the shrinkwrap file does not match the package. In that case you can use this command which does less stringent checks:
yarn install --pure-lockfile --ignore-engines --ignore-platform --ignore-scripts --link-duplicates
Yarn has a known minor reproducibility problem in that it embeds your Node major version and computer architecture into the tarball.
Remove forbidden items
Precompiled binaries are a severe problem in tarballs from the NPM registry. You must ensure they do not get used during build or shipped. The best moment to remove them is before packing the vendor tarball.
An example script that gets rid of most of them:
#zypper in file findutils moreutils
find . -name '*.node' -print -delete
find . -name '*.jar' -print -delete
find . -name '*.dll' -print -delete
find . -name '*.exe' -print -delete
find . -name '*.dylib' -print -delete
find . -name '*.so' -print -delete
find . -name '*.o' -print -delete
find . -name '*.a' -print -delete
find . -name '*.wasm' -print -delete
#We use sponge to avoid a race condition between find and rm
find . -type f| sponge |\
xargs -P"$(nproc)" -- sh -c 'file -S "$@" | grep -v '\'': .*script'\'' | grep '\'': .*executable'\'' | tee /dev/stderr | sed '\''s/: .*//'\'' | xargs rm -fv'
You should also remove any bundled libraries at this point.
Package only the node_modules into the vendor tarball.
Some applications can include multiple shrinkwrap files, example vscode
Build
In general the beginning of %build
should look like
%build
export CFLAGS="%{optflags}"
export CXXFLAGS="%{optflags}"
export LDFLAGS="%{?build_ldflags}"
export MAKEFLAGS="%{_smp_mflags}"
export ELECTRON_SKIP_BINARY_DOWNLOAD=1
%electron_rebuild
The %electron_rebuild
executes any build scripts in node_modules including, potentially, building native modules against Electron headers.
Native modules
If your package includes native modules which use only stable APIs (napi_* and uv_*) you must include the following in your spec to ensure they load successfully:
Requires: nodejs-electron%{_isa}
…
%check
%electron_check_native
This check will fail with an undefined symbol error if you use unstable APIs. In that case, use the following to ensure rebuilds on major Electron updates:
#in Requires: section
%electron_req
…
%check
%electron_check_native_unstable
C/C++ flags
- You are building a loadable plugin. The correct relocation model to use for loadable plugins is -fpic -fno-semantic-interposition. If you use a more relaxed model (-fpie or non-relocable) you will get a linker error. If you use a more strict model (-fpic) it will work but produce suboptimal code.
- Many upstream buildscripts for Node/Electron export symbols overzealously due to being tested only on Windows which does not have symbol visibility. Add -fvisibility=hidden to fix this. This won't break Node's required exports which correctly tag their visibility.
If all C/C++ code is built by %electron_rebuild
macro, these flags will be injected automatically. You need to add them manually otherwise.
Asar
Avoid.
Specific technologies
yarn
The %electron_rebuild
macro executes npm. It is not possible to use yarn to execute build scripts.
If your build scripts check for yarn, you need to patch them out (example from vscode) or fool them in other ways.
Rust
In general, Rust modules use only stable APIs and do not need the electron headers to build. General Rust guidelines can apply to them (modified appropriately for loadable plug-ins)
Rust does not have the equivalent of gcc's global -fvisibility=hidden; you should check for useless exports and patch them if possible.
Mixed Rust/C++ codebases need individual attention due to needing to work around rustc's numerous FFI bugs.
esbuild
@electron/fuses
electron-builder
Removed features
These features are available in upstream Electron builds but openSUSE currently does not build them due to being unused:
- PPAPI
- Printing
- WebExtensions
- WebGPU
Known bugs
app.isPackaged
Returns false
all the time. Patches are welcome.
process.execPath
This API is broken by design. Every its use must be patched out, otherwise the “About Electron” dialog will open instead of your app. Example from vscode.
app.relaunch
This API is broken by design for the same reason as the previous one (and with the same symptoms). Provide a suitable wrapper script as an additional parameter, example from vscode