CSS and JavaScript bundling and minification for ASP.NET Core and classic ASP.NET (System.Web).
In development, source files are served individually for easy debugging. In production, they are concatenated, minified via NUglify, and served as a single file.
dotnet add package DragonBundles
In Program.cs:
builder.Services.AddBundling();
// ...
app.UseBundling(bundles =>
{
bundles
.AddStyleBundle("site", "/css/base.css", "/css/layout.css")
.AddScriptBundle("app", "/js/utils.js", "/js/app.js");
});In _ViewImports.cshtml:
@addTagHelper *, DragonBundles<head>
<style-bundle name="site"></style-bundle>
</head>
<body>
...
<script-bundle name="app"></script-bundle>
</body>In Development, each source file gets its own tag:
<link rel="stylesheet" href="/css/base.css" data-bundle="site" />
<link rel="stylesheet" href="/css/layout.css" data-bundle="site" />In Production, a single minified bundle is rendered with a Subresource Integrity hash:
<link rel="stylesheet" href="/bundles/css/site.min.css?v=a1b2c3d4" integrity="sha384-..." crossorigin="anonymous" data-bundle="site" />The ?v=... suffix is a content hash for cache busting, updated automatically whenever source files change. The integrity attribute is a SHA-384 hash of the bundle bytes the browser uses to verify the response wasn't tampered with.
Bundles are minified at startup and served in-memory β no files are written to disk. In non-Development environments, source files are watched for changes and re-minified automatically without a restart.
Relative url() references in CSS files are rewritten to absolute paths before minification, so stylesheets from different directories compose correctly.
Source file paths accept glob patterns:
bundles.AddStyleBundle("site", "/css/**/*.css");Missing source files throw FileNotFoundException at startup.
DragonBundles integrates with System.Web.Optimization as a drop-in upgrade, replacing the default WebGrease minifier with NUglify.
In BundleConfig.cs:
using DragonBundles;
public static void RegisterBundles(BundleCollection bundles)
{
bundles.AddStyleBundle("site", "~/Content/base.css", "~/Content/layout.css");
bundles.AddScriptBundle("app", "~/Scripts/utils.js", "~/Scripts/app.js");
}In Razor views, add @using DragonBundles (or add it to Web.config), then:
<head>
@Html.StyleBundle("site")
</head>
<body>
...
@Html.ScriptBundle("app")
</body>Dev/prod rendering is controlled by BundleTable.EnableOptimizations β individual files in debug, single bundle in release, matching standard System.Web.Optimization behavior.
DragonBundles is designed to smooth this migration. Bundle names are consistent across both runtimes β swap the registration and rendering calls when you upgrade, and bundle names stay the same.
| Target | Runtime |
|---|---|
net10.0 |
.NET 10, ASP.NET Core |
net48 |
.NET Framework 4.8, ASP.NET MVC 5 |