canva-public/js2nix

Issue building isaacs-clui@8.0.2

RocketPuppy opened this issue · 1 comments

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'

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:

  • patches/0001-string-width-cjs-name.patch
    diff --git a/package.json b/package.json
    index 28ba7b4..8473800 100644
    --- a/package.json
    +++ b/package.json
    @@ -1,5 +1,5 @@
     {
    -	"name": "string-width",
    +	"name": "string-width-cjs",
        "version": "4.2.3",
        "description": "Get the visual width of a string - the number of columns required to display it",
        "license": "MIT",
    
  • patches/0002-string-ansi-cjs-name.patch
    diff --git a/package.json b/package.json
    index 1a41108..3145a62 100644
    --- a/package.json
    +++ b/package.json
    @@ -1,5 +1,5 @@
     {
    -	"name": "strip-ansi",
    +	"name": "strip-ansi-cjs",
        "version": "6.0.1",
        "description": "Strip ANSI escape codes from a string",
        "license": "MIT",
  • patches/0003-wrap-ansi-cjs-name.patch
    diff --git a/package.json b/package.json
    index dfb2f4f..c073015 100644
    --- a/package.json
    +++ b/package.json
    @@ -1,5 +1,5 @@
     {
    -	"name": "wrap-ansi",
    +	"name": "wrap-ansi-cjs",
        "version": "7.0.0",
        "description": "Wordwrap a string with ANSI escape codes",
        "license": "MIT",

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