Skip to content

Commit

Permalink
Bundler Minify update (#2992)
Browse files Browse the repository at this point in the history
* update doc

* update static and samples
  • Loading branch information
spboyer authored and Rick-Anderson committed Mar 17, 2017
1 parent 56e3b55 commit 31f5f9c
Show file tree
Hide file tree
Showing 26 changed files with 679 additions and 54 deletions.
187 changes: 133 additions & 54 deletions aspnetcore/client-side/bundling-and-minification.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,34 @@
---
title: Bundling and minification in ASP.NET Core | Microsoft Docs
author: rick-anderson
author: spboyer
description:
keywords: ASP.NET Core,
keywords: ASP.NET Core, Bundling and Minification, CSS, JavaScript, Minify, BuildBundlerMinifier
ms.author: riande
manager: wpickett
ms.date: 10/14/2016
ms.date: 02/28/2017
ms.topic: article
ms.assetid: d54230f9-8e5f-4861-a29c-1d3a14e0b0d9
ms.technology: aspnet
ms.prod: asp.net-core
ms.prod: aspnet-core
uid: client-side/bundling-and-minification
---
# Bundling and minification in ASP.NET Core

>[!WARNING]
> This page documents version 1.0.0-rc2 and has not yet been updated for version 1.0.0
By [Rick Anderson](https://twitter.com/RickAndMSFT), [Erik Reitan](https://github.com/Erikre), and [Daniel Roth](https://github.com/danroth27)

Bundling and minification are two techniques you can use in ASP.NET to improve page load performance for your web application. Bundling combines multiple files into a single file. Minification performs a variety of different code optimizations to scripts and CSS, which results in smaller payloads. Used together, bundling and minification improves load time performance by reducing the number of requests to the server and reducing the size of the requested assets (such as CSS and JavaScript files).

This article explains the benefits of using bundling and minification, including how these features can be used with ASP.NET Core applications.

## Overview

In ASP.NET Core apps, you bundle and minify the client-side resources during design-time using third party tools, such as [Gulp](using-gulp.md) and [Grunt](using-grunt.md). By using design-time bundling and minification, the minified files are created prior to the application’s deployment. Bundling and minifying before deployment provides the advantage of reduced server load. However, it’s important to recognize that design-time bundling and minification increases build complexity and only works with static files.
In ASP.NET Core apps, there are multiple options for bundling and minifying client-side resources. The core templates for MVC provide an out of the box solution using a configuration file and BuildBundlerMinifier NuGet package. Third party tools, such as [Gulp](using-gulp.md) and [Grunt](using-grunt.md) are also available to accomplish the same tasks should your processes require additional workflow or complexities. By using design-time bundling and minification, the minified files are created prior to the application’s deployment. Bundling and minifying before deployment provides the advantage of reduced server load. However, it’s important to recognize that design-time bundling and minification increases build complexity and only works with static files.

Bundling and minification primarily improve the first page request load time. Once a web page has been requested, the browser caches the assets (JavaScript, CSS and images) so bundling and minification won’t provide any performance boost when requesting the same page, or pages on the same site requesting the same assets. If you don’t set the expires header correctly on your assets, and you don’t use bundling and minification, the browsers freshness heuristics will mark the assets stale after a few days and the browser will require a validation request for each asset. In this case, bundling and minification provide a performance increase even after the first page request.

## Bundling
### Bundling

Bundling is a feature that makes it easy to combine or bundle multiple files into a single file. Because bundling combines multiple files into a single file, it reduces the number of requests to the server that is required to retrieve and display a web asset, such as a web page. You can create CSS, JavaScript and other bundles. Fewer files, means fewer HTTP requests from your browser to the server or from the service providing your application. This results in improved first page load performance.

Bundling can be accomplished using the [gulp-concat](https://www.npmjs.com/package/gulp-concat) plugin, which is installed with the Node Package Manager ([npm](https://www.npmjs.com/)). Add the `gulp-concat` package to the `devDependencies` section of your *package.json* file. To edit your *package.json* file from Visual Studio right-click on the **npm** node under **Dependencies** in the solution explorer and select **Open package.json**:

[!code-json[Main](../client-side/bundling-and-minification/samples/WebApplication1/src/WebApplication1/package.json?highlight=7)]

Run `npm install` to install the specified packages. Visual Studio will automatically install npm packages whenever *package.json* is modified.

In your *gulpfile.js* import the `gulp-concat` module:

[!code-js[Main](bundling-and-minification/samples/WebApplication1/src/WebApplication1/gulpfile.js?highlight=3&range=4-8)]

Use [globbing](http://www.tldp.org/LDP/abs/html/globbingref.html) patterns to specify the files that you want to bundle and minify:

[!code-js[Main](bundling-and-minification/samples/WebApplication1/src/WebApplication1/gulpfile.js?range=12-19)]

You can then define gulp tasks that run `concat` on the desired files and output the result to your webroot:

[!code-js[Main](bundling-and-minification/samples/WebApplication1/src/WebApplication1/gulpfile.js?highlight=3,10&range=31-43)]

The [gulp.src](https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpsrcglobs-options) function emits a stream of files that can be [piped](http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options) to gulp plugins. An array of globs specifies the files to emit using [node-glob syntax](https://github.com/isaacs/node-glob). The glob beginning with `!` excludes matching files from the glob results up to that point.

## Minification
### Minification

Minification performs a variety of different code optimizations to reduce the size of requested assets (such as CSS, image, JavaScript files). Common results of minification include removing unnecessary white space and comments, and shortening variable names to one character.

Expand Down Expand Up @@ -86,36 +61,120 @@ imageTagAndImageID | t
imageContext | a
imageElement | r

To minify your JavaScript files you can use the [gulp-uglify](https://www.npmjs.com/package/gulp-uglify) plugin. For CSS you can use the [gulp-cssmin](https://www.npmjs.com/package/gulp-cssmin) plugin. Install these packages using npm as before:
## Impact of bundling and minification

[!code-json[Main](../client-side/bundling-and-minification/samples/WebApplication1/src/WebApplication1/package.json?highlight=8,9)]
The following table shows several important differences between listing all the assets individually and using bundling and minification on a simple web page:

Import the `gulp-uglify` and `gulp-cssmin` modules in your *gulpfile.js* file:
Action | With B/M | Without B/M | Change
--- | :---: | :---: | :---:
File Requests |7 | 18 | 157%
KB Transferred | 156 | 264.68 | 70%
Load Time (MS) | 885 | 2360 | 167%

[!code-js[Main](bundling-and-minification/samples/WebApplication1/src/WebApplication1/gulpfile.js?highlight=4,5&range=4-8)]
The bytes sent had a significant reduction with bundling as browsers are fairly verbose with the HTTP headers that they apply on requests. The load time shows a big improvement, however this example was run locally. You will get greater gains in performance when using bundling and minification with assets transferred over a network.

Add `uglify` to minify your bundled JavaScript files and `cssmin` to minify your bundled CSS files.
## Using Bundling and minification in a project

[!code-js[Main](bundling-and-minification/samples/WebApplication1/src/WebApplication1/gulpfile.js?highlight=4,11&range=31-43)]
The MVC project template provides a *bundleconfig.json* connfiguration file which defines the options for each bundle. By default, a single bundle configuration is defined for the custom JavaScript (wwwroot/js/site.js) and Stylesheet (www/css/style.css) files.

You can run bundling and minification tasks from a command prompt using gulp (`gulp min`), or you can also execute any of your gulp tasks from within Visual Studio using the **Task Runner Explorer**. To use the **Task Runner Explorer** select *gulpfile.js* in the Solution Explorer and then select **Tools > Task Runner Explorer**:
[!code-json[Main](../client-side/bundling-and-minification/samples/BuildBundlerMinifierExample/bundleconfig.json)]

![Task Runner Explorer](bundling-and-minification/_static/task-runner-explorer.png)
Bundle options include:

> [!NOTE]
> The gulp tasks for bundling and minification do not general run when your project is built and must be run manually.
* outputFileName - name of the bundle file to output. Can contain a relative path from the bundleconfig.json file. **required**
* inputFiles - array of files to bundle together. These are relative paths to the confifiguration file. **optional**, *an empty value results in an empty output file. [globbing](http://www.tldp.org/LDP/abs/html/globbingref.html) patterns are supported.
* minify - minification options for the output type. **optional**, *default - `minify: { enabled: true }`*
* Configuration options are available per output file type.
* [CSS Minifier](https://github.com/madskristensen/BundlerMinifier/wiki/cssminifier)
* [JavaScript Minifier](https://github.com/madskristensen/BundlerMinifier/wiki/jsminifier)
* [HTML Minifier](https://github.com/madskristensen/BundlerMinifier/wiki/htmlminifier)
* includeInProject - add generated files to project file. **optional**, *default - false*
* sourceMaps - generate source maps for the bundled file. **optional**, *default - false*

## Impact of bundling and minification
### Visual Studio 2015 / 2017

The following table shows several important differences between listing all the assets individually and using bundling and minification on a simple web page:
Open *bundleconfig.json* in Visual Studio, if your environment does not have the extension installed; a prompt is presented suggesting that there is one that could assist with this file type.

Action | With B/M | Without B/M | Change
--- | :---: | :---: | :---:
File Requests |7 | 18 | 157%
KB Transferred | 156 | 264.68 | 70%
Load Time (MS) | 885 | 2360 | 167%
![BuildBundlerMinifier Extension Suggestion](../client-side/bundling-and-minification/_static/bundler-extension-suggestion.png)

The bytes sent had a significant reduction with bundling as browsers are fairly verbose with the HTTP headers that they apply on requests. The load time shows a big improvement, however this example was run locally. You will get greater gains in performance when using bundling and minification with assets transferred over a network.
Select View Extensions, and install the **Bundler & Minifier** extension (Requires Visual Studio restart).

![BuildBundlerMinifier Extension Suggestion](../client-side/bundling-and-minification/_static/view-extension.png)

When the restart is complete you need to configure build to run the processes of minifying and bundling the client side assets. Right click the *bundleconfig.json* file and select *Enable bundle on build...*.

Build the project and the *bundleconfig.json* is included in the build process to produce the output files based on the configuration.

```console
1>------ Build started: Project: BuildBundlerMinifierExample, Configuration: Debug Any CPU ------
1>
1>Bundler: Begin processing bundleconfig.json
1>Bundler: Done processing bundleconfig.json
1>BuildBundlerMinifierExample -> C:\BuildBundlerMinifierExample\bin\Debug\netcoreapp1.1\BuildBundlerMinifierExample.dll
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
```

### Visual Studio Code or Command Line

Visual Studio and the extension drive the bundling and minification process using GUI gestures, however the same capabilities are available with the `dotnet` CLI and BuildBundlerMinifier NuGet Package.

Add the NuGet package to your project:

```console
dotnet add package BuildBundlerMinifier
```

Restore the dependencies:

```console
dotnet restore
```

Build the app:

```console
dotnet build
```

The output from the build command shows the results of the minification and/or bundling according to what is configured.

```console
Microsoft (R) Build Engine version 15.1.545.13942
Copyright (C) Microsoft Corporation. All rights reserved.


Bundler: Begin processing bundleconfig.json
Minified wwwroot/css/site.min.css
Bundler: Done processing bundleconfig.json
BuildBundlerMinifierExample -> /BuildBundlerMinifierExample/bin/Debug/netcoreapp1.0/BuildBundlerMinifierExample.dll
```

## Adding files

In this example, an additional CSS file is added called `custom.css` and configured for bundling and minification with `site.css`, resulting in a single `site.min.css`.

custom.css

```css
.about, [role=main], [role=complementary]
{
margin-top: 60px;
}

footer
{
margin-top: 10px;
}
```

Add the relative path to `bundleconfig.json`.

[!code-json[Main](../client-side/bundling-and-minification/samples/BuildBundlerMinifierExample/bundleconfig2.json)]

> [!NOTE]
> Alternatively, the globbing pattern could be used - `"inputFiles": ["wwwroot/**/*(*.css|!(*.min.css)"]` which gets all css files and excludes the minified file pattern.
Build the application and if you open `site.min.css`, you'll now notice that contents of `custom.css` has been appended to the end of the file.

## Controlling bundling and minification

Expand All @@ -131,12 +190,32 @@ This environment tag will render the bundled and minified CSS files only when ru

[!code-html[Main](../client-side/bundling-and-minification/samples/WebApplication1/src/WebApplication1/Views/Shared/_Layout.cshtml?highlight=5&range=12-17)]

## Consuming bundleconfig.json from Gulp

If your app bundling and minification workflow requires additional processes such as image processing, cache busting or CDN assest processing etc., then you can convert the Bundle and Minify process to Gulp.

> [!NOTE]
> Conversion option only available in Visual Studio 2017.
Right click the `bundleconfig.json` and select **Convert to Gulp...**. This will generate the `gulpfile.js` and install the necessary npm packages.

![Convert to Gulp](../client-side/bundling-and-minification/_static/convert-togulp.png)

The `gulpfile.js` produced reads the `bundlconfig.json` file for the configuration, therefore it can continue to be used for the inputs/outputs and settings.

[!code-json[Main](../client-side/bundling-and-minification/samples/BuildBundlerMinifierExample/gulpfile.js)]

To enable Gulp when the project builds, add the following to the *.csproj file.

```xml
<Target Name="MyPreCompileTarget" BeforeTargets="Build">
<Exec Command="gulp min" />
</Target>
```

## Additional resources

* [Using Gulp](using-gulp.md)

* [Using Grunt](using-grunt.md)

* [Working with Multiple Environments](../fundamentals/environments.md)

* [Tag Helpers](../mvc/views/tag-helpers/index.md)
* [Tag Helpers](../mvc/views/tag-helpers/index.md)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"directory": "wwwroot/lib"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>

<PropertyGroup>
<PackageTargetFallback>$(PackageTargetFallback);portable-net45+win8+wp8+wpa81;</PackageTargetFallback>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="2.4.337" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace BuildBundlerMinifierExample.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}

public IActionResult About()
{
ViewData["Message"] = "Your application description page.";

return View();
}

public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";

return View();
}

public IActionResult Error()
{
return View();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;

namespace BuildBundlerMinifierExample
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();

host.Run();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace BuildBundlerMinifierExample
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}

app.UseStaticFiles();

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

0 comments on commit 31f5f9c

Please sign in to comment.