The other day I was poking around Sitecore.Forms.Mvc.dll — this assembly ships with Web Forms for Marketers (WFFM), and is used when WFFM is running on Sitecore MVC — and noticed WFFM does some bundling of JavaScript and CSS files:
WFFM uses the above class as an <initialize> pipeline processor. You can see this defined in Sitecore.Forms.Mvc.config:
This got me thinking: why not build my own class to serve as an <initialize> pipeline processor to bundle my CSS and JavaScript files?
As an experiment I whipped up the following class to do just that:
using System.Collections.Generic; using System.Linq; using System.Web.Optimization; using Sitecore.Pipelines; namespace Sitecore.Sandbox.Forms.Mvc.Pipelines { public class RegisterAdditionalFormBundles { public RegisterAdditionalFormBundles() { CssFiles = new List<string>(); JavaScriptFiles = new List<string>(); } public void Process(PipelineArgs args) { BundleCollection bundles = GetBundleCollection(); if (bundles == null) { return; } AddBundle(bundles, CreateCssBundle()); AddBundle(bundles, CreateJavaScriptBundle()); } protected virtual BundleCollection GetBundleCollection() { return BundleTable.Bundles; } protected virtual Bundle CreateCssBundle() { if (!CanBundleAssets(CssVirtualPath, CssFiles)) { return null; } return new StyleBundle(CssVirtualPath).Include(CssFiles.ToArray()); } protected virtual Bundle CreateJavaScriptBundle() { if (!CanBundleAssets(JavaScriptVirtualPath, JavaScriptFiles)) { return null; } return new ScriptBundle(JavaScriptVirtualPath).Include(JavaScriptFiles.ToArray()); } protected virtual bool CanBundleAssets(string virtualPath, IEnumerable<string> filePaths) { return !string.IsNullOrWhiteSpace(virtualPath) && filePaths != null && filePaths.Any(); } private static void AddBundle(BundleCollection bundles, Bundle bundle) { if(bundle == null) { return; } bundles.Add(bundle); } private string CssVirtualPath { get; set; } private List<string> CssFiles { get; set; } private string JavaScriptVirtualPath { get; set; } private List<string> JavaScriptFiles { get; set; } } }
The class above basically takes in a collection of CSS and JavaScript file paths as well as their virtual bundled paths — these are magically populated by Sitecore’s Configuration Factory using values provided by the configuration file shown below — iterates over both collections, and adds them to the BundleTable — the BundleTable is defined in System.Web.Optimization.dll.
I then glued everything together using a patch configuration file:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <pipelines> <initialize> <processor patch:after="processor[@type='Sitecore.Forms.Mvc.Pipelines.RegisterFormBundles, Sitecore.Forms.Mvc']" type="Sitecore.Sandbox.Forms.Mvc.Pipelines.RegisterAdditionalFormBundles, Sitecore.Sandbox"> <CssVirtualPath>~/wffm-bundles/styles.css</CssVirtualPath> <CssFiles hint="list"> <CssFile>~/css/uniform.aristo.css</CssFile> </CssFiles> <JavaScriptVirtualPath>~/wffm-bundles/scripts.js</JavaScriptVirtualPath> <JavaScriptFiles hint="list"> <JavaScriptFile>~/js/jquery.min.js</JavaScriptFile> <JavaScriptFile>~/js/jquery.uniform.min.js</JavaScriptFile> <JavaScriptFile>~/js/bind.uniform.js</JavaScriptFile> </JavaScriptFiles> </processor> </initialize> </pipelines> </sitecore> </configuration>
I’m adding the <initialize> pipeline processor shown above after WFFM’s though theoretically you could add it anywhere within the <initialize> pipeline.
The CSS and JavaScript files defined in the configuration file above are from the Uniform project — this project includes CSS, JavaScript and images to make forms look nice, though I am in no way endorsing this project. I only needed some CSS and JavaScript files to spin up something quickly for testing.
For testing, I built the following View — it uses some helpers to render the <link> and <script> tags for the bundles — and tied it to my Layout in Sitecore:
@using System.Web.Optimization @using Sitecore.Mvc @using Sitecore.Mvc.Presentation <!DOCTYPE html> <html> <head> <title></title> @Styles.Render("~/wffm-bundles/styles.css") @Scripts.Render("~/wffm-bundles/scripts.js") </head> <body> @Html.Sitecore().Placeholder("page content") </body> </html>
I then built a “Feedback” form in WFFM; mapped it to the “page content” placeholder defined in the View above; published it; and pulled it up in my browser. As you can see the code from the Uniform project styled the form:
For comparison, this is what the form looks like without the <initialize> pipeline processor above:
If you have any thoughts on this, or have alternative ways of bundling CSS and JavaScript files in your Sitecore MVC solutions, please share in a comment.
