LigerShark.WebOptimizer.Core 3.0.426

Prefix Reserved
dotnet add package LigerShark.WebOptimizer.Core --version 3.0.426                
NuGet\Install-Package LigerShark.WebOptimizer.Core -Version 3.0.426                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LigerShark.WebOptimizer.Core" Version="3.0.426" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add LigerShark.WebOptimizer.Core --version 3.0.426                
#r "nuget: LigerShark.WebOptimizer.Core, 3.0.426"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install LigerShark.WebOptimizer.Core as a Cake Addin
#addin nuget:?package=LigerShark.WebOptimizer.Core&version=3.0.426

// Install LigerShark.WebOptimizer.Core as a Cake Tool
#tool nuget:?package=LigerShark.WebOptimizer.Core&version=3.0.426                

ASP.NET Core Web Optimizer

Build status NuGet

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.

Check out the demo website or its source code.

Versions

Master is being updated for ASP.NET Core 3.0 For ASP.NET Core 2.x, use the 2.0 branch.

Content

How it works

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.

For instance, the pipeline for a single .css file could be orchestrated to first goes through minification, then through fingerprinting and finally through image inlining before being sent to the browser.

WebOptimizer makes sure that the pipeline is orchestrated for maximum performance and compatability out of the box, yet at the same time allows for full customization and extensibility.

The pipeline is set up when the ASP.NET web application starts, but no output is being 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.

Install and setup

Add the NuGet package LigerShark.WebOptimizer.Core to any ASP.NET Core 2.0 project.

dotnet add package LigerShark.WebOptimizer.Core 

Then in Startup.cs, add app.UseWebOptimizer() to the Configure method anywhere before app.UseStaticFiles (if present), like so:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseWebOptimizer();

    app.UseStaticFiles();
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

That sets up the middleware that handles the requests and transformation of the files.

And finally modify the ConfigureServices method by adding a call to services.AddWebOptimizer():

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddWebOptimizer();
}

The service contains all the configuration used by the middleware and allows your app to interact with it as well.

That's it. You have now enabled automatic CSS and JavaScript minification. No other code changes are needed for enabling this.

Try it by requesting one of your .css or .js files in the browser and see if it has been minified.

Disabling minification:
If you want to disable minification (e.g. in development), the following overload for AddWebOptimizer() can be used:

if (env.IsDevelopment())
{
    services.AddWebOptimizer(minifyJavaScript:false,minifyCss:false);
}

Minification

To control the minification in more detail, we must interact with the pipeline that manipulates the file content.

Minification is the process of removing all unnecessary characters from source code without changing its functionality in order to make it as small as possible.

For example, perhaps we only want a few certain JavaScript files to be minified automatically. Then we would write something like this:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddWebOptimizer(pipeline =>
    {
        pipeline.MinifyJsFiles("js/a.js", "js/b.js", "js/c.js");
    });
}

Notice that the paths to the .js files are relative to the wwwroot folder.

We can do the same for CSS, but this time we're using a globbing pattern to allow minification for all .css files in a particular folder and its sub folders:

pipeline.MinifyCssFiles("css/**/*.css");

When using globbing patterns, you still request the .css files on their relative path such as http://localhost:1234/css/site.css.

Setting up automatic minification like this doesn't require any other code changes in your web application to work.

Under the hood, WebOptimizer uses NUglify to minify JavaScript and CSS.

Bundling

To bundle multiple source file into a single output file couldn't be easier.

Bundling is the process of taking multiple source files and combining them into a single output file. All CSS and JavaScript bundles are also being automatically minified.

Let's imagine we wanted to bundle /css/a.css and /css/b.css into a single output file and we want that output file to be located at http://localhost/css/bundle.css.

Then we would call the AddCssBundle method:

services.AddWebOptimizer(pipeline =>
{
    pipeline.AddCssBundle("/css/bundle.css", "css/a.css", "css/b.css");
});

The AddCssBundle method will combine the two source files in the order they are listed and then minify the resulting output file. The output file /css/bundle.css is created and kept in memory and not as a file on disk.

To bundle all files from a particular folder, we can use globbing patterns like this:

services.AddWebOptimizer(pipeline =>
{
    pipeline.AddCssBundle("/css/bundle.css", "css/**/*.css");
});

When using bundling, we have to update our <script> and <link> tags to point to the bundle route. It could look like this:

<link rel="stylesheet" href="/css/bundle.css" />

Content Root vs. Web Root

By default, all bundle source files are relative to the Web Root (wwwroot) folder, but you can change it to be relative to the Content Root instead.

The Content Root folder is usually the project root directory, which is the parent directory of wwwroot.

As an example, lets create a bundle of files found in a folder called node_modules that exist in the Content Root:

services.AddWebOptimizer(pipeline =>
{
    pipeline.AddCssBundle("/css/bundle.css", "node_modules/jquery/dist/*.js")
            .UseContentRoot();
});

The UseContentRoot() method makes the bundle look for source files in the Content Root rather than in the Web Root.

To use a completely custom IFileProvider, you can use the UseFileProvider pipeline method.

