An alternative way to use Visual Studio with npm

EasyLOB
7 min readMar 28, 2023

Contents

· What is the problem?
· How does npm work?
· How does Visual Studio deal with NuGet?
· How does Visual Studio deal with npm?
· How do I deal with npm?
· How does Visual Studio deal with Gulp?
· How does Git deal with npm and NuGet?

IMPORTANT

NuGet accepts more than 1 version of a package in a project.

npm accepts only 1 version of a package in a project. The idea behind npm is to have a local copy, in the directory node-modules, for each project of your solution.

My way of using npm reduces the amount of data so many nome-modules directories require. To make it work I use the GLOBAL npm directory for 2 packages and only 1 node-modules directory per solution.

Of course, you may install more packages globally, but be aware, that ALL the projects you use this approach with share the same version, and, most important, the same updates of the packages: it’s up to you to decide if it works.

What is the problem?

.NET developers usually use NuGet as a Package Manager. Despite being able to deal with JavaScript packages, NuGet is not the best option for them.
So, a long time ago, Microsoft implemented native Bower support in Visual Studio, but Bower was deprecated in 2018:

How to migrate away from Bower?

So, some time ago, Microsoft created the LibPack to replace Bower in Visual Studio:

Library Manager ( LibMan )

But there is a much better solution than Bower or LibMan: npm.
npm is the Package Manager for Node.js and you will find there any JavaScript library you want.

Visual Studio has native support for npm, but I do not like the way it works.
So I changed it a little…

How does npm work?

npm manages and downloads JavaScript packages, very close to the way NuGet does with .NET Packages. Below you find a naive comparison of both:

The first npm goal is to support Node.js: the well-known JavaScript Server.
npm is a command-line tool and ( like Git ) you will feel better using it this way.

How does Visual Studio deal with NuGet ?

The NuGet packages are managed by NuGet Package Manager by command line and visually with Package Manager Console.
NuGet keeps a CACHE with all downloaded packages ( since ever ! ) in the following directory:

%UserProfile%\\.nuget\\packages

You may change the location of this CACHE with the following command:

SET NUGET_HTTP_CACHE_PATH=D:\NuGet\v3-cache

Below you find the project structure created for an ASP.NET Mvc Project using .NET Framework 4.8 or below, with NuGet:

/MySolution
/MyProject
packages.json
MyProject.csproj
/packages
/jQuery.3.4.1
MySolution.sln

As you can see, the packages are downloaded BY SOLUTION and NuGet automatically manages multiple versions.

Below you find the project structure created for an ASP.NET Core MVC Project with NuGet:

/MySolution
/MyProject
MyProject.csproj
MySolution.sln

As you can see, there are no packages directory and package.json file.
This is because all packages are kept in a USER directory and Projects reference it:

C:\Users\U-S-E-R\.nuget\packages

You may change the location of this directory with the following command:

SET NUGET_PACKAGES=D:\NuGet\packages

How does Visual Studio deal with npm ?

DON’T DO THIS: I WILL EXPLAIN WHY IN THE NEXT TOPIC!

To get npm you need to download and install Node.js:

Node.js Download

HINT
Do not install NPM Tools for Native Modules.

npm keeps a CACHE with all downloaded packages ( since ever ! ) in the following directory:

%AppData%/npm-cache

You may change the location of this CACHE with the following command:

npm config set cache D:\\npm\\CACHE --global

To begin with npm you create the package.json file in your ASNET MVC or ASP.NET Core MVC Project:

Add -> New Items -> Visual C# -> ASP.NET Core -> Web -> npm Configuration File

The file will be created empty but below you find the complete file:

{
"version": "1.0.0",
"name": "asp.net",
"private": true,
"devDependencies": {
"del": "6.0.0",
"gulp": "4.0.2"
},
"dependencies": {
"jquery": "3.4.1"
}
}

The devDepencies are packages you require for Development ( see Gulp below ).
The dependencies are packages you require for run-time.

To get the same result with the command line you may open the Command Line in the PROJECT directory and run the following commands:

npm init
npm install jquery@3.4.1 --save
npm update

The init command will create the package.json file.
The install command will download the package and update the package.json file ( — save ).
The update command will download the packages listed in the package.json file.

Eventually, you will find a package-lock.json file.
It contains detailed information about the dependencies between packages.
Should you delete it, you may recreate it with the following command:

npm install --package-lock-only

There is a nice extension for Visual Studio to open the Command Line without going to Windows Explorer and typing “cmd”:

Open Command Line

To force an update you clean the SOLUTION:

Build -> Clean Solution

