Sitecore Javascript Compression / Minification and LESS Compilation - javascript

Currently, I've been trying to put Cassette into our Sitecore project and it's just fallen flat on it's face. I've had dotLess in the project already, but would like a more solid solution for cache-busting while bundling.
I can use Cassette in a normal .Net4 project, but just can't get it to work in our Sitecore project. (Ed) We were unable to get it to actually build any sort of bundles (checked /_cassette) and it wasn't outputting anything to the page. For us, the project isn't built but is instead using CodeFile and I'm not sure if that was part of the problem. In general, we kept getting the No bundle with path 'xxx' exception no matter what we tried. It's a bummer to because I would really wouldn't mind having CoffeeScript weaved into the solution.
Is there a solution that compresses/minifies javascript and can render dotLess files with Sitecore?

The empty response streams from Cassette when working in any of the Sitecore client interfaces are being caused by the rewriteHtml functionality that it implements.
By default Cassette will buffer and rewrite page HTML output. This allows partial views to insert <link> tags referencing stylesheets after the <head> tag has been rendered. The rewrite functionality gets invoked as a PostRequestHandlerExecute event handler.
The empty response streams that you are seeing are as a result of the output stream that has been rewritten not being flushed. A fix for this issue is to flush the output stream when Close is called on the Cassette.AspNet.PlaceholderReplacingResponseFilter class, this is shown below:
void WriteUncompressedOutput()
{
var output = GetOutputWithPlaceholdersReplaced(bufferStream);
var outputBytes = outputEncoding.GetBytes(output);
if (outputBytes.Length > 0)
{
outputStream.Write(outputBytes, 0, outputBytes.Length);
outputStream.Flush();
}
}
If you do not require the rewriting functionality a workaround is available now. Just disable the Cassette HTML rewriting feature, either in the web.config:
<configuration>
<configSections>
....
<section name="cassette" type="Cassette.CassetteConfigurationSection, Cassette"/>
</configSections>
<cassette rewriteHtml="false"/>
or in code:
public class CassetteSettingsConfiguration : IConfiguration<CassetteSettings>
{
public void Configure(CassetteSettings configurable)
{
configurable.IsHtmlRewritingEnabled = false;
}
}
This information is included in my blog post about using Cassette with Sitecore.

We ended up getting SquishIt to work rather easily and without much hassle besides getting the JavaScript files to play nicely together.

Related

Minify dynamically generated javascript at runtime for ASP.NET

I use a .cshtml file to generate a dynamic .js file in an ASP.NET MVC controller. So the .js file never exists on disk, but only in memory at runtime. It works like this.
The browsers loads a javascript...
<script async src='http://example.com/script.js'></script>
...that is fetched from and generated by my MVC Controller endpoint:
[HttpGet]
[Route("script.js")]
public ActionResult GetScript()
{
// This takes a .cshtml template-file and returns a generated .js file
return new JavascriptViewResult(viewName, viewModel);
}
Is there a way to minify the resulting javascript file that is returned in runtime? I had a look at System.Web.Optimization.JsMinify but I'm not sure how I would get that to work. Can I write some kind of HttpHandler? Is there maybe a better approach to solve this problem?
I had a similar problem and after some searching some I came across this question. All you need to do is:
using Microsoft.Ajax.Utilities;
//...
string minifiedScript = new Minifier().MinifyJavaScript(yourJs);
I can't believe it was this simple, yet so hard to find.
P.S. It seems to be part of Microsoft Ajax Minifier library, but I don't remember ever installing it manually, so it's either part of MVC or comes with System.Web.Optimization.
I didn't notice the part about the JS being generated from a view. In that case using bundles might be a solution or rendering the view to a string (but I'm unfamiliar with how it's done in Spark view engine) before passing it to Minifier.MinifyJavaScript.
Edit: Another solution (albite somewhat convoluted) would be calling Minifier.MinifyJavaScript in the view and cramming the actual JS in a partial view. I don't know about Spark, but in Razor it's fairly easy to render a view to string from another view.

