diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-05-04 21:50:32 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-05-16 00:55:03 +0200 |
commit | efc32118b6b079462255890a7cb7c2e09ae9d473 (patch) | |
tree | 7bf13f27316c5db78fc6ea38e9a550f9a97452e4 | |
parent | build: integration testing support (diff) | |
download | sophie-efc32118b6b079462255890a7cb7c2e09ae9d473.tar.gz sophie-efc32118b6b079462255890a7cb7c2e09ae9d473.tar.zst sophie-efc32118b6b079462255890a7cb7c2e09ae9d473.zip |
feat: use wayland when available
Auto-detect wayland in the yarn watch script.
We use a shell script wrapper to launch sophie with wayland-specific
arguments whenever appropriate. Because of this, the electron binary
that ships with sophie has been renamed to sophie-bin.
Signed-off-by: Kristóf Marussy <kristof@marussy.com>
-rw-r--r-- | .electron-builder.config.cjs | 98 | ||||
-rw-r--r-- | build-helpers/detect_wayland.sh | 16 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | scripts/watch.js | 26 |
4 files changed, 114 insertions, 28 deletions
diff --git a/.electron-builder.config.cjs b/.electron-builder.config.cjs index efd9ef7..3eef91c 100644 --- a/.electron-builder.config.cjs +++ b/.electron-builder.config.cjs | |||
@@ -1,29 +1,8 @@ | |||
1 | const { readFile, rename, writeFile } = require('node:fs/promises'); | ||
2 | const path = require('node:path'); | ||
3 | |||
1 | const { Arch } = require('electron-builder'); | 4 | const { Arch } = require('electron-builder'); |
2 | const { flipFuses, FuseV1Options, FuseVersion } = require('@electron/fuses'); | 5 | const { flipFuses, FuseV1Options, FuseVersion } = require('@electron/fuses'); |
3 | const { join } = require('path'); | ||
4 | |||
5 | /** | ||
6 | * @type {import('electron-builder').Configuration} | ||
7 | * @see https://www.electron.build/configuration/configuration | ||
8 | */ | ||
9 | const config = { | ||
10 | directories: { | ||
11 | output: 'dist', | ||
12 | buildResources: 'buildResources', | ||
13 | }, | ||
14 | files: [ | ||
15 | 'packages/main/dist/**', | ||
16 | 'packages/preload/dist/**', | ||
17 | 'packages/renderer/dist/**', | ||
18 | 'packages/service-preload/dist/**', | ||
19 | 'locales/**', | ||
20 | // Do not ship with source maps. | ||
21 | '!**/*.map', | ||
22 | ], | ||
23 | afterPack(context) { | ||
24 | return burnFuses(context); | ||
25 | }, | ||
26 | }; | ||
27 | 6 | ||
28 | /** | 7 | /** |
29 | * Hardens the shipped electron binary by burning some electron fuses. | 8 | * Hardens the shipped electron binary by burning some electron fuses. |
@@ -46,7 +25,7 @@ async function burnFuses(context) { | |||
46 | darwin: '.app', | 25 | darwin: '.app', |
47 | win32: '.exe', | 26 | win32: '.exe', |
48 | }[context.electronPlatformName] || ''; | 27 | }[context.electronPlatformName] || ''; |
49 | const electronBinaryPath = join( | 28 | const electronBinaryPath = path.join( |
50 | context.appOutDir, | 29 | context.appOutDir, |
51 | `${context.packager.appInfo.productFilename}${ext}`, | 30 | `${context.packager.appInfo.productFilename}${ext}`, |
52 | ); | 31 | ); |
@@ -66,4 +45,73 @@ async function burnFuses(context) { | |||
66 | return flipFuses(electronBinaryPath, fuseConfig); | 45 | return flipFuses(electronBinaryPath, fuseConfig); |
67 | } | 46 | } |
68 | 47 | ||
48 | /** | ||
49 | * Adds a wrapper scripts that detects in wayland is in use and enabled it in chromium. | ||
50 | * | ||
51 | * The script in `build-heleprs/detect_wayland.sh` uses the `WAYLAND_DISPLAY` environmental | ||
52 | * variable to detect whether wayland is in use. | ||
53 | * | ||
54 | * If wayland is in use, the script enables the wayland ozone backed for chromium | ||
55 | * and pipewire screen sharing. Otherwise, the x11 ozone backend will be used. | ||
56 | * | ||
57 | * @param {import('electron-builder').AfterPackContext} context The `electron-builder` context. | ||
58 | * @return {Promise<void>} The promise to add the wrapper script. | ||
59 | * @see https://stackoverflow.com/a/45537237 | ||
60 | */ | ||
61 | async function enableWaylandAutoDetection(context) { | ||
62 | const { appOutDir, packager: { appInfo: { productName, productFilename } } } = context; | ||
63 | const electronBinaryPath = path.join(appOutDir, productFilename); | ||
64 | const newFilename = `${productFilename}-bin`; | ||
65 | const newElectronBinaryPath = path.join(appOutDir, newFilename); | ||
66 | await rename(electronBinaryPath, newElectronBinaryPath); | ||
67 | const wrapperScriptPath = path.join(__dirname, 'build-helpers/detect_wayland.sh'); | ||
68 | const wrapperScriptTempate = await readFile(wrapperScriptPath, 'utf8'); | ||
69 | const replacements = new Map([ | ||
70 | ['PRODUCT_NAME', productName], | ||
71 | ['REAL_BINARY_NAME', newFilename], | ||
72 | ]); | ||
73 | const wrapperScript = wrapperScriptTempate.replaceAll( | ||
74 | /\{\{([^}]+)\}\}/g, | ||
75 | (_match, /** @type {string} */ variable) => { | ||
76 | const replacement = replacements.get(variable); | ||
77 | if (replacement === undefined) { | ||
78 | throw new Error(`Unknown variable: ${variable}`); | ||
79 | } | ||
80 | return replacement; | ||
81 | }, | ||
82 | ); | ||
83 | await writeFile(electronBinaryPath, wrapperScript, { | ||
84 | encoding: 'utf8', | ||
85 | mode: 0o755, | ||
86 | }); | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * @type {import('electron-builder').Configuration} | ||
91 | * @see https://www.electron.build/configuration/configuration | ||
92 | */ | ||
93 | const config = { | ||
94 | directories: { | ||
95 | output: 'dist', | ||
96 | buildResources: 'buildResources', | ||
97 | }, | ||
98 | files: [ | ||
99 | 'packages/main/dist/**', | ||
100 | 'packages/preload/dist/**', | ||
101 | 'packages/renderer/dist/**', | ||
102 | 'packages/service-preload/dist/**', | ||
103 | 'locales/**', | ||
104 | // Do not ship with source maps. | ||
105 | '!**/*.map', | ||
106 | ], | ||
107 | afterPack(context) { | ||
108 | return burnFuses(context); | ||
109 | }, | ||
110 | async afterSign(context) { | ||
111 | if (context.electronPlatformName === 'linux') { | ||
112 | await enableWaylandAutoDetection(context); | ||
113 | } | ||
114 | } | ||
115 | }; | ||
116 | |||
69 | module.exports = config; | 117 | module.exports = config; |
diff --git a/build-helpers/detect_wayland.sh b/build-helpers/detect_wayland.sh new file mode 100644 index 0000000..e82a383 --- /dev/null +++ b/build-helpers/detect_wayland.sh | |||
@@ -0,0 +1,16 @@ | |||
1 | #!/usr/bin/env sh | ||
2 | if [ ! -L "$0" ]; then | ||
3 | electron_dir="$(dirname "$0")" | ||
4 | else | ||
5 | if command -v readlink >/dev/null; then | ||
6 | electron_dir="$(dirname "$(readlink -f "$0")")" | ||
7 | else | ||
8 | electron_dir="/opt/{{PRODUCT_NAME}}" | ||
9 | fi | ||
10 | fi | ||
11 | electron_path="${electron_dir}/{{REAL_BINARY_NAME}}" | ||
12 | if [ -n "${WAYLAND_DISPLAY+1}" ]; then | ||
13 | exec "${electron_path}" --enable-features=WaylandWindowDecorations,WebRTCPipeWireCapturer --ozone-platform=wayland "$@" | ||
14 | else | ||
15 | exec "${electron_path}" --ozone-platform=x11 "$@" | ||
16 | fi | ||
diff --git a/package.json b/package.json index 2e60130..9c864cc 100644 --- a/package.json +++ b/package.json | |||
@@ -23,7 +23,7 @@ | |||
23 | "test": "node --experimental-vm-modules --no-warnings $(yarn bin jest)", | 23 | "test": "node --experimental-vm-modules --no-warnings $(yarn bin jest)", |
24 | "test:ci": "yarn test --ci --coverage --reporters=default --reporters=jest-junit", | 24 | "test:ci": "yarn test --ci --coverage --reporters=default --reporters=jest-junit", |
25 | "test:integ": "electron scripts/electronJest.cjs --user-data-dir=userDataDir/integ --config=jest.integ.config.cjs --runInBand", | 25 | "test:integ": "electron scripts/electronJest.cjs --user-data-dir=userDataDir/integ --config=jest.integ.config.cjs --runInBand", |
26 | "test:integ:xvfb": "cross-env DISABLE_GPU=true xvfb-run -s \"-screen 0 1920x1080x24\" electron scripts/electronJest.cjs --user-data-dir=userDataDir/integ --config=jest.integ.config.cjs --runInBand", | 26 | "test:integ:xvfb": "cross-env DISABLE_GPU=true xvfb-run -s \"-screen 0 1920x1080x24\" electron scripts/electronJest.cjs --user-data-dir=userDataDir/integ --disable-features=WebRTCPipeWireCapturer --ozone-platform=x11 --config=jest.integ.config.cjs --runInBand", |
27 | "test:integ:ci": "cross-env DISABLE_GPU=true yarn test:integ --ci --coverage --reporters=default --reporters=jest-junit", | 27 | "test:integ:ci": "cross-env DISABLE_GPU=true yarn test:integ --ci --coverage --reporters=default --reporters=jest-junit", |
28 | "test:integ:xvfb:ci": "yarn test:integ:xvfb --ci --coverage --reporters=default --reporters=jest-junit", | 28 | "test:integ:xvfb:ci": "yarn test:integ:xvfb --ci --coverage --reporters=default --reporters=jest-junit", |
29 | "build": "node scripts/build.js", | 29 | "build": "node scripts/build.js", |
diff --git a/scripts/watch.js b/scripts/watch.js index eeee6e4..5db0d30 100644 --- a/scripts/watch.js +++ b/scripts/watch.js | |||
@@ -1,4 +1,5 @@ | |||
1 | import { spawn } from 'node:child_process'; | 1 | import { spawn } from 'node:child_process'; |
2 | import os from 'node:os'; | ||
2 | import path from 'node:path'; | 3 | import path from 'node:path'; |
3 | 4 | ||
4 | import { watch } from 'chokidar'; | 5 | import { watch } from 'chokidar'; |
@@ -31,7 +32,7 @@ const userDataDir = path.join(thisDir, '../userDataDir/development'); | |||
31 | 32 | ||
32 | /** @type {RegExp[]} */ | 33 | /** @type {RegExp[]} */ |
33 | const stderrIgnorePatterns = [ | 34 | const stderrIgnorePatterns = [ |
34 | // warning about devtools extension | 35 | // Warning about devtools extension |
35 | // https://github.com/cawa-93/vite-electron-builder/issues/492 | 36 | // https://github.com/cawa-93/vite-electron-builder/issues/492 |
36 | // https://github.com/MarshallOfSound/electron-devtools-installer/issues/143 | 37 | // https://github.com/MarshallOfSound/electron-devtools-installer/issues/143 |
37 | /ExtensionLoadWarning/, | 38 | /ExtensionLoadWarning/, |
@@ -44,6 +45,8 @@ const stderrIgnorePatterns = [ | |||
44 | // Does not seem to occur in production | 45 | // Does not seem to occur in production |
45 | // https://github.com/electron/electron/issues/32133#issuecomment-1079916988 | 46 | // https://github.com/electron/electron/issues/32133#issuecomment-1079916988 |
46 | /(sandbox_bundle\.js script failed to run|object null is not iterable).+ node:electron\/js2c\/sandbox_bundle \(160\)$/, | 47 | /(sandbox_bundle\.js script failed to run|object null is not iterable).+ node:electron\/js2c\/sandbox_bundle \(160\)$/, |
48 | // Warning when GPU-accelerated video decoding is not available (some wayland configs) | ||
49 | /Passthrough is not supported, GL is/, | ||
47 | ]; | 50 | ]; |
48 | 51 | ||
49 | /** | 52 | /** |
@@ -134,6 +137,20 @@ function setupMainPackageWatcher(viteDevServer) { | |||
134 | const portOrDefault = port || 3000; | 137 | const portOrDefault = port || 3000; |
135 | process.env.VITE_DEV_SERVER_URL = `${protocol}//${hostOrDefault}:${portOrDefault}/`; | 138 | process.env.VITE_DEV_SERVER_URL = `${protocol}//${hostOrDefault}:${portOrDefault}/`; |
136 | 139 | ||
140 | /** @type {string[]} */ | ||
141 | let extraArgs = []; | ||
142 | |||
143 | if (['aix', 'freebsd', 'linux', 'openbsd', 'sunos'].includes(os.platform())) { | ||
144 | // Use wayland display server if available. | ||
145 | extraArgs = | ||
146 | 'WAYLAND_DISPLAY' in process.env | ||
147 | ? [ | ||
148 | '--enable-features=WaylandWindowDecorations,WebRTCPipeWireCapturer', | ||
149 | '--ozone-platform=wayland', | ||
150 | ] | ||
151 | : ['--ozone-platform=x11']; | ||
152 | } | ||
153 | |||
137 | /** @type {import('child_process').ChildProcessByStdio<null, null, import('stream').Readable> | 154 | /** @type {import('child_process').ChildProcessByStdio<null, null, import('stream').Readable> |
138 | | undefined} */ | 155 | | undefined} */ |
139 | let childProcess; | 156 | let childProcess; |
@@ -144,7 +161,12 @@ function setupMainPackageWatcher(viteDevServer) { | |||
144 | function spawnProcess() { | 161 | function spawnProcess() { |
145 | childProcess = spawn( | 162 | childProcess = spawn( |
146 | String(electronPath), | 163 | String(electronPath), |
147 | ['.', `--user-data-dir=${userDataDir}`, ...process.argv.slice(2)], | 164 | [ |
165 | '.', | ||
166 | `--user-data-dir=${userDataDir}`, | ||
167 | ...extraArgs, | ||
168 | ...process.argv.slice(2), | ||
169 | ], | ||
148 | { | 170 | { |
149 | stdio: ['inherit', 'inherit', 'pipe'], | 171 | stdio: ['inherit', 'inherit', 'pipe'], |
150 | }, | 172 | }, |