services.AddWebOptimizer(pipeline =>
{
    var provider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(@"C:\path\to\my\root\folder");
    pipeline.AddJavaScriptBundle("/js/scripts.js", "a.js", "b.js")
        .UseFileProvider(provider);
});

Tag Helpers

WebOptimizer ships with a few Tag Helpers that helps with a few important tasks.

Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.

First, we need to register the TagHelpers defined in LigerShark.WebOptimizer.Core in our project.

To do that, go to _ViewImports.cshtml and register the Tag Helpers by adding @addTagHelper *, WebOptimizer.Core to the file.

@addTagHelper *, WebOptimizer.Core
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Cache busting

As soon as the Tag Helpers are registered in your project, you'll notice how the <script> and <link> tags starts to render a little differently when they are referencing a file or bundle.

NOTE: Unlike other ASP.NET Core Tag Helpers, <script> and <link> tags don't need an asp- attribute to be rendered as a Tag Helper.

They will get a version string added as a URL parameter:

<link rel="stylesheet" href="/css/bundle.css?v=OFNUnL-rtjZYOQwGomkVMwO415EOHtJ_Tu_s0SIlm9s" />

This version string changes every time one or more of the source files are modified.

NOTE: TagHelpers will only work on files registered as assets on the pipeline (will not work for all files in your <sctipt> and <link> tags out of the blue). make sure to add all required files as assets (glob is supported to add wildcard paths).

services.AddWebOptimizer(pipeline =>
{
    pipeline.AddFiles("text/javascript", "/dist/*");
    pipeline.AddFiles("text/css", "/css/*");
});

This technique is called cache busting and is a critical component to achieving high performance, since we cannot utilize browser caching of the CSS and JavaScript files without it. That is also why it can not be disabled when using WebOptimizer.

HTTPS Compression Considerations

When utilized with the services.AddResponseCompression middleware included in the Feature, it's important to note that by default the cache busted assets may not be included as the Response Header: content-type is modified from the default application/javascript to text/javascript, which is not a supported default ResponseCompressionDefaults.MimeTypes before ASP.NET Core 7.0 and can be added in the Startup.ConfigureServices like so:

services.AddResponseCompression( options => {
    options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
        new[] { "text/javascript"}
    );
});

Note: app.UseResponseCompression() should be used prior to app.UseWebOptimizer()

Note: If you're using ASP.NET Core 7.0 or later, you don't need to add this, as support for text/javascript is included by default.

Inlining content

We can also use Web Optimizer to inline the content of the files directly into the Razor page. This is useful for creating high-performance websites that inlines the above-the-fold CSS and lazy loads the rest later.

To do this, simply add the attribute inline to any <link> or <script> element like so:

<link rel="stylesheet" href="/css/bundle.css" inline />
<script src="/any/file.js" inline></script>

There is a Tag Helper that understands what the inline attribute means and handles the inlining automatically.

Compiling Scss

WebOptimizer can also compile Scss files into CSS. For that you need to install the LigerShark.WebOptimizer.Sass NuGet package and hooking it up is a breeze. Read more on the WebOptimizer.Sass website.

Options

You can control the options from the appsettings.json file or in code

{
  "webOptimizer": {
    "enableCaching": true,
    "enableMemoryCache": true,
    "enableDiskCache": true,
    "cacheDirectory": "/var/temp/weboptimizercache",
    "enableTagHelperBundling": true,
    "cdnUrl": "https://my-cdn.com/",
    "allowEmptyBundle": false
  }
}
services.AddWebOptimizer(pipeline =>
    {
        pipeline.AddCssBundle("/css/bundle.css", "css/*.css");
        pipeline.AddJavaScriptBundle("/js/bundle.js", "js/plus.js", "js/minus.js");
    },
    option =>
    {
        option.EnableCaching = true;
        option.EnableDiskCache = false;
        option.EnableMemoryCache = true;
        option.AllowEmptyBundle = true;
    });

enableCaching determines if the cache-control HTTP headers should be set and if conditional GET (304) requests should be supported. This could be helpful to disable while in development mode.

Default: true

enableTagHelperBundling determines if <script> and <link> elements should point to the bundled path or a reference per source file should be created. This is helpful to disable when in development mode.

Default: true

enableMemoryCache determines if the IMemoryCache is used for caching. Can be helpful to disable while in development mode.

Default: true

enableDiskCache determines if the pipeline assets are cached to disk. This can speed up application restarts by loading pipline assets from the disk instead of re-executing the pipeline. Can be helpful to disable while in development mode.

Default: true

cacheDirectory sets the directory where assets will be stored if enableDiskCache is true. Must be read/write.

Default: <ContentRootPath>/obj/WebOptimizerCache

cdnUrl is an absolute URL that, if present, is automatically adds a prefix to any script, stylesheet or media file on the page. A Tag Helper adds the prefix automatically when the Tag Helpers have been registered. See how to register the Tag Helpers here.

For example. if the cdnUrl is set to "http://my-cdn.com" then script and link tags will prepend the cdnUrl to the references. For instance, this script tag:

<script src="/js/file.js"></script>

