Loading rendering wise CSS / JS in Sitecore

For a client, we came across a request for enabling rendering wise CSS and JS assets. This is definitely something that should be used judicially to balance the performance benefit of not load up unnecessary css / js vs the performance hit to load up multiple files over multiple http requests.

None the less, this is how we decided to tackle this requirement.

  • New fields in Controller Rendering template
  • A controller / action to return the list of rendering assets for the given item
  • Partial views that use the data from the above method to output the script / link tags
  • Update the layout file to include a call to the controller action and the views built above

We added fields to the controller rendering template at /sitecore/templates/System/Layout/Renderings/Controller rendering to accept a pipe delimiited list of js / css filenames with relative paths.

We additionally also had a base template created with the same set of fields, which any module could inherit from if needed. So if you had modules for which you might want to change the look and feel / behavior based on datasource, you could use this provision.

The new controller action created here looped through the presentation of the current item, picked up the list of stylesheets and script files and returned the collection back.
This code also looks into rendering datasources, so see if they include assets as well.

    public class RenderingAssetsController : GlassController
    {
        public static Assets GetAssets()
        {
            LayoutDefinition layout = LayoutDefinition.Parse(LayoutField.GetFieldValue(Sitecore.Context.Item.Fields["__Renderings"]));
            Assets assets = new Assets { Scripts = new List<string>(), Stylesheets = new List<string>() };

            if (layout.Devices != null && layout.Devices.Count > 0)
            {
                DeviceDefinition dev = (DeviceDefinition)layout.Devices[0];
                ArrayList renderings = dev?.Renderings;
                if (renderings != null)
                {
                    IEnumerable<RenderingDefinition> renderingDefinitions = renderings.Cast<RenderingDefinition>();

                    foreach (RenderingDefinition renderingDefinition in renderingDefinitions)
                    {
                        if (renderingDefinition.ItemID != null)
                        {
                            Item renderingItem = SitecoreHelper.GetItemByID(renderingDefinition.ItemID);

                            string renderingScript =
                                renderingItem.GetRawValue(
                                    ItemTree.Templates.System.Layout.Renderings.Controller_Rendering.Assets
                                        .Rendering_Scripts.ItemID);

                            if (!string.IsNullOrWhiteSpace(renderingScript))
                            {
                                assets.Scripts.AddRange(
                                    renderingScript.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries)
                                        .Select(s => "/" + s.TrimStart('/')));
                            }

                            string renderingStylesheet =
                                renderingItem.GetRawValue(
                                    ItemTree.Templates.System.Layout.Renderings.Controller_Rendering.Assets
                                        .Rendering_Stylesheets.ItemID);

                            if (!string.IsNullOrWhiteSpace(renderingStylesheet))
                            {
                                assets.Stylesheets.AddRange(
                                    renderingStylesheet.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries)
                                        .Select(s => "/" + s.TrimStart('/')));
                            }

                            if (!string.IsNullOrWhiteSpace(renderingDefinition.Datasource))
                            {
                                Item datasource = SitecoreHelper.GetItemByID(renderingDefinition.Datasource);

                                if (datasource != null)
                                {
                                    Base_Rendering_Assets renderingAssets =
                                        ScService.Cast<Base_Rendering_Assets>(datasource);

                                    if (!string.IsNullOrWhiteSpace(renderingAssets.Rendering_Stylesheets))
                                    {
                                        assets.Stylesheets.AddRange(
                                            renderingAssets.Rendering_Stylesheets.Split(new[] {'|'},
                                                    StringSplitOptions.RemoveEmptyEntries)
                                                .Select(s => "/" + s.TrimStart('/')));
                                    }

                                    if (!string.IsNullOrWhiteSpace(renderingAssets.Rendering_Scripts))
                                    {
                                        assets.Scripts.AddRange(
                                            renderingAssets.Rendering_Scripts.Split(new[] {'|'},
                                                    StringSplitOptions.RemoveEmptyEntries)
                                                .Select(s => "/" + s.TrimStart('/')));
                                    }
                                }
                            }
                        }
                    }
                }
            }

            assets.Scripts = assets.Scripts.DistinctBy(s => s).ToList();
            assets.Stylesheets = assets.Stylesheets.DistinctBy(s => s).ToList();

            return assets;
        }
    }

The partials created would be simple – they just take in the list of assets and output them in the right format.

RenderingScripts Partial

@using System.Linq

@model List<string>

@if (Model != null && Model.Any())
{
    foreach (string script in Model)
    {
        <script type="text/javascript" src="@script"></script>
    }
}

RenderingStylesheets Partial

@using System.Linq

@model List<string>

@if (Model != null && Model.Any())
{
    foreach (string stylesheet in Model)
    {
        <link rel="stylesheet" href="@stylesheet" />
    }
}

In the layout code, you would invoke the controller action above and then embed the partials in the intended location in the html passing in the list of assets returned from the controller action call.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s