fix(aionui): Use production-only deps for runtime, hoist transitive deps
Some checks failed
CI / check (push) Has been cancelled

Replace full node_modules copy with production-only FOD (mirrors
the upstream Dockerfile pattern), reducing package output from
~6.9 GB to ~1.3 GB.

Hoist @sentry/node to top-level node_modules so Electron's
require() resolution can find it. Bun nests transitive deps
inside .bun/ but Electron resolves from the realpath, requiring
the dependency to be accessible from the walked-up directory
chain.
This commit is contained in:
2026-05-27 14:35:57 +03:00
parent 02947027ba
commit 7f0cec1a35

View File

@@ -24,25 +24,19 @@ let
hash = "sha256-A7dKGEuo5n+M7D9fJR3TN95q1P7En/ulsTO+ev6SAUY="; hash = "sha256-A7dKGEuo5n+M7D9fJR3TN95q1P7En/ulsTO+ev6SAUY=";
}; };
# Fixed-output derivation: fetch all pure-JS dependencies via bun. # FOD 1: All dependencies (dev + prod) for the build phase.
# We skip install scripts because they use #!/usr/bin/env shebangs bunBuildDeps = stdenv.mkDerivation {
# that don't exist in the Nix sandbox. Native addons are built name = "aionui-build-deps-${version}";
# separately in the main derivation.
bunDeps = stdenv.mkDerivation {
name = "aionui-bun-deps-${version}";
inherit src; inherit src;
nativeBuildInputs = [ nativeBuildInputs = [
bun bun
cacert cacert
]; ];
outputHashAlgo = "sha256"; outputHashAlgo = "sha256";
outputHashMode = "recursive"; outputHashMode = "recursive";
outputHash = "sha256-Fuj55vxDgpx5A4iwnU/5IZKPfaYMH3DeZ1yauuZHn8g="; outputHash = "sha256-Fuj55vxDgpx5A4iwnU/5IZKPfaYMH3DeZ1yauuZHn8g=";
dontPatchShebangs = true; dontPatchShebangs = true;
dontFixup = true; dontFixup = true;
SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt"; SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
buildPhase = '' buildPhase = ''
@@ -54,10 +48,36 @@ let
mkdir -p $out mkdir -p $out
cp -r node_modules $out/ cp -r node_modules $out/
cp -r packages $out/ cp -r packages $out/
# Workspace packages reference root configs with relative paths
cp tsconfig.json $out/ cp tsconfig.json $out/
''; '';
}; };
# FOD 2: Production-only dependencies for the runtime output.
# Mirrors the Dockerfile's `bun install --production --ignore-scripts`.
bunProdDeps = stdenv.mkDerivation {
name = "aionui-prod-deps-${version}";
inherit src;
nativeBuildInputs = [
bun
cacert
];
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "sha256-eCQ9ObhttZ10CehRRvl4IaOKkdK9m1TQJuhLmhiMkBY=";
dontPatchShebangs = true;
dontFixup = true;
SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
buildPhase = ''
export HOME=$TMPDIR
bun install --frozen-lockfile --production --ignore-scripts
'';
installPhase = ''
mkdir -p $out
cp -r node_modules $out/
'';
};
in in
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
@@ -84,11 +104,10 @@ stdenv.mkDerivation rec {
export HOME=$TMPDIR export HOME=$TMPDIR
# Use the pre-fetched node_modules from the FOD (symlink farm) # Use the full dependency set for the build
ln -sf ${bunDeps}/node_modules . ln -sf ${bunBuildDeps}/node_modules .
# Build better-sqlite3 native addon # Build better-sqlite3 native addon
# The FOD output is read-only; build in a temp dir.
echo "Building better-sqlite3 from source..." echo "Building better-sqlite3 from source..."
BT3_SRC=$TMPDIR/bts3-src BT3_SRC=$TMPDIR/bts3-src
BT3_OUT=$TMPDIR/bts3-out BT3_OUT=$TMPDIR/bts3-out
@@ -103,23 +122,6 @@ stdenv.mkDerivation rec {
cp build/Release/better_sqlite3.node "$BT3_OUT/build/Release/" 2>/dev/null || true cp build/Release/better_sqlite3.node "$BT3_OUT/build/Release/" 2>/dev/null || true
) )
# Build sharp native addon
echo "Building sharp from source..."
SHARP_SRC=$TMPDIR/sharp-src
SHARP_OUT=$TMPDIR/sharp-out
mkdir -p "$SHARP_SRC" "$SHARP_OUT"
cp -rL node_modules/sharp/* "$SHARP_SRC/" 2>/dev/null || true
if [ -f "$SHARP_SRC/package.json" ]; then
chmod -R u+w "$SHARP_SRC"
(
cd "$SHARP_SRC"
export npm_config_nodedir=${nodejs}
node-gyp rebuild 2>/dev/null || echo " sharp: build skipped (needs libvips)"
mkdir -p "$SHARP_OUT/build/Release"
cp build/Release/sharp.node "$SHARP_OUT/build/Release/" 2>/dev/null || true
)
fi
# electron-vite build # electron-vite build
echo "Running electron-vite build..." echo "Running electron-vite build..."
${nodejs}/bin/node node_modules/.bin/electron-vite build \ ${nodejs}/bin/node node_modules/.bin/electron-vite build \
@@ -142,34 +144,36 @@ stdenv.mkDerivation rec {
cp -r public $out/lib/aionui/ cp -r public $out/lib/aionui/
cp package.json $out/lib/aionui/ cp package.json $out/lib/aionui/
# Runtime dependencies # Production-only node_modules (mirrors Dockerfile)
# Copy node_modules (from the symlink) the compiled output cp -a ${bunProdDeps}/node_modules $out/lib/aionui/node_modules
# has externalized require() calls for every dependency. chmod -R u+w $out/lib/aionui/node_modules
cp -rL node_modules $out/lib/aionui/
# Remove prebuilt musl (Alpine) binaries from sharp they # Remove workspace symlink @aionui/web-host is bundled by
# are incompatible with glibc and we built from source anyway. # electron-vite (excluded from externalizeDepsPlugin), so the
find $out/lib/aionui/node_modules -path "*/sharp-linuxmusl*" -type d -exec rm -rf {} + 2>/dev/null || true # symlink to packages/web-host is not needed at runtime.
find $out/lib/aionui/node_modules -path "*/sharp-libvips-linuxmusl*" -type d -exec rm -rf {} + 2>/dev/null || true rm -f $out/lib/aionui/node_modules/@aionui/web-host
# Inject compiled native addons # @sentry/electron requires @sentry/node at runtime, but bun
# cp -rL from the FOD preserves read-only permissions. # nests it inside .bun/ rather than hoisting to top-level.
# Make native addon dirs writable before overlaying binaries. # Electron's require() walks up from the resolved realpath
chmod -R u+w $out/lib/aionui/node_modules/better-sqlite3 2>/dev/null || true # and needs it accessible either at top-level or via the
chmod -R u+w $out/lib/aionui/node_modules/sharp 2>/dev/null || true # symlink target's node_modules. We ensure top-level access.
if [ ! -e $out/lib/aionui/node_modules/@sentry/node ]; then
BT3_OUT=$TMPDIR/bts3-out SRC=$(echo $out/lib/aionui/node_modules/.bun/@sentry+node@*/node_modules/@sentry/node)
if [ -f "$BT3_OUT/build/Release/better_sqlite3.node" ]; then if [ -d "$SRC" ]; then
mkdir -p $out/lib/aionui/node_modules/better-sqlite3/build/Release ln -sf "$(realpath --relative-to=$out/lib/aionui/node_modules/@sentry "$SRC")" \
cp "$BT3_OUT/build/Release/better_sqlite3.node" \ $out/lib/aionui/node_modules/@sentry/node
$out/lib/aionui/node_modules/better-sqlite3/build/Release/ fi
fi fi
SHARP_OUT=$TMPDIR/sharp-out # Inject compiled better-sqlite3 .node into the runtime tree
if [ -f "$SHARP_OUT/build/Release/sharp.node" ]; then if [ -f "$TMPDIR/bts3-out/build/Release/better_sqlite3.node" ]; then
mkdir -p $out/lib/aionui/node_modules/sharp/build/Release rm -rf $out/lib/aionui/node_modules/better-sqlite3
cp "$SHARP_OUT/build/Release/sharp.node" \ cp -rL ${bunProdDeps}/node_modules/better-sqlite3 $out/lib/aionui/node_modules/better-sqlite3 2>/dev/null || true
$out/lib/aionui/node_modules/sharp/build/Release/ chmod -R u+w $out/lib/aionui/node_modules/better-sqlite3
mkdir -p $out/lib/aionui/node_modules/better-sqlite3/build/Release
cp "$TMPDIR/bts3-out/build/Release/better_sqlite3.node" \
$out/lib/aionui/node_modules/better-sqlite3/build/Release/
fi fi
# Desktop entry # Desktop entry