canva-public / js2nix

Node.js modules installation using Nix
MIT License
63 stars 14 forks source link

Issue building isaacs-clui@8.0.2 #26

Closed RocketPuppy closed 8 months ago

RocketPuppy commented 9 months ago

Hi, I have an issue when running the generated install script when this package is in the dependency closure. As you can see from the log output, it tries to symlink string-width into isaacs-clui but can't because it's already there.

@nix { "action": "setPhase", "phase": "unpackPhase" }
unpacking sources
unpacking source archive /nix/store/1sz22m4gsixc21cblc4151nhqgr7wjdl-cliui-8.0.2.tgz
source root is package
setting SOURCE_DATE_EPOCH to timestamp 499162500 of file package/package.json
@nix { "action": "setPhase", "phase": "patchPhase" }
patching sources
@nix { "action": "setPhase", "phase": "installPhase" }
installing
Executing Node.js install script for @isaacs/cliui ...
Error: EEXIST: file already exists, symlink '/nix/store/p9cxyx378j2s8y79980d0vy4jldprlc6-string-width-5.1.2/pkgs/string-width@5.1.2/node_modules/string-width' -> '/nix/store/mqs7wj5iybcv3g37sdp8w557k7c8vxp6-isaacs-cliui-8.0.2/pkgs/isaacs-cliui@8.0.2/node_modules/string-width'
olebedev commented 8 months ago

Hi there 👋

This is an interesting case, I spent a fair bit of time to understand what's going on there.

From what I can see, the package has these dependencies:

wrap-ansi "^8.1.0"
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
strip-ansi "^7.0.1"
strip-ansi-cjs "npm:strip-ansi@^6.0.1"
string-width "^5.1.2"
string-width-cjs "npm:string-width@^4.2.0"

Can you see the pattern? There are duplicates with -cjs suffix and an older minor version. I checked these packages and it turned out that the newer package uses ES modules and the older packages export their content as a CommonJS module.

The interesting part that breaks things here is that the *-cjs packages have their names in their package.json without that -cjs suffix. As long as js2nix links packages based on their names in package.json but not on how that package is known in the outer context, we are getting that clash of symlinks!

The fix for that would be to patch these packages to give them legal names. So, you would need to add the following into your package.json:

{
  "js2nix": {
    "overlay": {
      "ansi-regex@^6.0.1": {
        "doCheck": false
      },
      "ansi-styles@^6.1.0": {
        "doCheck": false
      },
      "strip-ansi@^7.0.1": {
        "doCheck": false
      },
      "string-width@^5.0.1": {
        "doCheck": false
      },
      "wrap-ansi@^8.1.0": {
        "doCheck": false
      },
      "string-width-cjs@4.2.3": {
        "patches": [
          "./patches/0001-string-width-cjs-name.patch"
        ]
      },
      "strip-ansi-cjs@6.0.1": {
        "patches": [
          "./patches/0002-string-ansi-cjs-name.patch"
        ]
      },
      "wrap-ansi-cjs@7.0.0": {
        "patches": [
          "./patches/0003-wrap-ansi-cjs-name.patch"
        ]
      }
    }
  }
}

And add the patches into ./patches directory, next to your package.json file with the following content:

This looks a bit hectic, but this is what makes js2nix pure and deterministic, so we have to sometimes tweak some faulty npm packages to make them work with the strict model that js2nix and Nix provides.

I hope that helps. Feel free to reopen the issue, if you have more questions with regard to that.

Best, Oleg