Below you find the project structure created for an ASP.NET Mvc Project with npm:

/MySolution
/MyProject
/node-modules
jquery
package.json
MyProject.csproj
MySolution.sln

But, you end up with 299 packages, 3.315 files, and 9,17 MB ( Visual Studio 2022 + ASP.NET 6 )!

The final result will be the following:

  • A node_modules PER PROJECT, instead of PER SOLUTION like you get with NuGet.
  • If you have more than one MVC Project per Solution, you will have multiple node_modules directories.
  • Package Manager Console will not work, complaining a missing package.json for the SOLUTION.
  • 299 packages, 3.315 files, and 9,17 MB in the node_modules, for each MVC project.

Well, there are some things we may improve here…

How do I deal with npm ?

Below you find the project structure created for an ASP.NET Core Mvc PROJECT with npm:

/MySolution
/MyProject
/node-modules
LINK del
LINK gulp
MyProject.csproj
package.json
/node-Modules
jquery
package.json
MySolution.sln

Create an empty package.json ( DO NOT INCLUDE ANY PACKAGE ! ) file in your PROJECT:

{
"version": "1.0.0",
"name": "asp.net",
"private": true,
"devDependencies": {
},
"dependencies": {
}
}

This file will be visible inside Visual Studio in your PROJECT!

Go to the command line in your PROJECT directory and execute the following commands.
The commands below install del and gulp in the GLOBAL npm directory ( see npm CACHE directory above ):

npm install del@5.1.0 -g
npm install gulp@4.0.2 -g

The commands below may be used to update these packages, when necessary:

npm update del -g
npm update gulp -g

The commands below create a symbolic link from the GLOBAL npm directory into the node_modules of your PROJECT:

npm link del
npm link gulp

With the symbolic link, you have just 1 copy of these packages in the GLOBAL npm directory!
If you don´t install these packages in your PROJECT, Visual Studio will complain about Gulp and the Task Runner Explorer ( see Gulp below ) will not work.

Second, take care of your SOLUTION.

Create a package.json file in your SOLUTION directory:

{
"version": "1.0.0",
"name": "asp.net",
"private": true,
"devDependencies": {
},
"dependencies": {
"jquery": "3.4.1"
}
}

If you add this file to your solution it will be visible in a ( Solution ) folder named “Solution Items”.

Go to the command line in your SOLUTION directory and execute the following command:

npm update

You may also use the Visual Studio Package Manager Console:

Visual Studio -> Tools — NuGet Package Manager -> Package Manager Console

The final result will be the following:

  • A node_modules PER SOLUTION, like NuGet.
  • If you have more than one MVC Project per Solution, you will have only 1 node_modules directory.
  • Package Manager Console will work perfectly with npm, for install/update/uninstall.
  • Task Runner Explorer ( see Gulp below ) will work perfectly.

How does Visual Studio deal with Gulp?

Gulp is a wonderful Task Automation JavaScript Tool fully integrated into Visual Studio.
As the JavaScript packages are downloaded in the node_modules directory, Gulp will help us to copy the files we really need to:

  • /Content and /Scripts directories for ASP.NET MVC Application
  • /wwwroot directory for ASP.NET MVC Core Application

The example below is for ASP.NET Core but may be easily adapted to ASP.NET MVC.
To begin just add a gulpfile.js to your PROJECT with the following content:

var del = require('del');
var gulp = require('gulp');
var source = '../node\_modules/';
var destination = './wwwroot/npm/';
gulp.task('npm-copy', async function () {
// jquery
gulp.src(source + "jquery/dist/\*min\*").pipe(gulp.dest(destination + "/jquery/js"));
});
gulp.task('npm-delete', async function () {
return del(\[destination + '/\*\*/\*'\]);
});

I guess the code is quite easy to understand.
As you can see it needs del and gulp packages to run.
This file will create two tasks: npm-copy and npm-delete.
To execute it just right-click the file above and select Task Runner Explorer.

After running the npm-copy Task I get the following structure under my wwwroot directory:

/wwwroot
/npm
/jquery
/js
jquery.min.js
jquery.min.map

How does Git deal with npm and NuGet?

I EXCLUDE packages directory and node_modules directory from Git versioning by including it in the .gitgnore file:

# NuGet Packages
\*\*/packages/\*
# npm Packages
\*\*/node\_modules/\*

It does not make sense to version something that is downloaded from the Web any time you want. You just download all packages after cloning the repository.

--

--

EasyLOB

Engineer, Developer, Software Engineer, IT Manager, Teacher and Consultant with 30+ years of experience in IT