ASP.NET Bundling - Ignoring second JS file - asp.net

I have set up a simple test using ASP.NET's bundling and minification feature. I have two very simple js files:
~/JS/Site.js
(function echo1() {
alert("this is site.js");
})();
~/JS/test.js
(function echo2(value) {
alert("and this is test.js");
})();
I've created a bundle as follows:
bundles.Add(new ScriptBundle("~/bundles/scripts/site-globals").Include(
"~/JS/Site.js",
"~/JS/test.js"));
and referenced the bundle on the page using #Scripts.Render("~/bundles/scripts/site-globals")
When I run the site under debug (<compilation debug="true" targetFramework="4.5" /> in web.config) I get the expected result - two alert boxes show one after the other.
However, when I run change to release (<compilation debug="false" targetFramework="4.5" />) - I only see the first alert box, and the combined JS file that gets sent to the browser has completely ignored the content of test.js.
The "combined and minified" output is as below, and wrongly only includes the code from Site.js:
(function(){alert("this is site.js")})()
Any ideas on why this is happening would be much appreciated! Thanks

I've found out what was causing this problem. If any of the javascript files have a comment as the last line, they will be combined together without a newline, causing the first line of the next file to be commented out.
Here's a link to another question on stack overflow which demonstrates this: https://stackoverflow.com/a/14223945/11459631
In my case, I was using the Web Essentials Visual Studio plugin to minify my javascript files. It was creating a .js.map file for each JS file, and at the end of each .min.js file was a commented line like this, which turned out to be causing the problem:
//# sourceMappingURL=somefile.min.js.map
Since I didn't need the mapping files, I turned this feature off using Options -> Web Essentials -> Javascript -> Set Generate source maps (.map) to false
Hope this helps anyone who finds this problem!

Matt, your bundling code looks correct, do you receive any js errors in the browser console when running in Release mode? Also as a side note, are you aware that you can simply define the folder path to your JS files and they will all be included?

Related

Do I need less.js if I'm using dotless?

I'm trying to import a bootstrap/angular (made for node)/less theme my company purchased into a ASP.net MVC project from scratch.
The theme uses less, so doing some google searches, I installed "dotless" and "dotless adapter for System.Web.Optimization".
So I'm copying and pasting the references and it errors here:
<!-- prochtml:remove:dist -->
<script type="text/javascript">less = { env: 'development' };</script>
<script type="text/javascript" src="~/assets/plugins/misc/less.js"></script> <-- Errors Here
<!-- /prochtml -->
It says "LessCssHttpHandler.cs not found". "You need to find LessCssHttpHandler.cs to view the source for the current call stack frame."
I was looking into what "less.js" does.. and i couldn't find a clear cut description but it seems like it makes it so that you're able to use the LESS environment because CSS isn't a current standard like CSS is.
If i'm right in my assumption, do I not need to include "less.js" into my project? Thanks
No. Once the processing is done server-side (using dotLess), no need to include Less.js in the client-side (as data is already received as regular CSS).
Also, if you're using Visual Studio, you can set WebEssentials to automatically compile your Less files upon saving (SomeStyleSheet.less -> SomeStyleSheet.css), then on the client-side you're simply loading regular CSS. That will spare you from both server and client side compilation needs.

Using bundles in WebForms outputs the minified/combined file even in debug mode

I've created a bundle of various script files that I want to be combined/minified together. In my code behind file (yes, sorry it's in VB!) I add it to a <asp:placeholder /> on the <head> like this
Me.PlhHeader.Controls.Add(New LiteralControl(Scripts.Render("~/bundles/main").ToHtmlString()))
This will work, but it always seems to output the compressed minified version, even when debug="true" in the Web.Config.
no matter what, this is what is output: <script src="/bundles/main"></script>
What do I need to do differently to make this output the individual uncompressed files when in debug mode?
EDIT
I've also tried to manually set the option BundleTable.EnableOptimizations = false and it still outputs the single minified script tag. I'm out of ideas.
Final Edit
I was doing something very dumb with some related code, but technically everything with the bundles was fine and working correctly. Problem solved for me!
I would recommend you to install the Microsoft.AspNet.WebOptimization.WebForms. It works really well.
Microsoft.AspNet.WebOptimization.WebForms
Then you can use:
<%: System.Web.Optimization.Scripts.Render("~/bundles/main") %>

ASP.NET Bundling - Bundle not updating after included file has changed (returns 304 not modified)

