NestJS cli very slow in Docker container on Windows with Visual Studio Code

Viewed 1018

The response from the nest cli command from NestJS (npm i -g @nestjs/cli) in a Docker Development container with Visual Studio Code on Windows 10 is suddenly very slow. At first it works fine but at some point, for instance after deleting a directory in the src folder, the nest command gets very slow.

Example:

node ➜ /workspaces/Servers/terminal-server (master ✗) $ time nest --help

[...]

real    0m44.576s
user    0m6.239s
sys     0m4.407s

Yarn is used for the package manager. NPM is used to install nest cli globally (npm i -g @nestjs/cli):

Software Version Running in container Running on W10 host
NPM 8.1.2 X
NodeJS v16.13.1 X
Yarn 1.22.15 X
Typescript 4.5.2 X
Nest 8.1.6 X
Visual Studio Code 1.63.2 X
Docker Desktop 4.3.1 X

It looks like the line const localCommandLoader = local_binaries_1.loadLocalBinCommandLoader(); in /usr/local/share/npm-global/bin/nest is causing the delay.

Edit: Compiling is also very slow. As you can see, it started at 8:57:20 and finished at 9:00:17. And this is compiling the default scaffolding.

[8:57:20 AM] Starting compilation in watch mode...

[8:59:43 AM] Found 0 errors. Watching for file changes.

[Nest] 5197  - 12/23/2021, 9:00:17 AM     LOG [NestFactory] Starting Nest application...
[Nest] 5197  - 12/23/2021, 9:00:17 AM     LOG [InstanceLoader] AppModule dependencies initialized +67ms
[Nest] 5197  - 12/23/2021, 9:00:17 AM     LOG [RoutesResolver] AppController {/}: +42ms
[Nest] 5197  - 12/23/2021, 9:00:17 AM     LOG [RouterExplorer] Mapped {/, GET} route +8ms
[Nest] 5197  - 12/23/2021, 9:00:17 AM     LOG [NestApplication] Nest application successfully started +8ms

I did the same on WSL:

[10:03:48 AM] Starting compilation in watch mode...

[10:03:53 AM] Found 0 errors. Watching for file changes.

[Nest] 1998  - 12/23/2021, 10:03:54 AM     LOG [NestFactory] Starting Nest application...
[Nest] 1998  - 12/23/2021, 10:03:54 AM     LOG [InstanceLoader] AppModule dependencies initialized +62ms
[Nest] 1998  - 12/23/2021, 10:03:54 AM     LOG [RoutesResolver] AppController {/}: +14ms
[Nest] 1998  - 12/23/2021, 10:03:54 AM     LOG [RouterExplorer] Mapped {/, GET} route +6ms
[Nest] 1998  - 12/23/2021, 10:03:54 AM     LOG [NestApplication] Nest application successfully started +9ms

For the Docker image I've selected the Node.js & TypeScript image. Would it be better to just use a plain image and install everything manually?

Or is there a way to get the response time of nest normal again?

1 Answers

TL;DR If you insist on booting into Windows for development but want to use VSCode and dev containers, try doing it all inside a Linux VM as I got a 96% reduction in time taken for key dev task steps.

Summary

I get a 96% reduction on startup / recompile time of a dev-container NestJS TypeScript project on npm run start:dev when running in a linux VM inside Windows 10 vs VSCode directly Windows 10 with docker and wsl2. ie 7s vs 2m 50s

Dev Containers

I think dev containers are great, love using them on github codespaces, but found the experience on Win 10 to be painfully slow.

In a multi developer team dev containers can offer a consistent experience between developers and reduce the risk of different setups on different developers' machines. But that's worthless if it takes more than a few seconds to rebuild the app everytime you save a file while running in 'watch' mode.

What slows NestJS / TypeScript in Dev Containers

After various investigations I'm convinced the speed penalty is in the dev container accessing the hosts filesystem.

NestJS cli is frustratingly eager to load everything it can do, before it even parses the command line args, so that's a big hit if filesystem access is slow.

And then the TypeScript compilation is obviously heavily dependent on filesystem speed. So this is the other area that grinds to a halt. Even on a relatively small NestJS project with few additional external dependencies!

What's fastest

Running Linux inside a VM on my Windows machine, running VSCode and docker all inside that VM meant that the filesystem access between the commands running inside the dev container (in docker inside the linux VM) can access the code 'hosted' on the linux VM very quickly.

Comparison Table

Activity Codespaces
Browser
Codespaces
Win10 remote
VSCode + Win Docker
on Win 10 with WSL2
VSCode + docker
in Linux VM
in Win 10
npx nest i 1.16s 1.16s 14.2s 1.12s
npm run start:dev startup 10s 8s 170s 7s
npm run start:dev update a file 3s 2s 38s 2s
rm -rf node_modules ; time npm install 30s 28s 85s 27s

Setups used:

  • Codespaces
    • 2core 4GB instance
  • Win 10
    • AMD Ryzen 7 3700X 8 Core @ 4.16GHz
    • 64GB 2400MHz RAM
    • 1TB SSD
    • Internet: 27Mb down / 5Mb up
  • Linux VM (inside Win 10 above)
    • VMware 16.2.3
    • Ubuntu 22.04
  • dev container is the recommended Node.js & Typescript container with VARIANT: "16-bullseye"
    • with mariadb server running inside

To get an active-developer experience, I ran each command a few times until the timing settled down and recorded the most representative time...

  • anything that doesn't use 'time' in the command was done by hand and so has a +/- 1sec error
  • time npx nest i
    • the time the command shows at the end
  • npm run start:dev startup
    • timing is from hitting enter to the first log of LOG [NestFactory] Starting Nest application...
  • npm run start:dev update a file
    • timing is from saving an update to a watched file, to the next log of LOG [NestFactory] Starting Nest application...
  • rm -rf node_modules ; time npm install
    • just another filesystem dependent task to compare the environments
    • the time the command shows at the end
Related