Electron

由于Electron的性质,与其他应用相比,将Electron应用构建为Flatpak应用需要一些额外的步骤。值得庆幸的是,有几种工具和资源可以使这些步骤更容易。

本教程提供有关如何构建Electron应用程序与其他应用程序不同的信息。 它还包括有关构建Electron应用程序的工具以及如何使用它的信息。

The guide walks through the manifest file of the sample Electron Flatpak application. Before you start, it is a good idea to take a look at this, either online or by downloading the application.

构建示例应用程序

虽然并非绝对必要,但最好自己尝试构建和运行示例应用程序。

To get setup for the build, download or clone the sample app from GitHub, and navigate to the /flatpak directory in the terminal. You must also install the Electron base app and the Node.js SDK extension:

$ flatpak install flathub org.electronjs.Electron2.BaseApp//23.08
$ flatpak install flathub org.freedesktop.Sdk.Extension.node18//23.08

然后运行构建命令:

$ flatpak-builder build org.flathub.electron-sample-app.yml --install --force-clean --user

最后,运行应用:

$ flatpak run org.flathub.electron-sample-app

基本配置

示例应用清单文件的第一部分指定了应用ID、runtime和SDK:

id: org.flathub.electron-sample-app
runtime: org.freedesktop.Platform
runtime-version: '23.08'
sdk: org.freedesktop.Sdk

Freedesktop运行时通常是与Electron应用程序一起使用的最佳运行时,因为它是最小的运行时,其他依赖项将特定于Electron本身。

Electron base应用

Next, the manifest specifies that the Electron base app should be used, by specifying the base and base-version properties in the application manifest:

base: org.electronjs.Electron2.BaseApp
base-version: '23.08'

Base apps are described in 依赖. Using the Electron base app is much faster and more convenient than manually building Electron dependencies. It also has the advantage of reducing the amount of duplication on users’ machines, since it means that Electron is only saved once on disk.

The Node.js SDK extension

In order to build Electron-based apps, you need Node.js available at build time. Flathub provides Node.js LTS versions as extensions for the SDK, so you can install one of them and add it in your apps’ manifest:

sdk-extensions:
  - org.freedesktop.Sdk.Extension.node18

Enable the extension by adding it to PATH:

build-options:
  append-path: /usr/lib/sdk/node18/bin

Note that the extension name (last portion of reverse-dns notation, node18 in this example) must be the same in sdk-extensions and append-path.

命令

这个 command 表明执行一个名为 run.sh 的脚本用来运行这个应用。这会在后续详细介绍。

command: run.sh

沙箱权限

The standard guidelines on sandbox permissions apply to Electron applications. However, Electron does not use Wayland by default. So for display access, only X11 should be used as the default configuration. This will make Electron use Xwayland in a wayland session and nothing else is required.

The sample app also configures pulseaudio for sound and enables network access.

finish-args:
  - --share=ipc
  - --socket=x11
  - --socket=pulseaudio
  - --share=network

备注

Native wayland support in electron is experimental and often unstable. It is advised to stick with the X11 and Xwayland configuration above as the default.

To enable experimental native Wayland support in Electron>=20, the --ozone-platform-hint=auto flag can be passed to the program. auto will choose Wayland when the seesion is wayland and Xwayland or X11 otherwise.

The recommended option is to leave it to the user. So --socket=x11 should be used in manifest and Wayland can be tested with:

flatpak run --socket=wayland org.flathub.electron-sample-app

To make native wayland the default for users --socket=fallback-x11 and --socket=wayland must be used in the manifest.

Client-side window decorations in native wayland can be enabled by passing --enable-features=WaylandWindowDecorations (Electron>=17).

Electron uses libnotify on Linux to provide desktop notifications. libnotify since 0.8.0 automatically uses the notification portal when inside a sandboxed environment and --talk-name=org.freedesktop.Notifications is not required.

org.electronjs.Electron2.BaseApp since branch/23.08 comes with libnotify>=0.8.0