I am trying out ASP.NET Bundling with ASP.NET MVC 4 application. The situation is that I want to make a CDN style service, which has JS and CSS files to which you can address from other sites with this type address: http://www.mycdn.com/scripts/plugin/js, which bundles and minifies all included .js files.
My bundle config for one file looks like this:
bundles.Add(new ScriptBundle("~/Scripts/plugin/pluginjs").Include("~/Scripts/plugin/jquery.plugin.js"));
However, when I do this, the bundles are not getting updated even after I change the original js files. I keep on getting 304 Not Modified, when I refresh my browser, and the content of the minified file is not updated. How can I make bundles update, because it is useless to have bundles with old content? I tried out every way, but could not figure out a solution.
I just had the exact same problem. I have a folder with 2 CSS files:
~/Content/main.css
~/Content/main.min.css (pre-existing from my previous manual minification process)
My bundling code is this:
bundles.Add(new StyleBundle("~/css/main").Include("~/content/main.css"));
No matter how much I changed my main.css the output was the same url with the same contents:
<link href="/css/main?v=6Xf_QaUMSlzHbXralZP7Msq1EiLTd7g1vId6Vcy8NJM1" rel="stylesheet"/>
The only way to update the bundle was to rebuild my solution - obviously not the best approach.
However as soon as I deleted main.min.css, everything started to work just fine. Playing a little more I discovered that if there are both main.css and main.min.css, then updating main.min.css will actually update the bundle... Weirdness, but at least predictable.
After fighting to figure out what makes the bundle cache refresh I came to a few conclusions that will hopefully help others:
If .min files ARE included as part of the bundle:
release mode + change min js code = cache refresh
release mode + change non min js code = no cache refresh
debug mode + change min js code = no cache refresh
debug mode + change non min js code = no cache refresh
If .min files are NOT included as part of the bundle:
debug mode + change js code = no cache refresh
release mode + change js code = cache refresh
Notes
By debug mode i mean web.config compilation debug = true (and
BundleTable.EnableOptimizations = false or is omitted)
By release mode i mean web.config compilation debug = false (and
BundleTable.EnableOptimizations = true or is omitted
Be sure you are actually making code changes. Changes such as spaces
and comments do not affect the resulting minified js so the server is
correct in that there are no changes (so the bundle cache is not
refreshed).
Please note that if you are using Google Chrome the caching is quite aggressive. To ensure nothing is cached, you can do Ctrl-Shift-I to bring up the developer pane. Go to Network and click Disable Cache. Ensure you keep this open. Now refresh the page. Your cache should be cleared and the file changes should be reflected now.
Okay, here's my story. I disabled generation of min files for less files in Web Essentials. Old min files were not deleted, and bundle thingy saw those instead of updated CSS. Good luck!
EDIT
Sometime later I spent another good 2 hours on the same issue. This time it was my fault I guess - I forgot the leading tilde, i.e. I wrote
Scripts.Render("/js/script")
in lieu of
Scripts.Render("~/js/script")
For whatever reason it sometimes worked, and sometimes it did no such thing.
The bundling operation is case sensitive. Make sure the filename has the proper case.
I had to change a line in my BundleConfig.cs:
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/Site.css")); <-- Uppercased.
I actually decided to not to use System.Web.Optimization for this task, but I found Microsoft Ajax Minifier, which is also included in WebGrease.dll, which comes with MVC4 System.Web.Optimization library. I wrote the following function, which I then called in Application_Start for each minified file:
public static void MinifyFile(string virtualPath)
{
string fullPath = HttpContext.Current.Server.MapPath(virtualPath);
string extension = Path.GetExtension(fullPath).ToLower();
string targetPath = fullPath.Substring(0, fullPath.Length - extension.Length) + ".min" + extension;
if(File.Exists(fullPath) == false)
{
throw new FileNotFoundException("File not found: " + fullPath);
}
string input = File.ReadAllText(fullPath);
string output;
if (extension == ".js")
{
Microsoft.Ajax.Utilities.Minifier jsmin = new Microsoft.Ajax.Utilities.Minifier();
output = jsmin.MinifyJavaScript(input);
}
else if (extension == ".css")
{
Microsoft.Ajax.Utilities.Minifier jsmin = new Microsoft.Ajax.Utilities.Minifier();
output = jsmin.MinifyStyleSheet(input);
}
else
{
throw new NotSupportedException(extension + " is not supported for minification.");
}
File.WriteAllText(targetPath, output);
}
Now, my application is minifying all files on Application_Start.
I'm not sure the feature as it currently stands will really support being a CDN, as it relies implicitly on the url to contain a hashcode to prevent browser caching.
But I can try to help you try to get there, and maybe its possible today... One issue that might potentially be a roadblock is that the BundleHandler will return 304 on any bundle requests that contain the IfLastModified header, since the assumption is that the browser cache is always valid due to the fingerprint in the url.
Can you add some details about how you are rendering references to the bundles? Are you using something like Scripts.Render("~/Scripts/plugin/pluginjs")?
Your bundle script tag should look something like this:
Good: <script src="/fbt/bundles/js?v=wvLq7H7qEZB2giyIRn7aEZAxhHOb2RfTYYh2HMd9EqM1"></script>
If your script tags are referencing the raw bundle with no version string, that would likely explain the caching issues you are seeing:
Not good: <script src="/fbt/bundles/js></script>
I know its been a while since this was updated but I have found I just need to wait a couple seconds to let the bundle catch up with my css changes. I have the bootstrap less files being compiled into a css and min.css and its definitely not instant to see my changes. For me it was about 10 seconds on a fast pc with an ssd. Your miles may vary based on your system specs.
I saw this answer but none of these were the case for me.
There were certain CSS rules that were making the styles bundler fail and i was getting the same hash, even if i made changes to the CSS file. It was all working correctly before for me.
In my case the violating css selector rule was -
#globalSearch.searching { ... }
If i made this just
.searching { ... }
It all starts working again and any changes i make to my css file the bundler hash changes correctly.
Just adding this answer as it might help someone.
For what it's worth, I had the same problem just now with one js file inexplicably refusing to update no matter what (rebuild, forced cache clear etc). After a while, I switched the client debug tools in IE on (F12) to start watching the network traffic, and this act alone forced the JS file to refresh. Go figure, but it worked.
The Issue for me was I had Fiddler running. After I close dit and rebuilt my solution it was loading the changes in the js file for me.
I had a similar problem. In my situation, I had a CSS file referenced in a style bundle and had that bundle referenced in my MVC view. I also had the "EnableOptimizations" flag set to false in the bundle code.
Despite all this, the view refused to update to include the new CSS file.
My solution was to create a minified version of the CSS file and include it in the project and it started working. I have no idea why this would be the case since that minified file is not referenced anywhere (even after the view updated) and shouldn't even be considered since the code is set to not be optimized. This is most likely a bug (or a feature) of the bundling functionality. I hope this helps someone else running into this problem.
Make sure your app is really being deployed in Release mode and that your host is fiddling with settings. I was having this issue, but after investigating, I realized my files were not actually being bundled. I was deploying in Release mode, but for some reason (I suspect host), I think my app was really deployed in debug.
I had to set the following at the end of the BundleConfig.cs file to force bundling, which in turn forced the updated file to finally show in the browser.
BundleTable.EnableOptimizations = true;
I had this issue today and I went through all the answers but my problem wasn't solved by any of the solutions here. Later I found that this was happening because there was an error in my CSS. One of the urls was not closed (the last single quote was missing).
This caused the css file to have a syntax error and it didn't compile for the Bundleconfig. I suppose there would have been a message in the Output log, but I hadn't checked.
If this is happening to you in 2020, try making sure your CSS does not have a syntax error.
Just update your System.Web.Optimization by NuGet

Returning razor-parsed Javascript as a ViewResult from a controller

I've successfully created an mvc/razor web application that returns css files that have been parsed by razor. Each time there's a background-image I have a razor snippet that writes the URL prefix to the image file name. The CSS now looks like this:
body { background-image: url(#LookupUrl.Image("background.gif")); }
Css files now work fine and I've moved onto trying to get javascript .js files to function the same way but these aren't playing ball.
The code is identical to the css code and it successfully finds the .js file, but razor seems to parse it differently. Here's an example js file:
function testFunction() { alert('test function hit!'); }
testFunction();
Razor seems to think it's code that it should compile, and gives the error:
Compiler Error Message: JS1135: Variable 'alert' has not been declared
> Source Error:
>
> Line 1: function testFunction() {
> Line 2: alert('test function
> hit!'); Line 3: } Line 4:
> testFunction();
After renaming the same file to .css it works fine.
Is there a way of getting razor to function with .js files in the same way as it does for .css?
Here's how I registered the file handlers for razor:
RazorCodeLanguage.Languages.Add("js", new CSharpRazorCodeLanguage());
RazorCodeLanguage.Languages.Add("css", new CSharpRazorCodeLanguage());
WebPageHttpHandler.RegisterExtension(".js");
WebPageHttpHandler.RegisterExtension(".css");
The build provider is registered in PreApplicationStart via the method Haacked outlines in his blog post.
Do I need to remove a handler that mvc adds for .js files?
UPDATE 2 days on
While I got working what I wanted to get working, I would not recommend this method to others. Using Razor to parse css/javascript is flawed without the use of <text><text/> - it's the simplicity of razor using the # ampersand that messes it up. Consider the CSS3 #font-face. Razor hits the # and thinks it should use it as a function. The same thing can happen with javascript, and happened with Jquery 1.5.1.
Instead, I'll probably go back to aspx webforms for dynamic css/javascript, where there's less chance of the <% %> code blocks appearing naturally.
I couldn't understand why CSS worked while JS didn't, especially after the copy+pasted JS code worked inside the CSS file.
I used the find/replace dialogue within visual studio on the System.Web.WebPages.Razor source to search for the string '.js' within the project. There was nothing helpful there so I then went to the System.Web.WebPages project. It found a match in System.Web.WebPages.Util, which is a static class with a few helper methods.
One of those methods is 'EnsureValidPageType' and within there is a try/catch block. Inside the 'catch' block is a comment:
// If the path uses an extension registered with codedom, such as Foo.js,
// then an unfriendly compilation error might get thrown by the underlying compiler.
// Check if this is the case and throw a simpler error.
It made me believe .js has got some special built-in handler with it.
I googled for a bit, couldn't find anything, then looked in the web.config that's within \Windows\Microsoft.NET\Framework64{version}\Config.
In there is a buildProvider mapping for the extension .js to
System.Web.Compilation.ForceCopyBuildProvider
After removing this buildprovider in the website's web.config, .js files get compiled and work as they should!
I'm still not too sure what the ForceCopyBuildProvider does or is for but I wonder if it's for visual studio. Various extensions have different Copy/Ignore build providers registered.
Once again apologies for answering my own question but I hope the comprehensive(waffley) answer might help others out.
You could try using the special <text> node to indicate to the Razor parser to treat the content literally:
<text>
function testFunction() { alert('test function hit!'); }
testFunction();
</text>
The default Razor parser uses the HtmlMarkupParser to handle the markup components of your template. There isn't currently any alternative parsers that support other markup languages (which you would need to treat the javascript code language as). If you did create a new markup parser, I would imagine it would be quite difficult to separate the code and markup (i.e. the C# and the Javascript).
What you could do, is use the <text></text> wrapping elements to enforce the parser switches to markup mode when that section of the template is reached, e.g.
<text>function testFunction() { alert('test function hit!'); }</text>
It's not pretty, but it should do the trick.

Minify Html output of ASP.NET Application

What are the ways by which we can reduce the size of the HTML Response sent by an asp.net application?
I am using Controls which are not owned by me and it produces output with white spaces. I am interested in Minifying the entire HTML output of the page just like how google does (View source www.google.com) to improve the timing.
Is there any Utility classes available for ASP.NET which can do this stuff for me?
There is no need to do it at run time. Because it can be done at compile time.
Details: http://omari-o.blogspot.com/2009/09/aspnet-white-space-cleaning-with-no.html
Try HTTP module as described here: http://madskristensen.net/post/a-whitespace-removal-http-module-for-aspnet-20
For Microsoft .NET platform there is a library called the WebMarkupMin, which produces the minification of HTML code. For each ASP.NET framework has its own module:
ASP.NET Core - WebMarkupMin.Web. Implemented as an HTTP module, so it can work with any framework. Suitable for use in the ASP.NET Web Pages framework (Razor).
ASP.NET MVC - WebMarkupMin.Mvc
ASP.NET Web Forms - WebMarkupMin.WebForms
Documentation is available at - http://webmarkupmin.codeplex.com/documentation
I want to comment on Thorn's suggestion (but I'm new to stack overflow).
The linked code (omari-o.blogspot.com) doesn't support MVC4, and although the code is open source it cannot easily be upgraded because of braking changes between MVC3 and MVC4.
There might be whitespaces written to the http result at runtime, only the developer of the actual site can know that. Thus static minification of template files (aspx) is not foolproof at all. Dynamic minification, which is suggested by gius, should be used to guarantee that whitespaces are removed correctly, and unfortunately this will incur a runtime computation cost. If code dynamically writes spaces to the output, it will have to be removed dynamically.
The accepted answer does not work with MVC 4, so here is a similar lib that minifies at build-time https://github.com/jitbit/HtmlOptimizerMvc4
Just adding another option I do not see listed here, which is the one I was recommended using:
Html minifier command line tool
Usage:
here and here
There is an issue, however, with this tool: it leaves single line (//) comments, and it causes problems for Razor parsing, since a single line comment placed within a C# block like the following:
#{
...
...
// anything
...
}
will cause the minification output rest of the line, from this point on, to be ignored by the Razor parser, which will thus raise an error stating there it could not find the closing "}" for the block.
My workaround for this issue was to completely removing these comments from the output.
This way it works.
To do that, simply remove the RegexOptions.SingleLine from line 145:
htmlContents = Regex.Replace(htmlContents, #"//(.*?)\r?\n", ""/*, RegexOptions.Singleline*/);

Resources