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.