Excluding the node_modules folder when publishing ASP.NET projects.
There are quite a few ASP.NET developers that have been adopting NodeJS in their projects for client side package management and development time tooling. A question that I get relatively often is, how can they exclude the node_modules
folder from being published. In this short post, I'll show some options for getting that done.
Setting up a project
I'm starting off with an out of the box, new ASP.NET MVC application. If you're using ASP.NET Web Forms then the process should be pretty much the same.
First, let's initialize a package.json
file and add some npm packages. You will need to have node installed on your machine. You can grab an installer for your OS on their downloads page. Next, open up a command line prompt at the root of your project.
To get to the command prompt quickly in Visual Studio, I recommend installing Mads Kristensen's Open Command Line extension. I use it all the time.
After the package.json
file is created, make sure you include it in your project. As you might already know, Visual Studio does not automatically add files that are placed in the project folder.
$ npm init
$ npm install toastr --save
Here I'm just installing toastr
, it's a handy little JavaScript library for going growl like notifications. In the Scripts
folder, I'll create a simple script called app.js
that'll create a notification.
toastr.info("this is just a test message");
Now, the toastr
JavaScript and CSS files need to be added to the page. Currently, they've both been installed into the node_modules
folder. Instead of referencing that path, I'll create a simple Gulp script that I can use to copy the toastr files out, and do any other processing I'd need for my site's front-end assets.
First, make sure that Gulp
is installed on the machine and in the project.
$ npm install --global gulp-cli
$ npm install --save-dev gulp gulp-concat
Now create the gulpfile.js
file.
const gulp = require('gulp');
const concat = require('gulp-concat');
const paths = {
nodeModules: './node_modules/',
scriptsDest: './Scripts/',
stylesDest: './Content/'
};
gulp.task('copy:css', () => {
const cssToCopy = [
`${paths.nodeModules}toastr/build/toastr.min.css`
];
return gulp.src(cssToCopy)
.pipe(concat('vendor.css'))
.pipe(gulp.dest(`${paths.stylesDest}`));
});
gulp.task('copy:js', () => {
const javascriptToCopy = [
`${paths.nodeModules}toastr/build/toastr.min.js`
];
return gulp.src(javascriptToCopy)
.pipe(concat('vendor.js'))
.pipe(gulp.dest(`${paths.scriptsDest}`));
});
gulp.task('default',['copy:css', 'copy:js'])
There are 2 simple Gulp
tasks here. One to copy the CSS files to the Content
folder and the other copies Javascript files to the Scripts
folder. To keep it simple, only the toastr
files are being copied over but you can add any other dependencies you've installed.
Running gulp
on the command line returns some output that looks like this.
Since these generated files aren't a part of the project, Visual Studio won't show them in the Solution Explorer by default. At the top of the Solution Explorer, click on the Show All Files
icon. You should see vendor.css
and vendor.js
greyed out under their respective folders. Right click on each file and choose Include In Project
.
Now you can just reference the files in your Razor template (or MasterPage if you're working with Web Forms).
Excluding node_modules from the project
If you followed through the last section and didn't skip ahead, you might have noticed that we included package.json
, vendor.js
and vendor.css
but not the node_modules
folder. Simply, excluding the node_modules
folder from the project will exclude it from the published web application.
Excluding node_modules via MSBUILD
You might have your own reasons why you want to include the node_modules
folder in the project. In that case, you exclude node_modules
(or any other folder) from being published by using the ExcludeFromPackageFolders
element.
First you'll need to unload your project from the solution and edit the project file. Next add an ExcludeFromPackageFolders
element to an ItemGroup element. Using the Include
attribute, you can provide a semicolon-separated list of folders that you want to exclude. For now, we're only interested in the node_modules
folder.
Note that we also include a FromTarget
element in our setup. This is an optional element and is only really there for descriptive purposes.
Once that's done, we'll save the file and reload the project. Doing a publish should now exclude the node_modules
folder even though it's included in the project.
Excluding files
With our current setup, the published output also includespackage.json
and gulpfile.js
. If you want to exclude these files from your published output, you can use a similar technique to the previous one using a ExcludeFromPackageFiles
element. The Include
property even supports globbing.
Now with all this in place, your NodeJS artifacts will not get included in your published web application.
Conclusion
If you're like me, you prefer to keep your published output at lean as possible. Excluding the node_modules
folder can greatly reduce the size of your deployed web application.
In general, I prefer not to let my project file know about the node_modules
folder at all. I find that projects load faster and I don't have to worry about ridiculously large commit messages in source control.