AspNet.AssetManager 4.4.1

dotnet add package AspNet.AssetManager --version 4.4.1
                    
NuGet\Install-Package AspNet.AssetManager -Version 4.4.1
                    
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="AspNet.AssetManager" Version="4.4.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AspNet.AssetManager" Version="4.4.1" />
                    
Directory.Packages.props
<PackageReference Include="AspNet.AssetManager" />
                    
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 AspNet.AssetManager --version 4.4.1
                    
#r "nuget: AspNet.AssetManager, 4.4.1"
                    
#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 AspNet.AssetManager@4.4.1
                    
#: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=AspNet.AssetManager&version=4.4.1
                    
Install as a Cake Addin
#tool nuget:?package=AspNet.AssetManager&version=4.4.1
                    
Install as a Cake Tool

AspNet.AssetManager

Build codecov NuGet Version NuGet Downloads License: MIT

Use Vite or Webpack with ASP.NET Core MVC and Razor Pages. AspNet.AssetManager reads your bundler's manifest and renders the correct <script> and <link> tags: from the dev server (with hot reload) in development, and from hashed static files in production.

<link-bundle fallback="Layout" />
<script-bundle defer fallback="Layout" />

Features

  • Tag helpers: <link-bundle />, <script-bundle /> and <style-bundle />.
  • Per-view bundles by convention: the bundle name is inferred from the view being rendered, e.g. Views/Home/Index.cshtml → Views_Home_Index.
  • Fallbacks: if a view has no bundle of its own, a shared one (e.g. Layout) is used.
  • Vite and Webpack: supports Vite manifests and key/value manifests such as webpack-assets-manifest.
  • Same markup in every environment: assets come from the dev server in development and from wwwroot in production.
  • Full Vite CSS: <link-bundle /> collects stylesheets from imported shared chunks, in the same order Vite applies them.
  • Targets .NET 8, 9 and 10.

Getting started

The quickest way to start is a project template from AspNet.Frontend.Templates. It sets up the .NET side and the bundler config for you:

dotnet new install AspNet.Frontend.Templates
dotnet new mvcvite   # also: mvcvitets, mvcwebpack(ts), razorvite(ts), razorwebpack(ts)

To add AspNet.AssetManager to an existing project, follow the steps below.

1. Install

dotnet add package AspNet.AssetManager

2. Register services

Program.cs:

using AspNet.AssetManager;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddAssetManager(builder.Configuration, builder.Environment);

var app = builder.Build();

app.UseStaticFiles();
// ...

3. Import the tag helpers

Views/_ViewImports.cshtml:

@addTagHelper *, AspNet.AssetManager

4. Render bundles in your layout

Views/Shared/_Layout.cshtml:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>@ViewData["Title"]</title>
  <link-bundle fallback="Layout" />
</head>
<body>
  @RenderBody()
  <script-bundle defer fallback="Layout" />
  @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Each page now loads its own bundle (Views_Home_Index, Views_Account_Login, ...) if one exists, and the Layout bundle if not.

5. Configure your bundler

Vite

appsettings.json:

{
  "AssetManager": {
    "PublicDevServer": "http://localhost:5173",
    "ManifestType": "Vite"
  }
}

vite.config.js. aspnet-buildtools finds the entry points for your views and serves a manifest from the Vite dev server:

import { viteConfig } from 'aspnet-buildtools';
import { defineConfig } from 'vite';

export default defineConfig({
  ...viteConfig,
  build: {
    ...viteConfig.build,
    assetsDir: '',
    manifest: 'assets-manifest.json', // must match AssetManager:ManifestFile
    outDir: 'wwwroot/dist',           // must match wwwroot + AssetManager:PublicPath
  },
  server: {
    cors: true,
  },
});

For hot module replacement, add the Vite client to your layout in development:

<environment include="Development">
  <script src="http://localhost:5173/@@vite/client" type="module"></script>
</environment>
Webpack

appsettings.json:

{
  "AssetManager": {
    "PublicDevServer": "http://localhost:9000"
  }
}

webpack.config.js, using webpack-assets-manifest and aspnet-buildtools:

import path from 'node:path';
import { webpackConfig } from 'aspnet-buildtools';
import { WebpackAssetsManifest } from 'webpack-assets-manifest';

