Using ASP.NET Javascript Bundles from the controller - asp.net-mvc

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.

Related

How to check if MVC bundle exists

Is there a way to test if a bundle exists before trying to render it?
I want to do something like this:
#{
var bundleName = GetBundleName();
}
#if (Scripts.BundleExists(bundleName))
{
#Scripts.Render(bundleName)
}
Obviously, Scripts.BundleExists() isn't real, but it there something build in that does this? Or do I have to implement this myself?
You can get the bundles in the View by: var bl = System.Web.Optimization.BundleTable.Bundles; Then you can search the collection for a specific bundle by path as registered in BundleConfig. After that check if the path or any of the included paths exist.
I'm not aware of any way (nor was I able to find a way) for you to do this that is built into the framework. If you really have to do this, I would point you to a solution by Herman.
Asp.Net MVC Bundling, best way to detect missing file
Are your bundles dynamic? If not, I would suggest that this may not be something you need. Once you have them setup correctly the first time, they shouldn't fail.

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.

ASP.Net MVC Bundles and Minification

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);

Changing file references during the Publishing of the website

I have a master file which has references to the JS and the CSS file used for my website. These references are pointing to the non-crunched version of the files. Now, when I hit the Publish button through Visual Studio for my project I want to change the references in my master file to point to the crunched version of the JS and CSS.
Eg: During development if it was pointing to http://www.example.com/main.js, during publish it should change the reference to http://www.example.com/main_min.js. Is there a way to do this?
Also, before changing the reference I need to run my current js file(main.js) through the tool which outputs the crunched js file(main_min.js).
Any help on this is appreciated!
Thanks.
You could go to the project's properties and in the Build Events tab enter the following into the "Post-build event command line":
$(SolutionDir)..\YourJsCruncher.exe $(ProjectDir)\content\js\debug\ $(ProjectDir)\content\js\release\
and then have a custom HTML helper:
public static MvcHtmlString IncludeJs(this UrlHelper helper, string javascriptFile)
{
#if DEBUG
var subfolder = "debug";
#else
var subfolder = "release";
#endif
var path = helper.Content("~/Content/js/{1}/{2}.js", subfolder, javascriptFile);
return MvcHtmlString.Create(string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>", path));
}
and then in your view:
<%= Url.IncludeJs("foo.js") %>
This question has most of the answers you need:
Concatenate and minify JavaScript on the fly OR at build time - ASP.NET MVC
Customizing the publich process for one click publish is a little trickier. The best I could answer is linking to this blog: http://vishaljoshi.blogspot.com/ When I was working with one-click-publish customization this is the place I found the most answers. If I remember correctly this wasn't trivial and its better to integrate this into your build process like the answers in the first question I link explain.

Resources