ASP.Net MVC Bundles and Minification - asp.net-mvc

When moving from development to a production environment I have run into some problems with the way in which my javascript files are being minified. It seems that some do not minify properly, and so I have been looking around to find a way to not minify a specific bundle.
public static void RegisterBundles(BundleCollection _bundles)
{
_bundles.Add(new ScriptBundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxxx.js"
));
_bundles.Add(new ScriptBundle("~/bundles/toMinify").Include(
"~/Scripts/yyyyy.js"
));
etc..
This is the basic layout in my bundle config class. I want to find a way in which to have all of my bundles minified, apart from the first one. Is this possible? So far the only solution I have found to achieve something similar is to turn off minification globally.

You have a couple of options, you can either replace your use of ScriptBundle with Bundle as in this example:
_bundles.Add(new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxxx.js"
));
.. or you could disable all transformations on a newly created bundle, like so:
var noMinify = new ScriptBundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxxx.js"
);
noMinify.Transforms.Clear();
_bundles.Add(noMinify);
Obviously the first solution is much prettier :)

You just have to declare a generic Bundle object and specify the transforms you need:
var dontMinify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxx.js");
bundles.Add(dontMinify);
var minify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/yyyyyy.js");
minify.Transforms.Add(new JsMinify());
bundles.Add(minify);

Related

Multiple CDN Bundling and Mimification in Mvc5

From this post I can bundle a single CDN file. So How to bundle many CDN files in one line ? Do I only need a list of strings and repeat this line for each item?
public static void RegisterBundles(BundleCollection bundles){
bundles.UseCdn = true;
var jqueryCdnPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";
bundles.Add(new ScriptBundle("~/bundles/jquery",
jqueryCdnPath).Include("~/Scripts/jquery-{version}.js"));
}
I think your answer is here: https://stackoverflow.com/a/31069580/2158136
When you use a CDN, you can´t bundle them in one line.
Even, if you add multiple bundles with the same virtual path, only the last item will be considered (It happened to us, and it took some time before we realized what was happening).
You have to add one line per each CDN that you need to add to the bundle.

Font-Awesome Get Request Failure When Bundling EnableOptimizations is true

I am experiencing a problem with font-awesome and ASP.NET’s optimisation/bundling feature.
When EnableOptimizations is set to false, the font which I'm using for a loading image works perfectly:
However, when EnableOptimizations is set to true, the font is no longer found and the following is displayed:
I’ve noticed there is a disparity between the paths which the GET requests are hitting:
EnableOptimizations = false: localhost:3620/Content/fonts/fontawesome-webfont.woff?v=4.1.0
EnableOptimizations = true: localhost:3620/fonts/fontawesome-webfont.svg?v=4.1.0
The bundle in question looks like this:
bundles.Add(new StyleBundle("~/Content/BootstrapAndFontAwesome").Include(
"~/Content/bootstrap/bootstrapLabel.css",
"~/Content/font-awesome/font-awesome.css"
));
What’s going on here and what’s the best way to fix it?
Cheers
Update
On Rowan's suggestion in the comments to this post, I implemented the following code from this stackoverflow answer which has fixed the problem on my dev machine:
public class CssRewriteUrlTransformWrapper : IItemTransform
{
public string Process(string includedVirtualPath, string input)
{
return new CssRewriteUrlTransform().Process("~" + VirtualPathUtility.ToAbsolute(includedVirtualPath), input);
}
}
I will need to do a few practice deployments to make sure it is solid (e.g. use virtual IIS directories etc.). Looks good so far!
Note that I did have to separate out the font-awesome file into it's own bundle as it cannot be bundled with another resource when adopting the CssRewriteUrlTransform solution.
Thanks.
Use CssRewriteUrlTransform.
Rewrites urls to be absolute so assets will still be found after bundling.
Example:
bundles.Add(new StyleBundle("~/Content/mycss")
.Include("~/Content/font-awesome.css", new CssRewriteUrlTransform()));
This SO post has a useful solution to this issue, and it appears to have been written by someone who actually works for Microsoft on the ASP.net Bundle code.
The issue is most likely that the icons/images in the css files are
using relative paths, so if your bundle doesn't live in the same app
relative path as your unbundled css files, they become broken links.
We have rebasing urls in css on our todo list, but for now, the easist
thing to do is to have your bundle path look like the css directory so
the relative urls just work, i.e:
new StyleBundle("~/Static/Css/bootstrap/bundle")
Update: We have added support for this in the 1.1beta1 release, so to
automatically rewrite the image urls, you can add a new ItemTransform
which does this rebasing automatically.
bundles.Add(new StyleBundle("~/bundles/publiccss").Include(
"~/Static/Css/bootstrap/bootstrap.css",
"~/Static/Css/bootstrap/bootstrap-padding-top.css",
"~/Static/Css/bootstrap/bootstrap-responsive.css",
"~/Static/Css/bootstrap/docs.css", new CssRewriteUrlTransform()));
This fixed my issue with getting 404 errors on Font Awesome icons, on the production server, due to the relative paths not being used correctly.
bundles.Add(new StyleBundle("~/Content/font-awesome/css/bundle").Include(
"~/Content/font-awesome/css/font-awesome.css", new CssRewriteUrlTransform()));
There’s a little know class called CssRewriteUrlTransform in the Sytem.Web.Optimization namespace that will help us solve this issue, or any css file that references url relative resources. The new code would now look something like:
bundles.Add(new StyleBundle("~/content/smartadmin")
.Include("~/content/css/font-awesome.css", new CssRewriteUrlTransform())
.Include("~/content/css/dataTables.responsive.css")
.IncludeDirectory("~/content/css", "*.min.css"));

