The Day npm decided to Break: Fixing Angular 18 Builds on Windows – and the hidden config that caused it all


💭 Introduction

Today, for no apparent reason—or at least that’s what it seemed to me—I stumbled upon a problem that completely broke my build. It started with what looked like a typical npm install, but suddenly nothing worked anymore.

If you’ve ever faced cryptic errors like:

Cannot find module @rollup/rollup-win32-x64-msvc
Cannot find module @esbuild/win32-x64

…then you already know the pain. 😩

In this post, I’ll walk you through what happened, why this issue keeps coming back, what the real cause is, and—finally—how to fix it once and for all. Hopefully, this will save you from hours of frustration and help your team avoid the same trap.


🔍 The Problem: npm Optional Dependencies Gone Wrong

It all started in an Angular 18 project on Windows. Running npm install looked fine—until I tried to build:

npm run build

And suddenly:

✘ [ERROR] Cannot find module @rollup/rollup-win32-x64-msvc

After digging deeper, I discovered this was a known npm bug on Windows that affects optional dependencies—those platform-specific packages like @esbuild/win32-x64 or @rollup/rollup-win32-x64-msvc.

The issue: npm sometimes fails to install them properly depending on your cache, Node.js version, or even network timing.

You end up with Linux binaries on Windows, which obviously don’t run. 🙃


⚠️ It Never Really Goes Away…

You fix it. You reinstall. You clear caches. You even think it’s over… and then it comes back.

Sometimes on a different machine. Sometimes in a new project. Sometimes weeks later after a package update.

That’s when I realized—this wasn’t a one-off. This was part of a larger pattern of npm’s handling of optional dependencies across platforms.

To prove it, here’s the list of official issues still open (and some already closed) across the npm/cli and rollup/rollup repositories.


🗂️ The Landscape: npm & Rollup Issues (2022–2025)

🧱 npm/cli Issues

✅ Closed / Completed

  1. #4828 – Platform-specific optional dependencies not included in package-lock.json
    • Fixed via PR #8184 (merged)
    • Root cause of platform-dependent binary errors
  2. #7900 – npm install hangs for ~2 minutes with optional dependencies in npm 10.9.0
    • Closed (November 2024)
    • Performance fix
  3. #7868 – npm 10.9.0 stuck in WSL Ubuntu environment
    • Fixed; Windows-specific
  4. #8260 – Error with npm install after creating Vite project
    • Closed (not reproducible)
  5. #7961 – Optional deps for OS/CPU variants pruned unexpectedly
    • Closed
  6. #7404 – Workspaces don’t honor shallow install strategy
    • Closed
  7. #7395 – Certificate issue with GitHub-hosted package on Windows
    • Closed (April 2024)

🔓 Open

  1. #8514 – libc field missing in package-lock.json
    • Open since August 2025
    • Affects native binary resolution (Linux)
  2. #7355 – Failed optional dependency builds block global installs
    • Open since April 2024

🧮 Plus ~50 other issues mentioning “optional dependencies” in npm/cli still open.


🎛️ rollup/rollup Issues

🔓 Open

  1. #5901 – Cannot find module @rollup/rollup-win32-x64-msvc
  2. #5897 – Same error as above
  3. #5821 – Windows Security flags rollup.win32-x64-msvc.node as malware
  4. #5571 – Cannot find module @rollup/rollup-win32-x64-msvc (Rollup 4.18.1) ← 🏆 The most useful one
  5. #5295 – Unsupported platform

✅ Closed

  1. #5325 – Similar case with Nuxt 3
  • Closed January 2024

💡 The Turning Point: «Eureka!»

After reading through all those reports, I realized something:
the issue wasn’t always npm’s fault.

Sometimes, npm was simply doing what I told it to—unintentionally.

That’s when I found the hidden culprit: the npm config os setting.


🧩 Before You Blame npm: Check Your Configuration

Before diving into complex fixes or postinstall scripts, check this first.

Run this:

npm config get os

Expected on Windows:

  • null (auto-detects your OS)
  • win32

Problem output on Windows:

  • linux
  • darwin

If npm thinks your OS is Linux, it will install Linux binaries—even on Windows! 🤯

This happens often if:

  • You used WSL and ran npm config set os linux
  • You copied a .npmrc file from another machine
  • You work across Docker + Windows environments
  • You’re using an old npm version

🛠️ The Fix

npm config delete os
npm config get os
# should return null

Then reinstall everything:

rm -rf node_modules package-lock.json
npm install

You’ll now get the correct win32-x64 binaries for Rollup, Esbuild, and Nx.

Recommended npm version: 10.9.4 or higher

Upgrade if needed:

npm install -g npm@10

⚙️ The Root Cause (for Real This Time)

Once I fixed the OS config, npm finally did its job.
But understanding why this happens helps avoid it altogether.

In short:

  • npm skips installing optional dependencies when it thinks they’re for another platform.
  • If your npm config os says linux, it won’t fetch Windows binaries.
  • Even reinstalling or clearing cache won’t help until that config is corrected.

🚀 Permanent Fixes and Best Practices

✅ Use lifecycle scripts wisely

Add preinstall/postinstall hooks to handle platform-specific installs automatically.

✅ Lock Node.js version via .nvmrc

echo "18.20.0" > .nvmrc

✅ Don’t commit .npmrc with OS-specific settings

.npmrc

✅ Use Yarn if all else fails

Yarn doesn’t have this optional-deps bug on Windows.


🎯 Conclusion

So, what started as “just another npm bug” turned out to be an invisible config problem hiding in plain sight.

The good news?
Once you know about it, fixing it takes less than a minute.

✅ Delete the wrong os config
✅ Use npm 10.9.4+
✅ Reinstall clean
✅ Enjoy working builds again

And maybe, just maybe, you’ll save someone else from losing half a day to this same issue. 😅

💬 If I’m being completely honest, I think what actually triggered the whole mess was my failed attempt to install NVM inside WSL2. I don’t remember exactly how I did it, but I’m convinced that was the spark that caused everything to go wrong! 🔥

If you ever plan to install NVM inside WSL2, make sure it has its own isolated setup and does not share paths or environment variables with your Windows installation.
Here’s how to clean up and reconfigure it properly:

# --- Clean Windows NVM paths from PATH (sample and optional) ---
export PATH=$(echo "$PATH" | tr ':' '\n' \
  | grep -v '^/mnt/c/ProgramData/nvm' \
  | grep -v '^/mnt/c/ProgramData/nvm/nodejs' \
  | tr '\n' ':')

# --- Install NVM ---
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash

# 🧩 Set up NVM for WSL2
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

Doing this ensures your WSL2 environment stays clean, isolated, and free from weird cross-path issues between Windows and Linux. 🚀


📚 References


Key Takeaways

  • Always check npm config get os before assuming a bug
  • Don’t trust “fixes” that don’t explain the why
  • Document what you learn — the next dev will thank you 🙌

Deja un comentario

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.