All Articles

Bundling and Minification of CSS and JS Files for an ASP.NET Core solution

Bundling

Bundling combines multiple files into a single file. Bundling reduces the number of server requests that are necessary to render a web asset, such as a web page. You can create any number of individual bundles specifically for CSS, JavaScript, etc. Fewer files mean fewer HTTP requests from the browser to the server or from the service providing your application. This results in improved first-page load performance.

Minification

Minification removes unnecessary characters from code without altering functionality. The result is a significant size reduction in requested assets (such as CSS, images, and JavaScript files). Common side effects of minification include shortening variable names to one character and removing comments and unnecessary whitespace.

In ASP.NET MVC, we could use BundleConfig to bundle and optimize Javascript files. Other solutions include tools like Gulp to minify Javascript and CSS files.

In ASP.NET Core, we do not have BundleConfig. Hence, we have to use either Gulp scripts or the open-source WebOptimizer.

ASP.NET Core Web Optimizer

ASP.NET Core middleware for bundling and minification of CSS and JavaScript files at runtime. With full server-side and client-side caching to ensure high performance. No complicated build process and no hassle.

Refer to their GitHub page: https://github.com/ligershark/WebOptimizer

WebOptimizer sets up a pipeline for static files so they can be transformed (minified, bundled, etc.) before sent to the browser. This pipeline is highly flexible and can be used to combine many different transformations to the same files.

The pipeline is set up when the ASP.NET web application starts, but no output is generated until the first time they are requested by the browser. The output is then being stored in memory and served very fast on all subsequent requests. This also means that no output files are being generated on disk.

Steps to configure ASP.NET Core Web Optimizer

  1. Install the LigerShark.WebOptimizer.Core NuGet package.

    Use the below command:

    dotnet add package LigerShark.WebOptimizer.Sass

    Or from the NuGet Package Manager window:

    weboptimizer-nuget-listing

  2. Go to Startup.cs and add the below line in the Configure method.

    Ensure to add the line before UseStaticFiles() is called.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
       if (env.IsDevelopment())
       {
           app.UseDeveloperExceptionPage();
       }
       else
       {
           app.UseExceptionHandler("/Home/Error");
       }
    
       app.UseWebOptimizer(); //Add this line
    
       app.UseStaticFiles();
    
       app.UseRouting();
    
       app.UseAuthorization();
    
       app.UseEndpoints(endpoints =>
       {
           endpoints.MapControllerRoute(
               name: "default",
               pattern: "{controller=Home}/{action=Index}/{id?}");
       });
    }
  3. Create an installer file for Serilog configuration. (or you can also add the below code in the ConfigureServices method in Startup.cs)

    For information on how to use Installer files, refer to my post on Lamar.

    using Lamar;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using System;
    
    namespace Project.Web.Installers
    {
       public class WebOptimizerInstaller : IInstaller
       {
           public void InstallServices(ServiceRegistry services, IConfiguration configuration)
           {
               services.AddWebOptimizer(pipeline =>
               {
                   pipeline.AddJavaScriptBundle("/js/site.js", "js/a.js", "js/b.js");
                   pipeline.AddCssBundle("/css/site.css", "css/a.css", "css/b.css");
               });
           }
       }
    }
  4. Add the below line in _ViewImports.cshtml.

    @addTagHelper *, WebOptimizer.Core
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
  5. So when you hit http://site-endpoint/js/site.js, you get a bundle Javascript file with the contents from a.js and b.js.

    Similarly, when you hit http://site-endpoint/css/site.css, you get a bundle CSS file with the contents from a.css and b.css.

  6. To include files in a folder with a pattern, you can also use the below code:

    pipeline.AddCssBundle("/css/site.css", "css/**/*css");
    pipeline.AddJavaScriptBundle("/js/site.js", "js/**/*.js");
  7. You can also use the below code to minify your CSS and JS files as requested.

    Pass file names to the method, if you want to specifically minify files.

    // => For minifying all CSS files
    pipeline.MinifyCssFiles(); 
    
    // => For minifying specific CSS files
    pipeline.MinifyCssFiles("site-a.css", "site-b.css"); 
    
    // => For minifying all JS files
    pipeline.MinifyJsFiles();
    
    // => For minifying all JS files
    pipeline.MinifyJsFiles("site-a.js", "site-b.js");
  8. You may want to minify your files only for the Non-development environments. The code will look like below in the end:

    using Lamar;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using System;
    
    namespace Project.Web.Installers
    {
       public class WebOptimizerInstaller : IInstaller
       {
           public void InstallServices(ServiceRegistry services, IConfiguration configuration)
           {
               string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
               bool isDevelopment = environment == Environments.Development;
               services.AddWebOptimizer(pipeline =>
               {
                   pipeline.AddCssBundle("/css/site.css", "css/**/*css");
                   pipeline.AddJavaScriptBundle("/js/site.js", "js/**/*.js");
                   if (!isDevelopment)
                   {
                       pipeline.MinifyCssFiles();
                       pipeline.MinifyJsFiles();
                   }
               });
           }
       }
    }

As the files are being served by Memory Cache, the performance also will be high. No build tasks are required to save the compiled files, they are served dynamically.

References

  1. ASP.Net Core Web Optimizer Github Repository.

Please drop a comment below if you have any queries.