How to apply bundle transform in debug mode?

In my project, I want to send application settings to the browser from the server.
To do so, I have created a class named "ConfigFileTransform", that inherits from IBundleTransform. In the process method, I replace keywords in javascript by their values. (Maybe it is not the best solution...)
For example, the query limit for a type of object is set to the client using this transform class.
My problem comes when I debug my application, I see the debugger going to my custom bundle transform class, but the rendered javascript does not contain the replacements...
In release mode, everything is ok.
Does anyone know what I can do to see my transforms applied when I am in debug mode?
Put this in the Application_Start method in your Global.asax file.
BundleTable.EnableOptimizations = true;
I haven't worked with only applying certain transforms but taking a look at this post:
ASP.Net MVC Bundles and Minification
You should be able to do this. You might need to refactor your bundle code a little so that you can add Conditional Compilation Variables to clear your transforms in debug only. So it could look something like this:
var noMinify = new ScriptBundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxxx.js"
);
#if DEBUG
noMinify.Transforms.Clear();
noMinify.Transforms.Add(new ConfigFileTransform())
#endif
_bundles.Add(noMinify);

Mvc4 bundling, minification and AngularJS services

Is there a way to customize the way Asp.Net MVC4 bundling&minification feature minifies the js files?
Meaning, I don't want to completely turn off minification, but "as is" it just breaks AngularJs.
Since AngularJs uses DI and IoC approach for injecting services in controllers, the following:
function MyController($scope) { }
Once minified, becomes:
function MyController(n) { }
Normally that wouldn't be a problem, but AngularJs uses the parameter names to understand which service to inject. So $scope should remain $scope, as well as any other parameter in angular controllers. Everything else, like local variables, etc, should be minified normally.
I can't find any clear documentation on how to configure Mvc4 minification, and it seems rather dumb for it to be "all or nothing" so I think I'm missing something.
Thanks.
Actually you can (and should!) write AngularJS code so it is "minification safe". Details are described in the "Dependency Annotation" section of http://docs.angularjs.org/guide/di but in short, for globally defined controllers you can write:
MyController.$inject = ['$scope'];
Please note that globally defined controllers are polluting global namespace (see this for more details) and should be avoided. If you declare a controller on a module level you can make it minification-safe as well:
angular.module('mymodule', []).controller('MyController', ['$scope', function($scope){
//controller code goes here
}]);
if you still want to control what to minify and what not (or if you want to include an already minified version by the plugin vendor) just declare two bundles, and only minify one of them on your BundleConfig.cs:
var dontMinify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxx.js");
bundles.Add(dontMinify);
var minify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/yyyyyy.js");
minify.Transforms.Add(new JsMinify());
bundles.Add(minify);
For those of you who don't want/can't be arsed to write the "minification-safe" angular-DI syntax, and don't care about variable names being obfuscated, I used BundleTransfomer along with Yui Js minifier - available via nuget:
Install-Package BundleTransformer.Core
Install-Package BundleTransformer.Yui
Gives VERY fine-grained control over minification/obfuscation. In the angular world, just set the obfuscateJavascript within the yui web.config section to false.

Using ASP.NET Javascript Bundles from the controller

I realise this breaks the MVC pattern, but there is a viable reason for doing it this way in an application I am currently building :)
What I am trying to do is output a JavaScript bundle directly from the Controller rather than via a link via a View.
So for example I have a bundle called "~/jQueryPlugin" what I'd like to do is something along the lines of
return this.JavaScript(BundleTable.GetBundle("~jQueryPlugin").BundleContent)"
However for the life of me I cannot figure out what the BundleTable.GetBundle("~jQueryPlugin").BundleContent part should be in order to get a string representation of the combined minimized bundle.
Any help would be appreciated·
In the 1.1-alpha1 release we added a new Optimizer class which should allow you to more easily do this. Its intended to be a standalone class that's useable out of side of ASP.NET hosting, so setting it up will be slightly different.
You can get the bundle contents out via something like this:
OptimizationSettings config = new OptimizationSettings() {
ApplicationPath = "<your physical path to the app>",
BundleSetupMethod = (bundles) => {
bundles.Add(new ScriptBundle("~/bundles/js").Include("~/scripts/jqueryPlugin.js"));
}
};
BundleResponse response = Optimizer.BuildBundle("~/bundles/js", config);
Assert.IsNotNull(response);
Assert.AreEqual("<your bundle js contents>", response.Content);
Assert.AreEqual(JsMinify.JsContentType, response.ContentType);
The next release should be fleshing this scenario out more, as it is needed for build time bundling integration with Visual Studio.

Resources