LayerZero.Tools.Web 2.1.0

dotnet add package LayerZero.Tools.Web --version 2.1.0
                    
NuGet\Install-Package LayerZero.Tools.Web -Version 2.1.0
                    
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="LayerZero.Tools.Web" Version="2.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LayerZero.Tools.Web" Version="2.1.0" />
                    
Directory.Packages.props
<PackageReference Include="LayerZero.Tools.Web" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add LayerZero.Tools.Web --version 2.1.0
                    
#r "nuget: LayerZero.Tools.Web, 2.1.0"
                    
#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.
#:package LayerZero.Tools.Web@2.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=LayerZero.Tools.Web&version=2.1.0
                    
Install as a Cake Addin
#tool nuget:?package=LayerZero.Tools.Web&version=2.1.0
                    
Install as a Cake Tool

📦 Dynamic Bundle Loader for ASP.NET Core

NuGet NuGet Downloads .NET


A convention-based asset bundling system for .NET 8+ with zero external framework dependencies. Automatically discovers and injects CSS/JS bundles per controller and action using Razor TagHelpers.

🧩 No WebOptimizer required.
✅ Self-contained bundle serving with built-in middleware.
✅ NUglify-powered minification and CSS/JS validation.


🔍 Purpose

Eliminates manual asset management in Razor views by scanning controller/action folder structures and auto-generating optimized bundles at runtime.


🗂 Folder Convention

wwwroot/
|   
+---css
|   |   site.css
|   |   
|   +---Controller
|   |   \---Home
|   |       |   Home.css
|   |       |   
|   |       +---Index
|   |       |       StyleSheet.css
|   |       |       
|   |       \---Privacy
|   |               StyleSheet.css
|   |               
|   \---critical
|           StyleSheet-cr1.css
|           StyleSheet-cr2.css
|           
+---js
|   |   site.js
|   |   
|   +---Controller
|   |   \---Home
|   |       |   Script.js
|   |       |   
|   |       +---Index
|   |       |       Script.js
|   |       |       
|   |       \---Privacy
|   |               flickity.pkgd.min.js
|   |               JavaScript.js
|   |               
|   \---critical
|           JavaScript-cr1.js
|           JavaScript-cr2.js
|           
\---lib

  • Controller/Action structure drives bundle discovery.
  • A special folder for critical CSS (wwwroot/css/critical)
  • A special folder for critical JS (wwwroot/js/critical)

⚙️ Installation

1. Add the NuGet Package

dotnet add package LayerZero.Tools.Web

Or reference the project directly:

dotnet add reference ../LayerZero.Tools.Web/LayerZero.Tools.Web.csproj

2. Dependencies

No external NuGet packages are required in your application. LayerZero.Tools.Web uses only:

  • NUglify (bundled — CSS/JS minification and validation)
  • Microsoft.AspNetCore.App framework reference

🚀 Usage

Register in Program.cs

builder.Services.AddDynamicBundle();

Or if you want to enable cache-busting on dev environment:

builder.Services.AddDynamicBundle(builder.Environment);

Enable Middleware

app.UseBundleServing();

🧠 TagHelpers

Register in _ViewImports.cshtml

@addTagHelper *, LayerZero.Tools.Web

Use in _Layout.cshtml

<head>
    <critical-style-bundle-loader/>
    <style-bundle-loader />
</head>
<body>
    @RenderBody()
    <critical-script-bundle-loader/>
    <script-bundle-loader />
</body>

Controller-wide assets load by default and are overridden by action-specific bundles if found.


💡 Features

✅ Convention-over-configuration
✅ Minification only in production
✅ Controller & action bundle granularity
✅ TagHelpers for clean layout injection
✅ Auto-registers bundles at startup
✅ Inline critical CSS (NUglify-minified)
✅ Inline critical JS (NUglify-validated)
✅ Cache-busting in development mode
✅ Zero external framework dependencies


⚠️ Known Limitations

  • Custom asset folder paths are not configurable via AddDynamicBundle().
  • Dynamic runtime configuration of asset logic is not exposed yet.
  • ✅ A static convention-based pathing system is in place (e.g., wwwroot/css/Controller/Action/...).

