readest/apps/readest-app/scripts/tauri.mjs
Huang Xin 655c72ad5a
feat(linux): ship Readest on the tauri CEF runtime (#6074)
* feat(linux): build and ship Readest on the tauri CEF runtime

Linux now builds against upstream tauri `feat/cef` (git) and the plugins on
plugins-workspace `feat/cef`, while macOS/Windows/mobile keep the readest
fork untouched:

- `pnpm tauri:cef dev|build` (scripts/tauri-cef.mjs) runs @tauri-apps/cli-cef
  with `--features cef`, cargo `--no-default-features` and the Linux-only
  `[patch.crates-io]` in src-tauri/.cargo/cef.toml, swapping the committed
  Cargo.cef.lock in for the run so Cargo.lock stays in the fork state.
- The fork crates are no longer workspace members (a member clashes on
  `links` with the git copy); the tauri-plugins fork carried no changes and
  is removed, tauri-plugin-fs comes from crates.io at 2.5.1.
- App: `cef = ["tauri/cef"]` (the fork gets a no-op stub), explicit runtime
  type, `cef_entry_point`, `--no-first-run` for CEF, commands generic over
  the runtime, xdg-portal dialogs on Linux (rfd's GTK thread crashes CEF),
  rangefile reads and pointer-driven move/resize on the Linux CEF runtime,
  Chromium reported in the About dialog, deb/rpm depend on libwebkit2gtk
  while plugins still pull the wry runtime.
- Build-generated permission files are untracked; turso registers `batch`.
- CI Linux legs use `pnpm tauri:cef`.

Submodules: packages/tauri -> feat/cef-feature-stub, tauri-plugin-turso ->
fix/register-batch-command (both need pushing).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* feat(linux): let the CEF wrapper run an unpacked tauri CLI for offline builds

Flatpak builds have no network, so `TAURI_CEF_CLI` points scripts/tauri-cef.mjs
at an unpacked copy of @tauri-apps/cli-cef instead of `pnpm dlx`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore(linux): take the CEF stack from the readest forks

- src-tauri/.cargo/cef.toml: tauri and the plugins now come from the readest
  forks' feat/cef branches (upstream feat/cef plus the DevTools-close fix in
  tauri-runtime-cef); Cargo.cef.lock re-resolved against them.
- tauri-plugin-turso: point at main, which merged the batch command fix.
- CI: STRACE_MODE=0 for the Linux legs so the CEF AppImage bundler
  (quick-sharun) does not launch the app under Xvfb and hang (#4906).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* feat(linux): make the CEF runtime the default tauri build on Linux

`pnpm tauri` now goes through scripts/tauri.mjs (the former tauri-cef.mjs):
on Linux its dev, build and bundle commands run the feat/cef tauri CLI
with the CEF feature, cargo config and Cargo.cef.lock swap, and every
other platform or command passes straight through to @tauri-apps/cli.
The separate `tauri:cef` script goes away, so the release and nightly
workflows, the local Linux build script and the docs use plain
`pnpm tauri build` again.

The tauri webdriver harness (scripts/test-tauri.sh) still calls the
`tauri` binary directly and keeps the wry runtime on Linux, since
tauri-driver needs WebKitWebDriver.

Cargo.cef.lock picks up the quick-xml 0.41 bump from main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore(nix): refresh cargoHash for the reshaped Cargo.lock

Dropping the packages/tauri-plugins submodule and the tauri-plugin-fs
path patch changed the vendored cargo dependency set, so the Nix
fixed-output hash moves to the value the nix-deps-check job reported.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(linux): harden the CEF wrapper and pointer window drag

Review follow-ups on the CEF runtime work:

- scripts/tauri.mjs parks the wry Cargo.lock in Cargo.lock.wry, created
  exclusively, so two CEF commands in one checkout cannot swap lockfiles
  over each other, and a killed run leaves an obvious file to move back.
- The CEF runtime alias, entry point and runtime attributes are gated on
  Linux as well as the `cef` feature; elsewhere the feature is a no-op.
- Pointer-driven window move/resize applies the last pointer delta when
  the button is released before the pending animation frame, and does
  not start tracking when the button was already released while the
  window state was being read.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 20:09:06 +02:00

113 lines
4.4 KiB
JavaScript
Executable file

#!/usr/bin/env node
// `pnpm tauri <command> [tauri args] [-- cargo args]`.
//
// Every platform but Linux goes straight to the npm @tauri-apps/cli, which
// builds on the readest tauri fork (the wry runtime). On Linux the desktop
// commands (dev, build, bundle) run on the CEF runtime instead: this uses the
// tauri CLI published from upstream's `feat/cef` branch and adds what the CEF
// build needs on top of the normal tauri command line:
// - `--features cef` so the CLI bundles the CEF distribution and cargo
// compiles the CEF runtime (`cef = ["tauri/cef"]` in src-tauri/Cargo.toml);
// - `--no-default-features` (cargo side) to drop the `wry` runtime, see
// src-tauri/Cargo.toml;
// - `--config src-tauri/.cargo/cef.toml` (cargo side) to take tauri and the
// plugins from the `feat/cef` branches instead of the readest fork.
//
// Cargo resolves that graph differently from the fork graph every other
// platform builds, and it can only write one Cargo.lock. So for the duration
// of the command the repo's Cargo.cef.lock is swapped in as Cargo.lock and the
// original is put back afterwards; the CEF resolution is saved back to
// Cargo.cef.lock, which is committed like Cargo.lock. The original is parked
// in Cargo.lock.wry meanwhile, created exclusively so two CEF commands in one
// checkout cannot swap over each other; if a run is killed hard (SIGKILL)
// before the swap back, `mv Cargo.lock.wry Cargo.lock` restores it.
//
// Mobile commands (`tauri android ...`, `tauri ios ...`) and the tauri
// webdriver test harness (scripts/test-tauri.sh, which needs WebKitWebDriver)
// keep the wry runtime on Linux too.
import { spawn } from 'node:child_process';
import fs from 'node:fs';
import { createRequire } from 'node:module';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const CEF_CLI = '@tauri-apps/cli-cef@3.0.0-alpha.26';
// Offline builds (Flatpak) cannot `pnpm dlx`; they point this at an unpacked
// copy of the CLI package's `tauri.js` instead.
const localCefCli = process.env['TAURI_CEF_CLI'];
const appDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const repoRoot = path.resolve(appDir, '../..');
const cargoConfig = path.join(appDir, 'src-tauri/.cargo/cef.toml');
const lockPath = path.join(repoRoot, 'Cargo.lock');
const cefLockPath = path.join(repoRoot, 'Cargo.cef.lock');
const savedLockPath = path.join(repoRoot, 'Cargo.lock.wry');
const [command, ...rest] = process.argv.slice(2);
const useCef = process.platform === 'linux' && ['dev', 'build', 'bundle'].includes(command);
const run = (file, args, cleanup = () => {}) => {
const child = spawn(file, args, { stdio: 'inherit' });
child.on('exit', (code, signal) => {
cleanup();
process.exit(code ?? (signal ? 1 : 0));
});
child.on('error', (error) => {
cleanup();
console.error(error);
process.exit(1);
});
};
if (!useCef) {
const tauriCli = createRequire(import.meta.url).resolve('@tauri-apps/cli/tauri.js');
run('node', [tauriCli, ...process.argv.slice(2)]);
} else {
const split = rest.indexOf('--');
const tauriArgs = split === -1 ? rest : rest.slice(0, split);
const cargoArgs = split === -1 ? [] : rest.slice(split + 1);
const args = [
command,
'--features',
'cef',
...tauriArgs,
'--',
'--no-default-features',
'--config',
cargoConfig,
...cargoArgs,
];
try {
fs.writeFileSync(savedLockPath, fs.readFileSync(lockPath), { flag: 'wx' });
} catch (error) {
if (error.code !== 'EEXIST') throw error;
console.error(
`${savedLockPath} exists: another CEF build is running from this checkout, or an earlier ` +
'one was killed before it could restore Cargo.lock. Wait for it to finish, or run ' +
'`mv Cargo.lock.wry Cargo.lock`.',
);
process.exit(1);
}
if (fs.existsSync(cefLockPath)) {
fs.copyFileSync(cefLockPath, lockPath);
}
let swapped = true;
const restoreLock = () => {
if (!swapped) return;
fs.copyFileSync(lockPath, cefLockPath);
fs.renameSync(savedLockPath, lockPath);
swapped = false;
};
// Ctrl-C reaches the child through the process group; stay alive until it
// has exited so the lock swap is undone.
for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
process.on(signal, () => {});
}
if (localCefCli) {
run('node', [localCefCli, ...args], restoreLock);
} else {
run('pnpm', ['dlx', CEF_CLI, ...args], restoreLock);
}
}