compiling node.js code to non-node-needed code

I am using ASP.NET MVC to build a web application, and I have fallen in love with the library Q.js, available here:
Q.js
Right now, I am using version 1.0, I load it up in the way that is most natural to me as an ASP.NET MVC developer. I have a place in my BundleConfig that just loads the script with my other scripts.
BundleConfig.cs
public static class BundleConfig {
public static void RegisterBundles(BundleCollection bundles){
bundles.Add(new ScriptBundle("~/bundles/scripts")
.Include("~/content/scripts/jquery.js")
// lots of other includes
.Include("~/content/scripts/q.js"));
}
}
So then in my view _Layout.cshtml, it's the normal simple process...
_Layout.cshtml
<head>
#Scripts.Render("~/bundles/scripts")
</head>
Easy enough, right? Yes, it works fine. But I notice that Q.js has another branch labelled v2.
Now, from what I can immediately tell, they are not that much different, but I do not believe the creator would have made a version 2 if they were not doing it to improve the product. I'd like to try it out, but this is where my experience fails me.
version 2 seems fundamentally different than version 1. Here is a link to it for quicker reference; Qv2
The q.js file starts out with this at line 43.
require("collections/shim");
var WeakMap = require("collections/weak-map");
var Iterator = require("collections/iterator");
var asap = require("asap");
I am accustomed to the require function being a part of requirejs, but I don't believe that is the purpose being served here. I in fact think this is intended to be consumed/run/used by node.js.
Now, since I am using ASP.NET MVC, I won't be using node.js. I've attempted to just put the expected folders and files in the right place so that they would be path relative to q.js, but that does not seem to satisfy it.
The Actual Question
Is there a way I can 'compile' Q.js 2.0 into a .js file that will not require node.js, and can be loaded normally within my ASP.NET MVC project? Can I use node.js to actually create an output .js file that has everything I need?
browserify is a tool for Node that takes all of the require()d dependencies, resolves them, and packages them into a single JavaScript file servable to the browser.

GWT: Calling external JavaScript library (sjcl) method

