diff --git a/flake.lock b/flake.lock index 07c8f8b86..b01674bec 100644 --- a/flake.lock +++ b/flake.lock @@ -18,6 +18,24 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1748437600, @@ -34,10 +52,32 @@ "type": "github" } }, + "pnpm2nix": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1748881470, + "narHash": "sha256-Uk4J9StEEH/JaJQ+cw7wVvgLPMLZNoOGDGxKSbSDXyc=", + "owner": "FliegendeWurst", + "repo": "pnpm2nix-nzbr", + "rev": "85497400540854c2895b9f59b5cc741a1f838da2", + "type": "github" + }, + "original": { + "owner": "FliegendeWurst", + "repo": "pnpm2nix-nzbr", + "type": "github" + } + }, "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "pnpm2nix": "pnpm2nix" } }, "systems": { @@ -54,6 +94,21 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 4ffa16168..19a366992 100644 --- a/flake.nix +++ b/flake.nix @@ -4,6 +4,10 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; flake-utils.url = "github:numtide/flake-utils"; + pnpm2nix = { + url = "github:FliegendeWurst/pnpm2nix-nzbr"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = @@ -11,69 +15,164 @@ self, nixpkgs, flake-utils, + pnpm2nix, }: flake-utils.lib.eachDefaultSystem ( system: let - packageJSON = builtins.fromJSON (builtins.readFile ./package.json); pkgs = import nixpkgs { inherit system; }; electron = pkgs.electron_35; + nodejs = pkgs.nodejs_22; + pnpm = pkgs.pnpm_10; inherit (pkgs) copyDesktopItems + darwin lib makeBinaryWrapper makeDesktopItem - nodejs - pnpm + removeReferencesTo stdenv wrapGAppsHook3 xcodebuild - darwin ; - desktop = stdenv.mkDerivation (finalAttrs: { - pname = "triliumnext-desktop"; - version = packageJSON.version; - src = lib.cleanSource ./.; - nativeBuildInputs = - [ - pnpm.configHook - nodejs - nodejs.python - copyDesktopItems - makeBinaryWrapper - wrapGAppsHook3 - ] - ++ lib.optionals stdenv.hostPlatform.isDarwin [ - xcodebuild - darwin.cctools + fullCleanSourceFilter = + name: type: + (lib.cleanSourceFilter name type) + || ( + let + baseName = baseNameOf (toString name); + in + # No need to copy the flake. + # Don't copy local development instance of NX cache. + baseName == "flake.nix" || baseName == "flake.lock" || baseName == ".nx" + ); + fullCleanSource = + src: + lib.cleanSourceWith { + filter = fullCleanSourceFilter; + src = src; + }; + packageJson = builtins.fromJSON (builtins.readFile ./package.json); + + makeApp = + { + app, + buildTask, + mainProgram, + installCommands, + preBuildCommands ? "", + }: + pnpm2nix.packages.${system}.mkPnpmPackage rec { + pname = "triliumnext-${app}"; + version = packageJson.version + (lib.optionalString (self ? shortRev) "-${self.shortRev}"); + + src = fullCleanSource ./.; + packageJSON = ./package.json; + pnpmLockYaml = ./pnpm-lock.yaml; + + workspace = fullCleanSource ./.; + pnpmWorkspaceYaml = ./pnpm-workspace.yaml; + + inherit nodejs pnpm; + + extraNodeModuleSources = [ + rec { + name = "patches"; + value = ./patches; + } ]; - dontWrapGApps = true; + postConfigure = + '' + chmod +x node_modules/.pnpm/electron@*/node_modules/electron/install.js + patchShebangs --build node_modules + '' + + lib.optionalString stdenv.hostPlatform.isLinux '' + patchelf --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ + node_modules/.pnpm/sass-embedded-linux-x64@*/node_modules/sass-embedded-linux-x64/dart-sass/src/dart + ''; - preBuild = lib.optionalString stdenv.hostPlatform.isLinux '' - patchelf --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ - node_modules/.pnpm/sass-embedded-linux-x64@*/node_modules/sass-embedded-linux-x64/dart-sass/src/dart - ''; + extraNativeBuildInputs = + [ + makeBinaryWrapper + nodejs.python + removeReferencesTo + ] + ++ lib.optionals (app == "desktop") [ + copyDesktopItems + wrapGAppsHook3 + ] + ++ lib.optionals stdenv.hostPlatform.isDarwin [ + xcodebuild + darwin.cctools + ]; + dontWrapGApps = true; - buildPhase = '' - runHook preBuild + env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1"; - # Disable NX interaction - export NX_TUI=false - export NX_DAEMON=false + preBuild = '' + ${preBuildCommands} + ''; - pnpm nx run desktop:build --outputStyle stream --verbose + scriptFull = "pnpm nx ${buildTask} --outputStyle stream --verbose"; - # Rebuild dependencies - export npm_config_nodedir=${electron.headers} - pnpm nx run desktop:rebuild-deps --outputStyle stream --verbose + installPhase = '' + runHook preInstall - runHook postBuild - ''; + ${installCommands} - installPhase = '' - runHook preInstall + runHook postInstall + ''; + + components = [ + "packages/ckeditor5" + "packages/ckeditor5-admonition" + "packages/ckeditor5-footnotes" + "packages/ckeditor5-keyboard-marker" + "packages/ckeditor5-math" + "packages/ckeditor5-mermaid" + "packages/codemirror" + "packages/commons" + "packages/express-partial-content" + "packages/highlightjs" + "packages/turndown-plugin-gfm" + + "apps/client" + "apps/db-compare" + "apps/desktop" + "apps/dump-db" + "apps/edit-docs" + "apps/server" + "apps/server-e2e" + ]; + + desktopItems = lib.optionals (app == "desktop") [ + (makeDesktopItem { + name = "TriliumNext Notes"; + exec = meta.mainProgram; + icon = "trilium"; + comment = meta.description; + desktopName = "TriliumNext Notes"; + categories = [ "Office" ]; + startupWMClass = "Trilium Notes Next"; + }) + ]; + + meta = { + description = "TriliumNext: ${app}"; + inherit mainProgram; + }; + }; + + desktop = makeApp { + app = "desktop"; + preBuildCommands = "export npm_config_nodedir=${electron.headers}"; + buildTask = "run desktop:rebuild-deps"; + mainProgram = "trilium"; + installCommands = '' + remove-references-to -t ${electron.headers} apps/desktop/dist/node_modules/better-sqlite3/build/config.gypi + remove-references-to -t ${nodejs.python} apps/desktop/dist/node_modules/better-sqlite3/build/config.gypi mkdir -p $out/{bin,share/icons/hicolor/512x512/apps,opt/trilium} cp --archive apps/desktop/dist/* $out/opt/trilium @@ -82,34 +181,29 @@ "''${gappsWrapperArgs[@]}" \ --set-default ELECTRON_IS_DEV 0 \ --add-flags $out/opt/trilium/main.cjs - - runHook postInstall ''; + }; - desktopItems = [ - (makeDesktopItem { - name = "TriliumNext Notes"; - exec = finalAttrs.meta.mainProgram; - icon = "trilium"; - comment = finalAttrs.meta.description; - desktopName = "TriliumNext Notes"; - categories = [ "Office" ]; - startupWMClass = "Trilium Notes Next"; - }) - ]; + server = makeApp { + app = "server"; + preBuildCommands = "pushd apps/server; pnpm rebuild; popd"; + buildTask = "--project=server build"; + mainProgram = "trilium-server"; + installCommands = '' + remove-references-to -t ${nodejs.python} apps/server/dist/node_modules/better-sqlite3/build/config.gypi + remove-references-to -t ${pnpm} apps/server/dist/node_modules/better-sqlite3/build/config.gypi - pnpmDeps = pnpm.fetchDeps { - inherit (finalAttrs) pname version src; - hash = "sha256-xC0u1h92wtthylOAw+IF9mpFi0c4xajJhUcA9pqzcAw="; - }; - - meta = { - description = "Free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases"; - mainProgram = "trilium"; - }; - }); + mkdir -p $out/{bin,opt/trilium-server} + cp --archive apps/server/dist/* $out/opt/trilium-server + makeWrapper ${lib.getExe nodejs} $out/bin/trilium-server \ + --add-flags $out/opt/trilium-server/main.cjs + ''; + }; in { + packages.desktop = desktop; + packages.server = server; + packages.default = desktop; } );