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