I want to use an external crypto library in my GWT project (client side). (particularly, Stanford Javascript Crypto Library, http://crypto.stanford.edu/sjcl/
I have added these lines in my project's gwt configuration file (MyProj.gwt.xml)
<script src="libs/sjcl/sjcl.js" />
<script src="libs/sjcl/core/sha256.js" />
And have created a new method in my security class:
public static native String sha256(String ptext)
/*-{
return sjcl.hash.sha256.hash(ptext);
}-*/;
But when I call it
String result = Security.sha256("password");
I get an error ("sjcl is not defined")
If someone who knows these issues and javasript could read the library and tell me the right way, I will be saving much time and effort - no digging in monstrous JavaScript.
UPD:
First thing I figured out, external library must be in /war directory
Second, I couldn't make GWT import the *.js files if I added the following just to gwt.xml files
<script src="libs/sjcl/sjcl.js"></script>
<script src="libs/sjcl/core/sha256.js"></script>
I had to add similar lines to Entry point's html source
<script src="/sjcl/sjcl.js"></script>
<script src="/sjcl/core/sha256.js"></script>
This way import works, I could check it with Chrome Inspector
I tried to use another library, not so complicated as sjcl, and it worked fine.
So, obviously, I'm not using sjcl right.
Another library is simpler, just pure methods, sjcl uses classes and stuff, but as I don't know JS at all, I can't figure out how to call such things properly without digging into JS syntax. I really would like to skip this part.
Can anybody look into the sjcl code and tell me how to call the method properly? The source is really small and JS pro can figure it out at a glance, I think.
UPD 2:
It turned out that adding the following code to gwt.xml is enough, just put library in /war and pay attention to the preceding "/" in the path. If you don't put it there, GWT will be seeking for you lib in module directory
UPD 3:
And don't forget to clear browser's cache or "not found" error won't go away
Make sure that when you talk about objects in the global context that you prefix them with $wnd, meaning the main window instance that the app is running in. This is documented in the JSNI docs, see https://developers.google.com/web-toolkit/doc/latest/DevGuideCodingBasicsJSNI#writing.
public static native String sha256(String ptext)
/*-{
return $wnd.sjcl.hash.sha256.hash(ptext);
}-*/;
"sjcl is not defined" means that you didn't import the sjcl file correctly.
Check the file path and make sure the browser can access the file.

How to Return static HTML and/or Javascript in OpenRasta

I am using OpenRasta 2.0, and am hosting within a console application.
I would like to be able to return some static HTML pages and JavaScript files from this setup, for example:
/index.html
/jquery.js
The files are entirely static, i.e. no Handler or Resource is required.
I have added the appropriate files to the project, and initially tried the following syntax:
ResourceSpace.Has
.ResourcesOfType<object>()
.AtUri("/")
.HandledBy<HtmlHandler>()
.RenderedByAspx("~/Views/IndexView.aspx");
The .aspx file is added to the project under a folder 'Views', and is set the build action to 'Embedded Resource'. This results in a NullReferenceException at runtime when attempting to resolve the virtual path. If I set the build action of the file to 'Compile', then it will not compile, I'm guessing because the console project does not understand ASPX.
I have also tried the following shorthand syntax for this available if referencing the WebForms codec:
ResourceSpace.Has
.TheUri("/jquery.js")
.ForThePage("~/Views/jquery.js");
But this suffers from the same issues as my initial approach, although does remove the need for a dummy Handler. So as far as I can tell, the WebForms codec cannot be used within a console application because the ASPX files cannot be compiled.
I was able to return HTML using the Razor codec as this expects the view templates to be embedded. However - I was not able to return a JavaScript file with the appropriate media type using the same technique, and I had to turn my otherwise static files into .cshtml files with a #resource defined.
I can't find any examples online of returning static HTML and/or JavaScript using OpenRasta. I would expect to find a dedicated configuration API for this like the "TheUri" syntax but independent of the WebForms codec.
I could create my own 'EmbeddedFileHandler' to return the content of a static embedded file, but I feel like I'm missing something since this is such a simple use case...
Anything that depends on the asp.net pipeline being initialized (such as aspx webforms pages) cannot compile because the BuildProvider is not there to do it, mostly because webforms is too tightly coupled to the asp.net pipeline.
OR 2 was not really designed to be used as a full web stack outside of asp.net for serving static content, as usually the host environment is better suited at doing it, but that's definitly something we're going to address in 3.0.
What I'd suggest is something along the lines of registering FileInfo as a resource, create a handler that can scan the file system for the files you want, and provide your own codec that either stream the data itself or call the API for the host http listener. It should be about 20 lines of code tops and would make a great blog post. :)

Add ASP.NET server script to mostly-static .JS / .CSS files without losing IntelliSense?

Using VS2008 and ASP.NET 3.5 (or VS 2010 / .NET 4.0?), how can I include a bit of dynamic ASP.NET server-side code in mostly-static JavaScript and CSS files?
I want to do this to avoid cloning entire JS or CSS files to vary just a small part of them multi-tenant sites. Later, I want to extend the solution to handle localization inside javascript/CSS, dynamic debugging/tracing support, and other cool things you can get by injecting stuff dynamically into JavaScript and CSS.
The hard part is that I don't want to lose all the cool things you get with static files, for example:
JS/CSS code coloring and intellisense
CSS-class "go to definition" support in the IDE
automatic HTTP caching headers based on date of underlying file
automatic compression by IIS
The server-side goodness of static files (e.g. headers/compression) can be faked via an HttpHandler, but retaining IDE goodness (intellisense/coloring/etc) has me stumped.
An ideal solution would meet the following requirements:
VS IDE provides JS/CSS intellisense and code coloring. Giving up server-code intellisense is OK since server code is usually simple in these files.
"go to defintion" still works for CSS classes (just like in static CSS files)
send HTTP caching headers, varying by modified date of the underlying file.
support HTTP compression like other static files
support <%= %> and <script runat=server> code blocks
URL paths (at least the ones that HTTP clients see) end with .JS or .CSS (not .ASPX). Optionally, I can use querystring or PathInfo to parameterize (e.g. choosing a locale), although in most cases I'll use vdirs for this. Caching should vary for different querystrings.
So far the best (hacky) solution I've come up with is this:
Switch the underlying CSS or JS files to be .ASPX files (e.g. foo.css.aspx or foo.js.aspx). Embed the underlying static content in a STYLE element (for CSS) or a SCRIPT element (for JS). This enables JS/CSS intellisense as well as allowing inline or runat=server code blocks.
Write an HttpHandler which:
looks at the URL and adds .aspx to know the right underlying ASPX to call
uses System.Net.HttpWebRequest to call that URL
strips out the containing STYLE or SCRIPT tags, leaving only the CSS or JS
adds the appropriate headers (caching, content type, etc.)
compresses the response if the client suports compression
Map *.CSS and *.JS to my handler.
(if IIS6) Ensure .JS and .CSS file extensions are mapped to ASP.NET
I'm already using a modified version of Darick_c's HttpCompression Module which handles almost all of above for me, so modifying it to support the solution above won't be too hard.
But my solution is hacky. I was wondering if anyone has a more lightweight approach for this problem which doesn't lose Visual Studio's static-file goodness.
I know I can also hack up a client-side-only solution where I split all JS and CSS into "vary" and "won't vary" files, but there's a performance and maintenance overhead to this kind of solution that I'd like to avoid. I really want a server-side solution here so I can maintain one file on the server, not N+1 files.
I've not tried VS10/.NET 4.0 yet, but I'm open to a Dev10/.net4 solution if that's the best way to make this scenario work.
Thanks!
I have handled a similar problem by having a master page output a dynamic generated JSON object in the footer of each page.
I needed to have my js popup login dialog box support localization. So using JSON.NET for serialization, I created a public key/value collection property of the master page that pages could access in order place key/values into such as phrase key/localized phrase pairs. The master page then renders a dynamic JSON object that holds these values so that static js files could reference these dynamic values.
For the js login box I have the masterpage set the localized values. This made sense because the masterpage also includes the login.js file.
I do commend you on your concern over the number of http requests being made from the client and the payload being returned. Too many people I know and work with overlook those easy optimizations. However, any time I run into the same issue you're having (which is actually quite often), I have found I've usually either taken a wrong turn somewhere or am trying to solve the problem the wrong way.
As far as your JS question goes, I think Frank Schwieterman in the comments above is correct. I'd be looking at ways to expose the dynamic parts of your JS through setters. A really basic example would be if you have want to display a customized welcome message to users on login. In your JS file, you can have a setMessage(message) method exposed. That method would then be called by the page including the script. As a result, you'd have something like:
<body onLoad="setMessage('Welcome' + <%= user.FirstName %>);">
This can obviously be expanded by passing objects or methods into the static JS file to allow you the functionality you desire.
In response to the CSS question, I think you can gain a lot from the approach Shawn Steward from the comments makes a good point. You can define certain static parts of your CSS in the base file and then redefine the parts you want to change in other files. As a result, you can then dictate the look of your website by which files you're including. Also, since you don't want to take the hit for extra http requests (keep in mind, if you set those files to be cached for a week, month, etc. it's a one time request), you can do something like combining the CSS files into a single file at compilation or runtime.
Something like the following links may be helpful in pointing you in the right direction:
http://geekswithblogs.net/rashid/archive/2007/07/25/Combine-Multiple-JavaScript-and-CSS-Files-and-Remove-Overheads.aspx
http://www.asp.net/learn/3.5-SP1/video-296.aspx?wwwaspnetrdirset=1
http://dimebrain.com/2008/04/resourceful-asp.html
By utilizing the combining at run or compile time you can gain the best of both world by allowing you to logically separate CSS and JS files, yet also gaining the reduction of payload and requests that comes with compressing and combining files.

Categories