dream2nix icon indicating copy to clipboard operation
dream2nix copied to clipboard

Node.js examples - not sure how to use...

Open a-h opened this issue 1 year ago • 7 comments

Hi,

I was trying to port an npmlock2nix project over to dream2nix, and I don't know where to start based on reading the repo examples etc. The documentation site seems broken.

This blog post has a nice looking example - https://johns.codes/blog/building-typescript-node-apps-with-nix but it appears out of date.

The examples here look more complete, but are out-of-date - https://github.com/nix-community/dream2nix/blob/a5e098038c42528bf4dff2db6cb958b1777b00e3/examples/nodejs_eslint/flake.nix#L20

From reading the code at https://github.com/nix-community/dream2nix/blob/main/examples/dream2nix-packages-nodejs/no-lock/default.nix I have no idea where to start. I don't know where "config" comes from.

Any pointers on how to proceed? Here's the npmlock2nix example.

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/23.05";
    npmlock2nix = {
      url = "github:nix-community/npmlock2nix";
      flake = false;
    };
  };

  outputs = { self, nixpkgs, npmlock2nix }:
    let
      pkgs = nixpkgs.legacyPackages."x86_64-linux";
      nl2nix = import npmlock2nix {inherit pkgs;};
      app = nl2nix.v2.build {
        src = ./.;
        nodejs = pkgs.nodejs-18_x;
        buildCommands = [ "HOME=$PWD" "npm run build" ];
        installPhase = ''
          mkdir -p $out
          cp -r .next/standalone $out/app
          cp -r public $out/app/public
          mkdir -p $out/app/.next
          cp -r .next/static $out/app/.next/static
        '';
      };
      nextUser = pkgs.runCommand "user" {} ''
        mkdir -p $out/etc
        echo "nextjs:x:1000:1000:nextjs:/home/nextjs:/bin/false" > $out/etc/passwd
        echo "nextjs:x:1000:" > $out/etc/group
        echo "nextjs:!:1::::::" > $out/etc/shadow
      '';
      dockerImage = pkgs.dockerTools.buildImage {
        name = "app";
        tag = "latest";

        copyToRoot = [
          # Uncomment the coreutils and bash if you want to be able to use a shell environment
          # inside the container.
          #pkgs.coreutils
          #pkgs.bash
          nextUser
          pkgs.nodejs-18_x
          app
        ];
        config = {
          Cmd = [ "node" "server.js" ];
          User = "nextjs:nextjs";
          Env = [ "NEXT_TELEMETRY_DISABLED=1" ];
          ExposedPorts = {
              "3000/tcp" = {};
          };
          WorkingDir = "/app";
        };
      };
    in
    {
      packages."x86_64-linux".default = app;
      packages."x86_64-linux".docker = dockerImage;
    };
}

And here's my non-working attempt to get it running:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/23.05";
    gitignore = {
      url = "github:hercules-ci/gitignore.nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    dream2nix.url = "github:nix-community/dream2nix";
  };

  outputs = { self, nixpkgs, gitignore, dream2nix }:
    let
      pkgs = nixpkgs.legacyPackages."x86_64-linux";
      d2n = dream2nix.modules.drv-parts.nodejs-granular;
      node = {
        imports = [
          dream2nix.modules.drv-parts.nodejs-node-modules
        ];

        mkDerivation = {
          src = ./.;
        };

        deps = {nixpkgs, ...}: {
          inherit
            (nixpkgs)
            fetchFromGitHub
            mkShell
            stdenv
            ;
        };

        # How do I set build command?
        #buildCommands = [ "HOME=$PWD" "npm run build" ];

        # How do I set the node version?
        #nodejs = pkgs.nodejs-18_x;

        # How do I configure the install phase?
        #installPhase = ''
          #mkdir -p $out
          #cp -r .next/standalone $out/app
          #cp -r public $out/app/public
          #mkdir -p $out/app/.next
          #cp -r .next/static $out/app/.next/static
        #'';

        name = "my-app";
        version = "2.8.7";
      };
      # This doesn't work.
      app = node.mkDerivation {};
      nextUser = pkgs.runCommand "user" {} ''
        mkdir -p $out/etc
        echo "nextjs:x:1000:1000:nextjs:/home/nextjs:/bin/false" > $out/etc/passwd
        echo "nextjs:x:1000:" > $out/etc/group
        echo "nextjs:!:1::::::" > $out/etc/shadow
      '';
      dockerImage = pkgs.dockerTools.buildImage {
        name = "app";
        tag = "latest";
        copyToRoot = [
          # Uncomment the coreutils and bash if you want to be able to use a shell environment
          # inside the container.
          #pkgs.coreutils
          #pkgs.bash
          nextUser
          pkgs.nodejs-18_x
          app
        ];
        config = {
          Cmd = [ "node" "server.js" ];
          User = "nextjs:nextjs";
          Env = [ "NEXT_TELEMETRY_DISABLED=1" ];
          ExposedPorts = {
              "3000/tcp" = {};
          };
          WorkingDir = "/app";
        };
      };
    in
    {
      packages."x86_64-linux".default = app;
      packages."x86_64-linux".docker = dockerImage;
    };
}