构建选项

构建选项不是必要的,但是在发生一些错误的时候很有用。 env 允许设置一个环境变量数组,这时将 NPM_CONFIG_LOGLEVEL 设置为 info 可以让 npm 给我们更多关于错误的详情。

build-options:
  cflags: -O2 -g
  cxxflags: -O2 -g
  env:
    NPM_CONFIG_LOGLEVEL: info

应用模块

清单文件的最后一部分是定义应用模块如何构建。可以找到一些Electron和Node.js的一些附加逻辑。

flatpak-builder 默认不能访问网络。这意味着依赖于下载资源的工具无法工作。因此,Node.js包必须在构建之前提前下载好。设置环境变量 electron_config_cache 表明这些包会在构建的时候被找到。

清单文件的下一部分描述了怎样构建应用。使用了简单构建系统的选项,允许指定一系列命令来构建。下载地址和应用的hash也会进行指定。

name: electron-sample-app
buildsystem: simple
build-options:
  env:
    XDG_CACHE_HOME: /run/build/electron-sample-app/flatpak-node/cache
    npm_config_cache: /run/build/electron-sample-app/flatpak-node/npm-cache
    npm_config_nodedir: /usr/lib/sdk/node18
    npm_config_offline: 'true'
subdir: main
sources:
  - type: archive
    url: https://github.com/flathub/electron-sample-app/archive/1.0.1.tar.gz
    sha256: a2feb3f1cf002a2e4e8900f718cc5c54db4ad174e48bfcfbddcd588c7b716d5b
    dest: main

绑定NPM包

下一行是NPM模块如何作为flatpak的一部分进行绑定:

- generated-sources.json

Since even simple Node.js applications depend on dozens of packages, it would be impractical to specify all of them as part of a manifest file. A Python script has therefore been developed to download Node.js packages with NPM or Yarn and include them in an application’s sources.

The Python script requires a package-lock.json (or yarn.lock) file. This file contains information about the packages that an application depends on, and can be generated by running npm install --package-lock-only from an application’s root directory. The script is then run as follows:

$ flatpak-node-generator npm package-lock.json

This generates the manifest JSON needed to build the NPM/Yarn packages for the application, which are outputted to a file called generated-sources.json. The content of this file can be copied to the application’s manifest but, because it is often very long, it is often best to link to it from the main manifest, which is done by adding generated-source.json as a line in the manifest section, as seen above.

启动应用

The Electron app is run through a simple script. This can be given any name but must be specified in the manifest’s "command": property. See below a sample wrapper for launching app:

- type: script
  dest-filename: run.sh
  commands:
    - zypak-wrapper.sh /app/main/electron-sample-app "$@"

构建命令

Last but not least, since the simple build option is being used, a list of build commands must be provided. As can be seen, npm is run with the npm_config_offline=true environment variable, installing dependencies from packages that have already been cached. These are copied to /app/main/. Finally the run.sh script is installed to /app/bin/ so that it will be on $PATH:

build-commands:
  # Install npm dependencies
  - npm install --offline
  # Build the app; in this example the `dist` script
  # in package.json runs electron-builder
  - |
    . ../flatpak-node/electron-builder-arch-args.sh
    npm run dist -- $ELECTRON_BUILDER_ARCH_ARGS  --linux --dir
  # Bundle app and dependencies
  - cp -a dist/linux*unpacked /app/main
  # Install app wrapper
  - install -Dm755 -t /app/bin/ ../run.sh

Note that if the application you are trying to package contains a build block in package.json with instructions for Linux, this can cause electron-builder to try to fetch additional binaries at build-time (Even if –dir option is used). The following example shows a configuration that will try to download AppImage binaries:

"build": {
  "linux": {
    "target": "AppImage",
  }
}

The preferred way of fixing this, is not a patch, but a build-time edit using jq. The following command will replace "target": "AppImage" with "target": "dir":

jq '.build.linux.target="dir"' <<<$(<package.json) > package.json