6

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?

Postie
  • 324
  • 3
  • 15
  • When you say it used to be fast and is now slow, are you sure that it wasn't just being cached before, which seems fast, and now it is actually compiling that it is slow? There is a common problem with docker and npm, in that depending on which cache layers you lose, the npm install has to download everything again and it can be slow. The only thing you can do afaik is push the npm part as early as possible in the dockerfile to minimise the number of rebuilds. – Luke Briner Dec 23 '21 at 09:46
  • Well setting up the application with `nest new projectname` was fast. The packages where already installed using yarn. NPM was only used to install the nest cli globally. Then I created a controller but it had a typo. Removed the files, created the controller again with `nest g controller name` and then it got real slow. – Postie Dec 23 '21 at 11:07
  • 1
    I'm running into virtually the exact same situation. node:16.13.1-alpine3.14, NestJS v8.1. Between saving a file and have the server restart is ~2 mins, virtually unusable. – prototypik Jan 30 '22 at 00:03
  • can you show the output of [`tsc --extendedDiagnostics`](https://github.com/microsoft/TypeScript/wiki/Performance#extendeddiagnostics) – Micael Levi Jan 30 '22 at 00:10
  • Could do that, but even showing the help from the nest cli is slow. Or does it get compiled runtime with tsc? – Postie Feb 17 '22 at 08:07
  • 1
    Im having same issue.. hopefuly a real answer will come soon – Jeremy Meek Mar 09 '22 at 03:33

3 Answers3

5

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
Dave Amphlett
  • 1,922
  • 1
  • 15
  • 17
0

I have been experiencing this as well and wanted to expand on the info above based on my experience. VS Code has a WSL extension which lets you open WSL folders in code which allows you to see better performance on the file system. See https://code.visualstudio.com/docs/remote/wsl for reference. Here are the steps I used to be able to make it work:

  • Install Ubuntu 20 from the Microsoft Store for a WSL distro. You can install it other ways I believe. I tried 22 and it did not work but not sure if that was because I did something else wrong so you could try it and see.
  • Enable WSL integration for the new distro with Docker Desktop. Reference https://docs.docker.com/desktop/windows/wsl/ for some information on this.
  • Install the WSL extension for VS Code. See first link above.
  • As noted in both links above the way to start is open up a WSL terminal, cd to the directory you want to run VS Code in and type code . It is also possible to do it from the VS Code interface as well as noted in the VS Code post.
  • From there if you have your .devcontainer folder already setup you can reopen the folder in a dev container and away you go!
  • If you need to access any of the files through Windows you can go to the \wsl$ network path and access them there.

This feels a little convoluted but it seems this is the supported way for now based on what I read. Perhaps in the future the WSL2 to Windows file system interface will be improved to a point where this is not necessary.

Happy to hear any feedback or update this based on other's experiences.

Rob Baily
  • 2,770
  • 17
  • 26
0

As @Rob Baily suggested, executing the script in WSL while the files are in windows is very slow.

From an microsoft/WSL issue:

(...) /mnt/c is your Windows drive, so WSL2 accesses files from Windows via a proxy, not directly. Copy all project files from /mnt/c/.../example-nextjs to /home/user, so that it is stored in WSL2 virtual machine.

I did that and it's very simple to run VS Code from a WSL folder if you want:

mkdir -p ~/projects/foo
cp -Rf /mnt/c/projects/foo ~/projects/foo

Then run VS Code on the new folder:

cd ~/projects/foo
code .

From now on, you are actually running the code in the WSL VM, so you don't need to manage a separate Linux VM on your computer.

After doing this, running npm run start:dev takes only a few seconds for me (compared to several minutes when the files were on /mnt/..) and now --watch actually works!