a-h avatar Aug 08 '23 16:08 a-h

It looks like npmlock2nix is no longer required, since nix itself has a buildNpmPackage function now, as per https://zero-to-nix.com/start/nix-build

However, it requires you to define the hash in advance as npmDepsHash rather than it becoming part of the flake.lock.

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/23.05";
  };

  outputs = { self, nixpkgs }:
    let
      # Systems supported
      allSystems = [
        "x86_64-linux" # 64-bit Intel/AMD Linux
        "aarch64-linux" # 64-bit ARM Linux
        "x86_64-darwin" # 64-bit Intel macOS
        "aarch64-darwin" # 64-bit ARM macOS
      ];

      # Helper to provide system-specific attributes
      forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f {
        pkgs = import nixpkgs { inherit system; };
      });
    in
    {
      packages = forAllSystems ({ pkgs }: {
        default = pkgs.buildNpmPackage {
          name = "zero-to-nix-javascript";

          buildInputs = with pkgs; [
            nodejs-18_x
          ];

          src = ./.;

          npmBuild = "npm run build";

          npmDepsHash = "sha256-s1Kze9LuYSDVxm1jxMG1yoGCYVRBsnwJ0Zi0NcT5lzg=";

          installPhase = ''
            mkdir -p $out
            cp dist/* $out
            cp hello.sh $out/hello
            chmod +x $out/hello
          '';
        };
      });
    };
}

a-h avatar Sep 03 '23 17:09 a-h

Hey @a-h we have been overhauling the architecture within the last couple of months and it was a bit messy. By now we have removed all the legacy things and it should be a lot less confusing.

You might want to check the docs and ./examples once more. We'd be happy to get some feedback.

DavHau avatar Sep 05 '23 22:09 DavHau

Thanks, I'm afraid I still can't work out how to package a Node app based on the examples.

Looking at this file, I can't see where the derivation is output: https://github.com/nix-community/dream2nix/blob/main/examples/packages/single-language/nodejs-project/default.nix

There's a mkDerivation function, but I don't know why - should I call that? There's also a node-js-granular function. Are two things being packaged in the same file, can I call either of these functions?

I don't know where the entrypoint is. How would I connect this file up to a flake.nix? The example https://github.com/nix-community/dream2nix/blob/main/examples/dream2nix-repo-flake/flake.nix uses a dream2nix function called import packages - is there an importPackage function and that's how mkDerivation gets called? Does it magically know how to pass the config parameter?

I saw that the config parameter is still there. I googled around more, and found https://nixos.org/guides/nix-pills/nixpkgs-parameters.html#id1442 - so I guess that's what the config param is, and it can be null? But... its used on line 17 to get "deps" - I don't know how that gets populated.

I don't know why there's a lock.lockFileRel parameter, and what it might be used for. Where does that file come from?

A fully standalone minimal example would be very useful for me. 😁

a-h avatar Sep 06 '23 09:09 a-h

similarly I've had a look at the examples and what confuses me is why packagesDir start with a / : packagesDir = "/packages"; . In my repo the package.json is at the root of the repo so what should I set packagesDir to ? looks like it is mandatory. (I am using the flake example).

teto avatar Sep 11 '23 13:09 teto

Hi, I've been struggling a lot as well with building a node app with dream2nix. I've only read good things about it and I'd like to give it a try, but I don't get it. Looking at the docs here for example: https://nix-community.github.io/dream2nix/options/nodejs-node-modules.html I have no idea what I'm supposed to do. Same with reading the examples, the node-project doesn't explain what kind of project, what's the difference between this and package? both use evalModules and it's not clear how the default.nix are different. I've been using flake-parts and I cannot find any mentions in the docs, but I see folders related to flake-parts.

It would be awesome if something like https://diataxis.fr/ was followed for dream2nix, I don't mind reviewing all the documentation PR's, and once I'm more familiarized also sending PR's.

Some tutorials that I think would be useful are migration tutorials:

  • From pkgs.rustPlatform.buildRustPackage to dream2nix.buildRustPackage
  • From buildNpmPackage to dream2nix.lib.evalModules?

That would help people understand where they are standing and how to transition. And it would also create a space for people to send their migration guides PR's when they transition from another tool to dream2nix.

Thanks again for the project and the effort, it's really what I'm dreaming for 💪🏻

woile avatar Nov 26 '23 08:11 woile

I'm in a similar situation and it seems to be really difficult to find help.

Would be great to have a simple example like: build a single node package from GitHub and use it in a NixOS configuration.

serpent213 avatar Jan 22 '24 11:01 serpent213

For anyone that stumbled across this in the last months: @DavHau cleaned up a lot of the examples recently (42838c590971da17a4b6483962707b7fb7b8b9a7) and as far as i tested it the nodejs examples are now easy to build and adapt. Just cd into the directory and 'nix build'. There are still some quirks regarding specific npm packages but many projects can be built without any problems. I think this issue can be closed.

punsii2 avatar Mar 20 '24 17:03 punsii2

Agreed, just looped back around this, and the examples work, and are relatively easy to adapt now.

a-h avatar Jul 12 '24 15:07 a-h