🔥 Critical CSS (v1.1.0+)

  • Combines all .css files under wwwroot/css/critical/ into a single <style> tag.
  • Injected above all other stylesheets.
  • CSS is minified via NUglify. If a file cannot be parsed at all, raw content is used as fallback.

Note: Critical CSS is also accessible as a plain HTTP route at /bundles/z-Critical.css (or /bundles/z-Critical.min.css when minification is enabled). This endpoint is served with full caching headers and can be useful for debugging or inspecting the inlined content.


🔥 Critical JS (v1.2.0+)

  • Combines all .js files under wwwroot/js/critical/ into one <script> tag.
  • Injected before all other scripts for optimal early execution.
  • JS is validated via NUglify. Files with syntax errors are skipped with a /* File X Skipped: reason */ comment in their place.

Note: Critical JS is also accessible as a plain HTTP route at /bundles/z-Critical.js (or /bundles/z-Critical.min.js). Same as for Critical CSS — useful for inspection, not intended as the primary delivery mechanism.


🆕 What's New in v2.1.0

Removed external parser dependencies

LayerZero.Tools.Web is now fully self-contained:

  • Removed LigerShark.WebOptimizer.Core — replaced with a built-in BundleStore (lazy ConcurrentDictionary cache) and BundleServingMiddleware. Update app.UseWebOptimizer()app.UseBundleServing().
  • Removed AngleSharp.Css — CSS parsing and formatting replaced with NUglify. Critical CSS is now minified inline rather than pretty-printed.
  • Removed Esprima — JS syntax validation replaced with NUglify. Behaviour is identical: valid JS is inlined as-is; invalid JS produces a skip comment.
  • Removed CssFileParser / JsFileParser (LayerZero.Tools.Web.Parser) — internal helpers superseded by BundleStore.Build(). If you referenced these classes directly, remove those usages.

Migration note: Replace app.UseWebOptimizer() with app.UseBundleServing() in your Program.cs.


🆕 What's New in v1.3.0

LayerZero.Tools.Web added Critical JavaScript support:

  • Place scripts in wwwroot/js/critical/
  • Files are parsed and rendered inline, before all standard JS bundles
  • Useful for early execution logic such as feature flags, layout adjustments, or performance-critical bootstraps

Critical JS handling mirrors Critical CSS introduced in v1.2.0, forming a complete early asset delivery strategy.


🚫 Cache-Busting in Development

To prevent browser caching during local testing, development mode appends ?v=<random> to asset URLs.

<link rel="stylesheet" href="/bundles/home.min.css?v=46174bc4-f61a-4382-a733-81ffe8c73074" />

In production, clean URLs are used for optimal caching.


✨ Example

Requesting /Home/Index loads:

<style>/* critical CSS injected here */</style>
<link rel="stylesheet" href="/bundles/home.min.css" />
<link rel="stylesheet" href="/bundles/home/index.min.css" />
<script>/* critical JS injected here */</script>
<script src="/bundles/home.min.js"></script>
<script src="/bundles/home/index.min.js"></script>

🛣 Upcoming

  • ✅ Custom JsRoot, CssRoot, CriticalCssRoot directories.
  • ✅ Optional feature toggles for minification, cache-busting, critical asset control.
  • ✅ Fluent configuration syntax.
builder.Services.AddDynamicBundle(new DynamicBundleConfig
{
    JsRoot = "wwwroot/assets/js",
    CssRoot = "wwwroot/assets/css",
    CriticalCssRoot = "wwwroot/assets/critical",
    EnableCacheBusting = true
});

👤 Author

LayerZero Team — Built for clean architecture and developer clarity.

Product Compatible and additional computed target framework versions.
.NET 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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.0 98 5/16/2026
2.0.0 114 2/26/2026
1.3.0 165 7/5/2025
1.2.0 147 6/28/2025
1.1.1 181 6/22/2025
1.1.0 178 6/22/2025
1.0.1 261 6/13/2025
1.0.0 362 6/11/2025