I am using the new System.Web.Optimization and have created a bundle like this:
bundles.Add(New ScriptBundle("~/bundles/BaseJS").Include(
"~/Resources/Core/Javascripts/jquery-1.7.1.js",
"~/Resources/Core/Javascripts/jquery-ui-1.8.16.js",
"~/Resources/Core/Javascripts/jquery.validate.js",
"~/Resources/Core/Javascripts/jquery.validate.unobtrusive.js",
"~/Resources/Core/Javascripts/jquery.unobtrusive-ajax.js"))
and in my view I have added this
@System.Web.Optimization.Scripts.Render("~/bundles/BaseJS")
In fiddler the URL comes across with an expires header of 1 year in the future and a content type of text/javascript
In the web.config I have some code for gzip that is working on static JS files but it doesn't seem to on the minified bundles.
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00"/>
<remove fileExtension=".js"/>
<mimeMap fileExtension=".js" mimeType="text/javascript"/>
</staticContent>
<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true"/>
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
<scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll"/>
<dynamicTypes>
<add mimeType="text/*" enabled="true"/>
<add mimeType="text/javascript" enabled="true"/>
</dynamicTypes>
<staticTypes>
<add mimeType="text/*" enabled="true"/>
<add mimeType="text/javascript" enabled="true"/>
</staticTypes>
</httpCompression>
Is there a way to make the render bundle gzip the content?
As you noted, creating a custom bundle transform by creating a class that implements IBundleTransform is the right way to go. For example, the following is an example bundle transform that uses the SharpZipLib (via NuGet) to do GZip compression:
public class GZipTransform : IBundleTransform
{
string _contentType;
public GZipTransform(string contentType)
{
_contentType = contentType;
}
public void Process(BundleContext context, BundleResponse response)
{
var contentBytes = new UTF8Encoding().GetBytes(response.Content);
var outputStream = new MemoryStream();
var gzipOutputStream = new GZipOutputStream(outputStream);
gzipOutputStream.Write(contentBytes, 0, contentBytes.Length);
var outputBytes = outputStream.GetBuffer();
response.Content = Convert.ToBase64String(outputBytes);
// NOTE: this part is broken
context.HttpContext.Response.Headers["Content-Encoding"] = "gzip";
response.ContentType = _contentType ;
}
}
Now, here's the unfortunate part - in testing this sample, I uncovered a bug that will keep it from working. The original design expected that folks would do pretty simple things - and as such, BundleResponse exposes properties that allow you to set the content (more specifically, string content) and the content type. The BundleContext exposes a property of HttpContext, which would lead a reasonable person to believe that additional properties of a response could be set there (as shown above). However, this is misleading for 2 reasons:
Bundle transforms are run as a part of creating the bundle - and creating the bundle happens the first time it is referenced (not dereferenced, as in, the browser follows the src attribute in a script tag - but referenced, as in, the view calls the Scripts.Render helper method). In my example above, this means that a content-encoding header with a value of gzip will be set on the first page with a view that uses bundling's helper methods to generate a link - and if the actual HTTP content is not gzipped, you'll get an error since the browser can't decode the HTTP content.
Even if #1 weren't an issue, the bundle is put immediately put into the ASP.NET cache after it is created - so this code path will only be executed once.
We're taking a hard look at the design in the next version of framework to enable you to specify all (ideally) aspects of the HTTP response message that is free of the HTTP context (meaning it's easily cachable).
One additional note. To supply custom bundle transforms, you'll need to fall back to creating an instance of Bundle rather than ScriptBundle/StyleBundle. Those classes are really just shorthand types for bundles with preconfigured bundle transforms. To create a bundle based on Bundle, you would do something like the following:
var jqueryBundle = new Bundle("~/bundles/jqueryall", new GZipTransform("text/javascript"));
jqueryBundle.Include("~/Scripts/jquery-1.*",
"~/Scripts/jquery-ui*",
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*");
bundles.Add(jqueryBundle);