export default {
  ...webpackConfig,
  output: {
    path: path.resolve(import.meta.dirname, 'wwwroot/dist'),
    filename: '[name]-[contenthash].js',
    publicPath: '/dist/',
  },
  plugins: [new WebpackAssetsManifest()],
  devServer: {
    headers: { 'Access-Control-Allow-Origin': '*' },
    port: 9000,
  },
};

Tag helpers

Tag helper Renders Attributes
<link-bundle /> One or more <link rel="stylesheet"> tags name, fallback
<script-bundle /> A <script src="..."> tag name, fallback, async, defer, module
<style-bundle /> An inline <style> tag with the bundle's CSS (useful for critical CSS) name, fallback
  • name: bundle to render. If omitted, it is resolved as described in Bundle names.
  • fallback: bundle to render if name cannot be found in the manifest.
  • module: adds type="module". Defaults to true for Vite manifests and false otherwise.

Nothing is rendered if neither bundle exists, so it is safe to put these tags in a shared layout.

Bundle names

The bundle for a tag helper is chosen in this order:

  1. The name attribute, e.g. <script-bundle name="Checkout" />.
  2. ViewData["Bundle"], set in a view or controller. A value starting with / is converted the same way as view paths: "/Some/Bundle" → Some_Bundle.
  3. The path of the view being rendered:
View Bundle name
Views/Home/Index.cshtml Views_Home_Index
Pages/Account/Login.cshtml Pages_Account_Login
Areas/Admin/Views/Users/Edit.cshtml Areas_Admin_Views_Users_Edit

If that bundle is not in the manifest, the fallback bundle is used.

aspnet-buildtools produces these names: a Views/Home/Index.cshtml.js (or .ts) next to a view becomes the Views_Home_Index entry, and any *.bundle.js file becomes a named bundle (Layout.bundle.js → Layout).

Configuration

All settings live in the AssetManager section of appsettings.json:

Setting Default Description
PublicDevServer — Required in development. The dev server URL the browser uses, e.g. http://localhost:5173.
InternalDevServer PublicDevServer The dev server URL the ASP.NET Core app uses to fetch the manifest. Set this when the app runs in Docker, WSL, etc. and reaches the dev server at a different address.
PublicPath /dist/ Base path for built assets, under wwwroot in production.
ManifestFile assets-manifest.json File name of the manifest, relative to PublicPath.
ManifestType KeyValue KeyValue (flat { "name.js": "name-hash.js" }, e.g. webpack-assets-manifest) or Vite.

Development vs. production

The app counts as being in development when IWebHostEnvironment.IsDevelopment() returns true.

Development Production
Manifest Fetched from the dev server on each request Read from wwwroot + PublicPath + ManifestFile once, then cached
Asset URLs PublicDevServer + PublicPath (Vite: PublicDevServer + /) PublicPath, served by UseStaticFiles()
Extra attributes crossorigin="anonymous" —

If the dev server is not running, a DevServerException ("Development server not started!") is thrown.

Rendering from code

For full control, inject IAssetService:

@using AspNet.AssetManager
@inject IAssetService AssetService

@{
    var bundle = ViewData.GetBundleName() ?? Html.GetBundleName();
}

@* Tags *@
@await AssetService.GetScriptTagAsync(bundle, "Layout", ScriptLoad.Defer)
@await AssetService.GetLinkTagAsync(bundle, "Layout")
@await AssetService.GetStyleTagAsync("Critical")

@* Paths *@
@AssetService.WebPath
@await AssetService.GetBundlePathAsync("SomeBundle.js")
@await AssetService.GetBundlePathAsync("SomeBundle", FileType.CSS)

ScriptLoad can be Normal, Async, Defer or AsyncDefer.

Building from source

The build uses NUKE:

./build.sh Test        # Windows: .\build.cmd Test

src/AspNet.AssetManager.Demo is a small Webpack-based MVC app for trying changes locally (npm install && npm start, then dotnet run).

License

MIT

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 is compatible.  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 is compatible.  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
4.4.1 38 10/10/2026
4.4.0 502 5/25/2026
4.3.2 147 5/22/2026
4.3.1 151 5/22/2026
4.3.0 824 1/8/2026
4.2.1 569 1/5/2026
4.2.0 850 10/15/2025
4.1.1 664 10/14/2025
4.1.0 649 10/14/2025
4.0.1 684 8/17/2025
4.0.0 660 8/14/2025
3.0.0 667 7/31/2025