openSUSE:Packaging Electron

Jump to: navigation, search

THIS IS AN UNFINISHED DRAFT


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
  • PDF
  • 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

ELECTRON_RUN_AS_NODE