Sitecore MVC - Using static assets generated by Gulp
In this blog post I'll explain how you can use static assets created by Gulp within your Sitecore MVC solutions.
Reason for switching over to Gulp
Wait, hold on, switching out the "out of the box" mechanism for working with bundling and minification of frontend assets (styles and script files) in ASP.NET MVC? But why switch out something that already works, and is used in various ASP.NET MVC projects, including Sitecore MVC?
While I understand it can sound a bit strange, there are a couple of reasons to why you want to switch over to using Gulp as the primary tool for generating your static assets, including (but not limited to):
- The static assets are created once at build-time rather than during runtime
- The static assets can be uploaded to i.e. Azure for serving off as a content distribution network (CDN) resource
- Different versions of the static assets can be served simultaneously from a CDN, supporting rollback scenarios
- ASP.NET Core MVC already supports using Gulp for static assets
- Gulp is well-known to frontend devs, who'll be interacting the most with JavaScript and CSS.
To emphasize the last point, I'm regularly met with frustrated frontend devs, who usually give me that look when I tell them to use Visual Studio to work with their code...
All jokes aside (and having been entangled in the realm of frontend myself), the default development flow in ASP.NET MVC doesn't really match up with the myriad of frontend tools available today. Instead of forcing frontend devs to work within the boundaries of the development flow and tooling found in Visual Studio, frontend devs should be able to stay in the tool they prefer using in order to maximize their productivity as much as possible.
What's that Gulp thingy again?
If you have been playing around with Sitecore Helix, or more specifically the build system in the reference implementation Sitecore Habitat, you should be familiar with Gulp.
If you haven't been using the Habitat build system, or been exposed to Gulp in general, the official description is that:
Gulp is a toolkit for automating painful or time-consuming tasks in your development workflow, so you can stop messing around and build something
In Habitat, the build system includes a number of tasks that will listen for changes to files of a given type and automatically deploy these to your local Sitecore development instance. This includes changes to .NET assemblies after a build, changes to ASP.NET MVC Razor view files and changes to frontend assets (like styles and scripts).
If you want to get started using Gulp, but don't know how or where to get started with Gulp, I'd recommend starting with the beginners guide from CSS tricks and follow up with the official documentation from Gulp.
The big picture
Now that the reason for switching over to Gulp are out in the open, let's look at how the different pieces fits together in terms of the interaction between Gulp and Sitecore MVC:
First, the Gulp file generates the static assets for the styles and script, along with a manifest. The manifest file contains mappings of the original paths to the revisioned paths, such as:
When a static asset (style or script) changes content, the revisioned paths within the manifest are changed to reflect that a new version of the static asset is now present.
During the request of static assets, the Sitecore MVC layout will never point directly to the revisioned path of the static assets, but instead use the original paths. The static asset resolver receives the request from the layout, which in turn uses the manifest to lookup the revisioned paths. If the requested original path is found in the manifest, the revisioned path is returned to the static asset resolver, which caches (in-memory) the revisioned path, before returning it to the layout.
Coolbits: The manifest provides a way to solve the issue of cache busting static assets, since the layout never directly knows which revision to use. This is entirely up to the manifest to decide.
If a new version of a static asset comes along, the manifest will make sure that the new version of the static asset will be fetched by the static asset resolver. When this happen, the static assets cached in the clients browser will be forced to fetch the new static assets, since they now have a different revision as part of their paths in the style and script tags.
The minimal viable Gulp file
To quickly get you up and running, I've provided a very basic Gulp file, which enables:
- Building of styles using Sass as the preprocessor
- Building of scripts using ECMAScript 6 features
- Building a manifest for the styles and scripts to be used by the .NET static assets resolver
You can either include the following Gulp file, or create your own - however, please make sure that you end up building a manifest, as this is the required contract needed for the static assets resolver to work:
The Gulp file itself is based on the sample Gulp file provided by people behind Gulp, which you can find here.
Using the static assets in Sitecore MVC
With the Gulp file in place, you are now able to generate static assets from your styles and scripts. In order to use these generated static assets in your Sitecore MVC solution, you need to include the following files from GitHub in your codebase:
Once done, you should able to use the @StaticAssets
MVC Html helpers in your shared _Layout.cshtml
file, like so:
Additionally, you will also have to hook into Sitecore's initialize pipeline and bootstrap the static asset resolver, in order to load the static assets from the generated manifest file. This can be done using the following patch file:
Optional: Including the static assets in the deployment package
If you decide to deploy your static assets together with your Sitecore solution (meaning that you'll use a Web Publish to push out your custom solution code to your Sitecore IIS web root folder), you'll quickly discover some issues when you try to deploy your code - well, I did. To sum up, the problem is that the static assets from the output are not included as part of the package being developed, mainly because the output isn't included as part of the C# project. However, I didn't want to do this, since it meant that these files eventually had to go into version control, which doesn't really make sense if you think about it.
With a little help from Google, I discovered that a solution actually exists to this problem, since you can include "extra files" in the deployment package, as described in ASP.NET Web Deployment using Visual Studio: Deploying Extra Files. In my example, the C# project file needed to include the following configuration, which will include the static assets as part of the deployment package:
What if I want to use Grunt, Webpack or [Insert shiny frontend tech here]?
Good question, and the answer is pretty simple; just do it! In fact, when I initially sketched out the content of this blog post, I experimented using both Grunt and Webpack, which I got working in a similar way to Gulp. The reason for this is that each of these have plugins that allow you to generate manifests and because the static asset resolver simply expects a manifest containing of key/value pairs, you should be all set.
Final words
I'd like to say a big thanks to Anthony Chu for his article on Using Grunt/Gulp for Bundling and Minification in ASP.NET, which pointed me in the right direction. I'd also like to give a shout out to my colleague Allan Kimmer Jensen for helping me with the Gulp specific details, related to generating the manifest file.
I should also add that there will be a NuGet package available, containing the code gists and configuration...
As always, if you got additional details to the content explained in this blog post, or feedback in general, please drop me a note in the comment section below.