If you’re like me, you love npm ci
. A lot. Until that one fateful day.
Let’s say you want to install the Netlify CLI locally in order to automate your deployment without building on Netlify directly. My use case for this is using Hakyll, which in turn relies on Stack and Haskell, and Netlify does not seem to support this build path out of the box.
Because you don’t just want to follow the instructions written in the Netlify documentation and install an NPM package globally using
npm install -g netlify-cli
you try to install it locally and call the individual Netlify CLI sub commands
using npm run
.
So, you run
npm install --save netlify-cli
and it appears to work, at first.
We look at the size of the resulting node_modules
folder and get nervous.
~/p/test-netlify-cli$du --si -s node_modules
432M node_modules
Wow, so much needed to push some files to a server. Accepting this, we try to
establish whether this can be reinstalled easily using npm ci
(clean
install), which is where we hit a road block.
~/p/test-netlify-cli$npm ci
npm ERR! code EBADPLATFORM
npm ERR! notsup Unsupported platform for @esbuild/android-arm@0.16.17: wanted {"os":"android","arch":"arm"} (current: {"os":"darwin","arch":"arm64"})
npm ERR! notsup Valid OS: android
npm ERR! notsup Valid Arch: arm
npm ERR! notsup Actual OS: darwin
npm ERR! notsup Actual Arch: arm64
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/justusperlwitz/.npm/_logs/2023-02-10T04_46_03_996Z-debug-0.log
Ouch! What is this? android-arm
? But we are building on macOS with arm64, why
would it try to pull in android dependencies? We consult the internet, and find
that people have related problems to this. First, we see that the problem seems
not to lie in the Netlify CLI itself, but in esbuild. So we find one
closed issue and another
closed issue, both gone stale
and not translated into any action.
Further searching reveals a
post
by Sean McPherson, talking about a seemingly related issue, during an automated
build. In it, the author describes deleting package-lock.json
and not
committing it to version control as a workaround, and explains that this will
not work well in a professional environment with multiple contributors.
Sadly, I am the only one working on my personal website, so luckily I can
attempt to fix it by … deleting the package-lock.json
file before I perform
an npm install
(and not clean install, since there is no lock file).
I will not do that of course, because I have too much pride and putting a lock file out of version control is exactly what I was warned about 1 month into starting as a Ruby on Rails developer at the start of my career more than 10 years ago.
And since some habits are just hard to break, I begun to dig a bit more into
what is causing the issue specifically. When I read Sean McPherson’s blog post
one more time, I see the build log mentioning a --no-optional
flag. That lead
me to believe that I can somehow nudge NPM into leaving out the Android related
packages.
Just running
npm install --save --no-optional netlify-cli
does absolutely nothing differently (still have to delete the lock file every time), but it does show us an interesting hint:
npm WARN config optional Use `--omit=optional` to exclude optional dependencies, or
npm WARN config `--include=optional` to include them.
npm WARN config
npm WARN config Default value does install optional deps unless otherwise omitted.
We attempt to follow the suggestion here and receive an even more interesting result:
~/p/test-netlify-cli$npm install --save --omit=optional netlify-cli
npm ERR! code 1
npm ERR! path ...
npm ERR! command failed
npm ERR! command sh -c node install.js
npm ERR! [esbuild] Failed to find package "@netlify/esbuild-darwin-arm64" on the file system
npm ERR!
npm ERR! This can happen if you use the "--no-optional" flag. The "optionalDependencies"
npm ERR! package.json feature is used by esbuild to install the correct binary executable
npm ERR! for your current platform. This install script will now attempt to work around
npm ERR! this. If that fails, you need to remove the "--no-optional" flag to use esbuild.
It looks like esbuild and/or netlify-cli are very keen on installing the
relevant system packages. Unfortunately, I have not been able to figure out how
to omit all the non-relevant packages, and just install
@netlify/esbuild-darwin-arm64
directly. One way or another it breaks after
trying to recreate node_modules
or package-lock.json
. For example, the
following will not work:
npm install --save --omit=optional netlify-cli @netlify/esbuild-darwin-arm64
Maybe that is a limitation of NPM as well. As it stands right now, I have to
run npm i
instead of npm ci
and one way or another
other people seem to have this issue too.