How to make Microsoft Bundle output JavaScript not HTML script tags
asp.net, asp.net-mvc-4, bundle, c#
Solution
You can do what the BundleHandler does: Get a bundle based on the virtual path (same one you would use for `@Script.Render`), generate the response and write the contents.
@{
var context = new BundleContext(this.Context, BundleTable.Bundles, string.Empty);
var bundle = BundleTable.Bundles.GetBundleFor("~/VIRTUALPATH");
var response = bundle.GenerateBundleResponse(context);
var content = response.Content;
this.WriteLiteral(content);
}
Or in short:
@Html.Raw(BundleTable.Bundles.GetBundleFor("~/VIRTUALPATH").GenerateBundleResponse(new BundleContext(this.Context, BundleTable.Bundles, string.Empty)).Content)
EDIT: To get unminified content in debug, we can do what Scripts does: Get the bundle again, but instead of generating the response, we iterate its files and write their contents (delimited).
@{
var context = new BundleContext(this.Context, BundleTable.Bundles, string.Empty);
var bundle = BundleTable.Bundles.GetBundleFor("~/VIRTUALPATH");
if (BundleTable.EnableOptimizations)
{
var response = bundle.GenerateBundleResponse(context);
var content = response.Content;
this.WriteLiteral(content);
}
else
{
var files = bundle.EnumerateFiles(context);
foreach (var file in files)
{
var stream = file.VirtualFile.Open();
using (var reader = new StreamReader(stream))
{
this.Output.Write("{0}{1}", reader.ReadToEnd(), bundle.ConcatenationToken);
}
}
}
}
Problem
I am building a ASP.NET MVC4 based jQuery plug-in and I would like to use the standard Microsoft Bundler. Now normally when I use the bundler the final usage is this: ``` @Scripts.Render(BundleConfig.jsBundleFile) ``` With a output like this in debug: ``` <script src="/Scripts/..."></script> <script src="/Scripts/..."></script> <script src="/Scripts/..."></script> <script src="/Scripts/..."></script> <script src="/Scripts/..."></script> <script src="/Scripts/..."></script> ``` And a single tag to the minified and combined file in the official release. However, because we are building a jQuery plug-in I want to use the minifier to insert the actual JavaScript from the various files i.e. in DEBUG, when I have `Object1` defined in one file and `Object2` defined in another then I get this: ``` /* Content from file #1 */ var Object1 = function() { /* Un-minified content of Object1 */ }; /* Content from file #2 */ var Object2 = function() { /* Un-minified content of Object2 */ }; ``` and in the release I would get the minified content. From the MSDN I saw that the bundler, by default can't do that. But I am wondering is there an extension that can do this or another minifing library that can? Though I'd prefer to stay with the Microsoft Bundler. In my own research on how to extend the System.Web.Optimizer I found the CodePlex project of `System.Web.Optimization`, where it is said it's not open source as of yet, with makes the extending kinda difficult to anyone not really working on it. EDIT : So knowing that I can't really expand the System.Web.Optimizer I went with a compromise solution and this is what I ended up using. In the Controller: ``` public JavaScriptResult jQueryComponent() { JavaScriptResult ret = new JavaScriptResult(); ClientSettings Model = new ClientSettings(); #if DEBUG List<string> jsFiles = App_Start.BundleConfig.Main.FilesToBeBundledJS; StringBuilder bundleBuilder = new StringBuilder(); foreach (string file in jsFiles) { bundleBuilder.Append(System.IO.File.ReadAllText(Server.MapPath(file))); } ViewBag.bundledJS = bundleBuilder.ToString(); #else StringBuilder urlBuilder = new StringBuilder("http://localhost"); int port = Request.Url.Port; if (port != -1) { urlBuilder.Append(':'); urlBuilder.Append(port); } urlBuilder.Append(Scripts.Url(App_Start.BundleConfig.Main.jsBundleFile)); WebClient wc = new WebClient(); byte[] raw = wc.DownloadData(urlBuilder.ToString()); string bundledJS = System.Text.Encoding.UTF8.GetString(raw); ViewBag.bundledJS = bundledJS; #endif ret.Script = RenderRazorViewToString("~/Views/Main/jQueryComponent.cshtml", Model); return ret; } private string RenderRazorViewToString(string viewName, object model) { ViewData.Model = model; using (StringWriter sw = new StringWriter()) { ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName); ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw); viewResult.View.Render(viewContext, sw); viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View); return sw.GetStringBuilder().ToString(); } } ``` And in the View (jQueryComponent.cshtml): ``` @{ Layout = null; } if (typeof jQuery != 'function') { throw "This is a jQuery plugin i.e. jQuery needs to be defined first"; } (function ($) { //Adds the bundled JS into the plug-in @Html.Raw(ViewBag.bundledJS) $.fn.jsPlugIn = function() { /* Creates a new instance of [MainObject] with is defined in the bundle. */ //uses the bundled JS var Main = new MainObject(); Main.doSomething(); return this; }; }(jQuery)); ``` Any ideas how to improve this are welcome alongside the proper extention to the bundler. Although works, this is far from ideal and I am well aware of this. Please do not criticise this approach unless you have an alternative.