...will become this:

<script src="http://my-cdn.com/js/file.js"></script>

allowEmptyBundle determines the behavior when there is no content in source file of a bundle, by default 404 exception will be thrown when the bundle is requested, set to true to get a bundle with empty content instead.

Default: false

Custom pipeline

Read more in the custom pipeline documentation.

Extend

Extensions can hook up new transformations and consume existing ones.

A good extension to look at is the WebOptimizer.Sass extension. It demonstrates how to write a processor and how to write extension methods that makes it easy to hook it up to the pipeline.

Plugins

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (19)

Showing the top 5 NuGet packages that depend on LigerShark.WebOptimizer.Core:

Package Downloads
FenixAlliance.ACL.Dependencies

Application Component for the Alliance Business Suite.

LigerShark.WebOptimizer.Sass

Compiles Sass and Scss files for the LigerShark.WebOptimizer.Core system.

LigerShark.WebOptimizer.NodeServices

Base classes for Node.js based processors for the LigerShark.WebOptimizer.Core system.

codeessentials.WebOptimizer.Dotless

Compiles Less files for the LigerShark.WebOptimizer.Core system.

JJMasterData.Web

JJMasterData is a codeless CRUD Generator from database metadata. This package contains the Data Dictionary Razor Class Library with all necessary packages.

GitHub repositories (6)

Showing the top 5 popular GitHub repositories that depend on LigerShark.WebOptimizer.Core:

Repository Stars
nopSolutions/nopCommerce
ASP.NET Core eCommerce software. nopCommerce is a free and open-source shopping cart.
skimedic/presentations
Copy of my public presentations
VahidN/DNTIdentity
A highly customized sample of the ASP.NET Core Identity
madskristensen/PhotoGallery
ASP.NET Core Photo Gallery
JJConsulting/JJMasterData
.NET CRUD generator library with Bootstrap support to create dynamic forms at runtime from a data dictionary.
Version Downloads Last updated
3.0.426 71,510 8/8/2024
3.0.422 10,331 7/31/2024
3.0.420 6,092 7/30/2024
3.0.418 2,037 7/29/2024
3.0.413 45,648 7/3/2024
3.0.405 358,822 2/12/2024
3.0.403 34,358 2/6/2024
3.0.396 306,983 10/9/2023
3.0.391 164,831 9/5/2023
3.0.386 68,261 8/8/2023
3.0.384 361,681 3/23/2023
3.0.380 70,772 3/6/2023
3.0.378 38,740 2/22/2023
3.0.372 769,962 9/28/2022
3.0.368 310,623 7/20/2022
3.0.365 327,820 6/1/2022
3.0.357 536,990 2/7/2022
3.0.352 8,676 2/3/2022
3.0.348 135,277 1/13/2022
3.0.344 204,602 12/17/2021
3.0.335 53,767 11/29/2021
3.0.330 47,028 11/10/2021
3.0.327 25,016 11/2/2021
3.0.319 112,583 8/25/2021
3.0.313 20,239 8/11/2021
3.0.311 132,195 5/24/2021
3.0.307 15,801 5/19/2021
3.0.304 77,995 3/15/2021
3.0.295 53,644 10/28/2020
3.0.279 40,866 7/24/2020
3.0.276 21,548 7/14/2020
3.0.250 95,078 9/25/2019
3.0.249 20,311 9/25/2019
3.0.248 1,671 8/20/2019
1.0.236 71,508 1/2/2019
1.0.215 27,996 4/8/2018
1.0.201 11,843 2/8/2018
1.0.197 13,627 11/21/2017
1.0.196 1,746 11/21/2017
1.0.189 5,338 11/13/2017
1.0.178-beta 1,692 11/7/2017
1.0.177-beta 1,470 10/30/2017
1.0.175-beta 7,845 10/18/2017
1.0.174-beta 1,676 10/16/2017
1.0.173-beta 1,874 10/12/2017
1.0.172-beta 1,451 9/19/2017
1.0.169-beta 1,600 9/14/2017
1.0.168-beta 1,483 9/14/2017
1.0.165-beta 3,075 9/9/2017
1.0.164-beta 1,470 9/8/2017
1.0.162-beta 1,489 8/28/2017
1.0.158-beta 1,533 8/24/2017
1.0.155-beta 1,653 8/24/2017
1.0.153-beta 1,602 8/23/2017
1.0.150-beta 1,494 8/23/2017
1.0.145-beta 1,537 8/22/2017
1.0.144-beta 1,566 8/21/2017
1.0.143-beta 1,568 8/21/2017
1.0.142-beta 1,446 8/18/2017
1.0.141-beta 1,538 8/17/2017
1.0.133-beta 1,540 8/16/2017
1.0.132-beta 1,427 8/15/2017
1.0.131-beta 1,452 8/15/2017
1.0.129-beta 1,431 8/15/2017
1.0.128-beta 1,549 8/15/2017
1.0.121-beta 1,597 8/11/2017
1.0.118-beta 1,463 8/11/2017
1.0.116-beta 1,585 8/11/2017
1.0.115-beta 1,608 8/10/2017