A Step by Step Guide to Bundling and Minification in ASP.NET Core
Tags: dotnet, aspnetcore, bundling, minification
Published: 2021-08-29 09:26:02

It is the dream of every web developer to build blazing fast and high-performance web applications but this is not easy to accomplish unless we implement some performance optimizations. Web pages have evolved from static HTML pages to complex and responsive pages with a lot of dynamic contents and plugins which require a large number of CSS and JavaScript files to be downloaded to the clients. To improve the initial page request load time, we normally apply two performance techniques called bundling and minification. In this tutorial, I will give you a step by step overview of different tools and techniques we can use to apply bundling and minification in ASP.NET Core 5 applications.

[Download Source Code](https://github.com/ezzylearning/AspNetCoreBundleMinifyDemo)

## Introduction To Bundling and Minification

Bundling and minification are two distinct performance optimizations we can use in our web apps to improve the performance of our apps and to reduce the number of requests from the browser to server and to reduce the size of data transferred from server to browser. If these two techniques are used together they improve the load time of our page on the first request. Once the page has been requested and loaded into the browser, the browser caches the static files e.g. JavaScript, CSS, and images so this improves the overall user experience.

## Bundling

Bundling is a process of combining multiple files into a single file. The benefit is that the browser needs to make fewer requests for all those separate files and needs to load just a single file from the server. We can have separate bundles for CSS and JavaScript files and we can even have separate bundles for third-party plugins, scripts, and styles.

![ASP.NET Core Bundling](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9yd7wf7k9qq5y1ffxyz3.png)

## Minification

Minification is the process of removing unnecessary comments, spaces, and extra characters from the code without altering any functionality. This means we can reduce the file size significantly which increases the file load time from server to client.

![ASP.NET Core Minification](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4d28md0n6bo2e4i13x16.png)

The following table ([available at the official docs page](https://docs.microsoft.com/en-us/aspnet/core/client-side/bundling-and-minification?view=aspnetcore-5.0)) outlines the differences between individually loading assets and using bundling and minification on a local machine. You can expect even greater performance gains when bundled and minified assets are transferred over the network.

<table><thead><tr><td><strong>Action</strong></td><td><strong>With<br>Bundling and Minification</strong></td><td><strong>Without<br>Bundling and Minification</strong></td><td><strong>Change</strong></td></tr></thead><tbody><tr><td>File Requests</td><td>7</td><td>18</td><td>157%</td></tr><tr><td>KB Transferred</td><td>156</td><td>264.68</td><td>70%</td></tr><tr><td>Load Time (ms)</td><td>885</td><td>2360</td><td>167%</td></tr></tbody></table>

## Bundling and Minification Strategies in ASP.NET Core

In old days, we were using a different technique to register all our bundles in **BundleConfig.cs** file available in **App\_Start** folder. A method called **RegisterBundles** in ASP.NET was used to create, register, and configure bundles as follows:
```
public static void RegisterBundles(BundleCollection bundles)
{   
    bundles.Add(new ScriptBundle("~/bundles/js").Include(
      "~/Scripts/bootstrap.js",
      "~/Scripts/jquery-3.3.1.js"));
}
```
We were including above bundles in our Web pages, Views and Layout Pages as follows:
```
<head>
    <title>@ViewBag.Title</title>
    
    @Scripts.Render("~/bundles/js")
</head>
```
While this approach looks easy to use, it’s no longer applicable in ASP.NET 5. The new ASP.NET Core project templates in Visual Studio provide a solution for bundling and minification using a JSON configuration file called **bundleconfig.json**. There are also some NuGet Packages and Visual Studio extensions that can help us in bundling and minification. If you need a more advanced bundling and minification solution or your workflow requires processing beyond bundling and minification then you have the option of using third-party tools or task runners such as Gulp, Grunt or Webpack, etc.

Another important aspect is to decide whether you want to do bundling and minification at design time or run time. Design time bundling and minification will allow you to create minified files before application deployment which will reduce server load time. However, the downside is that the design time bundling and minification only work with static files and it will also increase the build complexity.

## **Configure Bundles using bundleconfig.json File**

In ASP.NET Core we typically add our static files in the **wwwroot** folder. There is a folder **css** for CSS files, a folder **js** for JavaScript files, and a third folder **lib** for external libraries such as JQuery, bootstrap, etc. To start bundling and minification, the first you need is a **bundleconfig.json** file so let’s add this file using the standard Add New Item dialog in Visual Studio.

![Add bundleconfig JSON file in Visual Studio 2019](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bbj8ym17hwb8r1nztzag.png)

Typically, we add this file to our project root folder.

![Solution Explorer with bundleconfig JSON file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w3mwr8ysiz643za8e72h.png)

Here's an example of how the contents of **bundleconfig.json** look like in the default template:
```
[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/lib/bootstrap/dist/css/bootstrap.css",
      "wwwroot/css/site.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    },
    "sourceMap": false
  }
]
```
It is not very difficult to understand the JSON available in the bundleconfig.json file. There is a JSON object for each bundle we want to configure and there are some options available related to each bundle e.g. **outputFileName**, **inputFiles** etc. The default template has a single bundle configuration for custom JavaScript **wwwroot/js/site.js** and a single bundle configuration for custom stylesheet **wwwroot/css/site.css** files.
```
{
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/lib/bootstrap/dist/css/bootstrap.css",
      "wwwroot/css/site.css"
    ]
}
```
Some of the common options available are the following:

**outputFileName:** This is a required option and this specifies the name of the output bundle file. It can contain a relative path from the bundleconfig.json file.

**inputFiles**: This is an array of files we want to bundle together and it can also contain relative paths from the bundleconfig.json file. This option is not required so if you will not specify any input file, an empty output file will be generated.

**minify**: This is another optional setting and it specifies whether we want to enable minification or not. The default value is enabled: true.

**sourceMap**: This option indicates whether a source map for the bundled file should be generated or not. The default value is false.

**includeInProject**: This option specifies whether to add generated files to the project file. The default value is false. Let’s modify the default template and include both bootstrap and jquery into the generated bundle files. I have also renamed the output file name from **site** to **main**.
```
[
  {
    "outputFileName": "wwwroot/css/main.min.css",
    "inputFiles": [
      "wwwroot/lib/bootstrap/dist/css/bootstrap.css",
      "wwwroot/css/site.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/main.min.js",
    "inputFiles": [
      "wwwroot/lib/jquery/dist/jquery.js",
      "wwwroot/lib/bootstrap/dist/js/bootstrap.js",
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    },
    "sourceMap": false
  }
]
```
## **Bundling and Minification using BuildBundlerMinifier Package**

In the previous section, we added the bundleconfig.json file and configure our bundles in this JSON file. If you will build your project in Visual Studio, nothing will happen and no bundles will be generated. This is because you need to install a NuGet package called BuildBundlerMinifier to let Visual Studio and .NET know that they need to build your bundles. You can install this package from the NuGet package manager available within Visual Studio.

![Install BuildBundleMinifier Nuget Package](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3c8yvxiayxzut2tbcrbk.png)

Once the package is installed, build your project and you will now see your bundled and minified files generated in the folder specified in bundleconfig.json. 

![Solution Explorer showing Minified JS and CSS files](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/przrzyqw7n52me27lvph.png)

## **Environment-based Bundling and Minification**

I am sure you would like to use the non-bundles and non-minified files in the development environment because they will make your life much easier during debugging. As a best practice, you should use the bundled files only in the production environment. You can specify which file to use in which environment by using **Environment** Tag Helper. If you want to learn more about Tag Helpers then you can read my post [A Developer Guide to ASP.NET Core Tag Helpers](https://www.ezzylearning.net/tutorial/a-developer-guide-to-asp-net-core-tag-helpers).

The Environment Tag Helper only renders its contents when the application is running in specific environments. The following code snippet shows how to use environment tag helper to render non-bundled files in the Development environment and bundled files when the environment is not Development such as Production or Staging. You can add the following environment tag helper in **_Layout.cshtml** file.
```
<environment include="Development">
  <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
  <link rel="stylesheet" href="~/css/site.css" />
</environment>

<environment exclude="Development">
  <link rel="stylesheet" href="~/css/main.min.css" asp-append-version="true" />
</environment>
```
We can use same environment tag helper to render our JavaScript files as follows:
```
<environment include="Development">
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
</environment>

<environment exclude="Development">
    <link rel="stylesheet" href="~/js/main.min.js" asp-append-version="true" />
</environment>
```
If you will build and run your project now, you will see the following CSS and JavaScript files will be included on your website. This is because you are currently in the Development environment.
```
<link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="/css/site.css" />
...
...
...
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="/js/site.js?v=4q1jwFhaPaZgr8"></script>
```
You can change your environment from Development to Production using the project properties dialog as shown in the following screenshot.

![Change Environment from Development to Production in Visual Studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h0210y1iv4xcivcu78c1.png)

If you will run your project again, you will see the following bundled and minified files are included on your web page.
```
<link rel="stylesheet" href="/css/main.min.css?v=GEO9YOMPwE4" />
...
...
...
<link rel="stylesheet" href="/js/main.min.js?v=AHmIHyQd" />
```
## **Using Bundler & Minifier Visual Studio Extension**

If you are using Visual Studio, it is a good idea to automate the bundling and minification process using a Visual Studio extension [Bundler & Minifier](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier) developed by [Mads Kristensen](https://github.com/madskristensen). This extension allows us to select and bundle files without writing a single line of code. You can download and install this extension from [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier). You may be asked to close Visual Studio and re-open it during the installation of the extension.  
  
Please note that if you want to use this extension then you don’t need the BuildBundlerMinifier NuGet package anymore. You can uninstall the BuildBundlerMinifier package from your project.

If you will right-click on the bundleconfig.json file, you will see some new “Bundler & Minifier” related options available to you. You can Delete Bundle Output Files, Update Bundles, etc.

![Bundler & Minifier Visual Studio 2019 Extension Options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oaooo2a911povb2bd8es.png)

Similarly, if you will select and right-click on a single bundled file such as **main.min.css**, you should see the option to “**Re-minify File**” or an option to remove the file from bundling.

![Reminify bundle file in Visual Studio using Bundle and Minifier Extension](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esgi1rtwxxb2evejem0h.png)

This extension will also make your bundleconfig.json file recognizable in Task Runner Explorer. This will allow us to run bundling from Task Runner Explorer manually or we can trigger bundling when certain Visual Studio events occur such as Before or After Build.

![Task Runner Explorer shows bundleconfig JSON file in Visual Studio 2019](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ysa3ns3btaj6m9pmdb3.png)

To execute the bundle from Task Runner Explorer, right-click on “**Update all files**” option and click “**Run**” option and you will see the bundled files are generated in your project Solution Explorer.

![Bundling and Minification using Task Runner Explorer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rqmje1xjzk5b3gxolujz.png)

## **Summary**

In this tutorial, I have given you a basic overview of bundling and minification. I have also shown you some packages, tools, and extensions available for handling bundling and minification in our projects. If you need more than bundling and minification such as linting, image optimization, cache busting, CDN, and so on then you can use task runners such as Gulp, Grunt, or Webpack. I will show you how to Gulp for bundling and minification in my next post.