Managing CDNs in Web Parts and JSLink Files

Scot Hillier

by Scot Hillier on 2/27/2015

Share this:

Article Details

Date Revised:

Applies to:
CDN Manager, GitHub, Scot Hillier, SharePoint development, SharePoint Online, third-party JavaScript libraries

About a month ago, I released the CDN Manager app for managing Content Delivery Network (CDN) references in SharePoint 2013. The goal of creating the app initially came from discussions with David Mann and Marc Anderson around the idea of supporting “community developers” that were doing things like creating simple Script Editor web parts and light JSLink. We put together something quickly, pushed it out to the public, and then invited the community to participate in improving the app. You can read about the initial effort here.

I’m pleased to say that we got a great response from the community. While several people expressed interest in helping us out, Hugh Wood provided the most significant input. Well-known for his expertise in Client-Side Rendering (CSR) techniques in SharePoint 2013, Hugh provided the architecture and guidance necessary to properly support script-on-demand (SOD) and the Minimal Download Strategy (MDS). In addition to SOD and MDS, we also added support for CSS and several capabilities to make CDN management as smooth as possible. Today we’re releasing v2 of the CDN Manager with many significant improvements that make the app a true product.

  • Support for script-on-demand
  • Support for Minimal Download Strategy
  • Support for CSS CDNs like Bootstrap
  • The ability to specify script dependencies between CDNs
  • Yahoo Query Language validation of CDN locations
  • Scripting permission verifications

In this article, I’ll take you through the basics of getting up a running with the new CDN Manager. I’ll show you how to get it installed and then give samples you can use in both Script Editor web parts or JSLink files.

Important: This version of the CDN Manager is not backward compatible. If you installed the first version earlier, use that app to remove any CDN references before upgrading to this version. Otherwise, the injected JavaScript custom action may get “stuck” and need to be removed programmatically.

Getting started

Initially, we wanted to publish the CDN Manager to the SharePoint store. Unfortunately, the app required full control over the host web to properly inject the CDN references. Since the SharePoint store does not permit full-control apps, we published it in the IT Unity GitHub repo. So, to get started, you’ll need to pull the code down from the repo and compile the project.

After you get the code, you have two options for deployment. The simplest approach is to change the Site URL property in Visual Studio to point to a developer site collection and start debugging. The app will be deployed and launch immediately. The second option is to compile the APP file and upload it into your app catalog. Either approach is straightforward. The only special consideration is to make sure that your tenancy supports scripting.

Scripting support is disabled by default in Office 365 and must be enabled at the tenant level. In the SharePoint administration area, examine the settings and look for the “Custom Script” options (Figure 1). Change the options to allow scripting. The CDN Manager checks for these permissions, so you’ll see an error message if scripting is not enabled. Additionally, site collections are created with the current scripting permissions, so you may have to create a new site collection once the permissions are changed.

Content Delivery Network CDN allow custom script Office 365

Figure 1, Allow scripting in the tenancy

Once scripting support is in place, you can launch the app. When the app launches, you’ll be presented with a pre-loaded set of CDN references including jQuery, KnockoutJS and Bootstrap. The CDN Manager will test each reference in the list to ensure the CDN is valid (Figure 2). Invalid CDNs will not be injected into the host web. You can see the results of the validation and the information for each CDN in the app dashboard.

Content Delivery Network CDN script reference validity test

Figure 2, The CDN Manager

In order to inject CDNs into the current site, they must be designated as “active.” You may designate the active CDNs by clicking the “Manage CDN List” button and editing list items (Figure 3). In the list management view, you can also add and delete references. Table 1 explains each field in the list.

Content Delivery Network CDN list items

Figure 3, Working with CDN Manager list items

Table 1, CDN Manager fields




A unique title for the entry. This should be the name of the JavaScript or CSS file (e.g., knockout-2.2.1.js).


This is the URL of the CDN in protocol-relative format. The CDN Manager will automatically add the correct protocol.


A Boolean field indicating whether or not this CDN will be injected into the host web.


The order in which the CDN is injected.


Either “JavaScript” or “StyleSheet” as appropriate.


The title of an entry upon which this entry depends (e.g., jquery-1.11.2.min.js).


The main object namespace in a JavaScript library that can be used to check if the library is properly loaded (e.g., jQuery).

Once you have selected the active CDNs, they can be injected into the host web by clicking the “Inject Active CDNs” button. This action will remove any previously-injected CDNs and then inject the currently-active CDNs you selected. You can also remove the injected CDNs by clicking “Remove All CDNs.”

Working with Script Editor web parts

Once the CDNs are injected, you can easily write JavaScript in a Script Editor web part to use the functionality of the referenced libraries. The app injects an object named CDNManager, which exposes a single method named getScript. This method accepts a single entry or an array of libraries to load and a callback function to notify your code that the library is ready. As a simple example, Listing 1 shows code that will change the color of the left-hand navigation elements on a SharePoint page to red.

Listing 1, jQuery in a Script Editor web part

 CDNManager.getScript('jquery-1.11.2.min.js', function () {
    jQuery('.menu-item-text').css('color', 'red');

If you need to load multiple libraries, simply specify them as an array. Listing 2 shows code that loads both jQuery and KnockoutJS. When the callback function fires, a view model is then bound to HTML.

Listing 2, Loading multiple libraries

<div data-bind='text: firstName'></div>
<div data-bind='text: lastName'></div>

  CDNManager.getScript(['jquery-1.11.2.min.js','knockout-2.2.1.js'],function() {
    var viewModel = {
        'firstName': ko.observable('Scot'),
        'lastName': ko.observable('Hillier')

When working with Script Editor web parts, it’s important to remember that the presence of the <script> tag will break the Minimal Download Strategy feature. Therefore, you should turn off the MDS feature in sites where you intend to use this approach.

Working with JSLink

JSLink is a capability of SharePoint 2013 that allows customization of list fields, forms and views using client-side code. Because JSLink works by linking custom JavaScript in a page, it is an ideal mechanism for utilizing the libraries injected by the CDN Manager. I won’t go into detail concerning the fundamentals of JSLink because there are plenty of references out there like this MSDN article. Instead, I’ll assume a basic understanding and show you how the CDN Manager can make your life easier.

Beginning with the end in mind, Figure 4 shows an out-of-the-box task list that has been customized with JSLink. In particular, the “% Complete” field has been modified to display a Bootstrap progress bar instead of the normal text information. Additionally, a Bootstrap tooltip is used to display the actual text value on hover.

Content Delivery Network CDN Bootstrap progress bar tooltip

Figure 4, A bootstrap progress bar and tooltip

A JavaScript file named progress.js, which implements the customization, is included in the repository along with the CDN Manager source code. The file is also available as a GitHub Gist. In order to get the sample working, simply inject the jQuery, bootstrap JavaScript and bootstrap CSS libraries that come pre-loaded in the app. Next, upload the progress.js file to the Master Page gallery and set the JSLink property on an out-of-the-box task list. Listing 3 shows the complete source code for progress.js.

Listing 3, Creating a Bootstrap progress bar

(function () {
    // Initialize the variables for overrides objects
    var overrideCtx = {};
    overrideCtx.Templates = {};

    overrideCtx.Templates.Fields = {
        'PercentComplete': { 'View': '<div class="progress" data-toggle="tooltip" data-placement="right"
         title="<#=ctx.CurrentItem.PercentComplete.replace(" %", "")#>%"><div class="progress-bar"
         role="progressbar" aria-valuenow="<#=ctx.CurrentItem.PercentComplete.replace(" %", "")#>"
         aria-valuemin="0" aria-valuemax="100" style="width:
         <#=ctx.CurrentItem.PercentComplete.replace(" %", "")#>%;"></div></div>' }


(function () {
    "use strict";

    if (typeof (_spBodyOnLoadCalled) === 'undefined' || _spBodyOnLoadCalled) {
    else {

    function load () {
        CDNManager.getScript(['jquery-1.11.2.min.js','bootstrap.min.js'], ready);

    function ready () {


Listing 3 contains two anonymous functions. The first function is standard JSLink functionality that creates an override template for the “PercentComplete” field in the list. The HTML in the template comes directly from the Bootstrap progress bar sample, modified slightly to include the value of the field. The second anonymous function uses the CDN Manager to load jQuery and the Bootstrap tooltip plugin.

The second anonymous function is particularly interesting because it is written to delay loading of the libraries until the CDNManager object exists. It turns out that the JSLink file will load before the CDNManager object so the loading of the libraries will fail unless it is delayed. The code in the second anonymous function uses the _spBodyOnLoadFunction.push method to ensure the call happens when the CDNManager is available.

While the code in Listing 3 focuses on classic JSLink functionality to modify a list field, it is interesting to note that the code in the file is not limited to interacting with list elements. You could use a JSLink file to inject JavaScript into the page to perform any legitimate function. Furthermore, JSLink won’t break the MDS feature, and the CDN Manager is designed internally to support MDS. This makes the JSLink approach superior to simply dropping Script Editor web parts on the page.

Going forward

Version 2 of the CDN Manager looks to be pretty solid at this point. However, it remains a community project with some room to grow. Therefore, I encourage readers to get the source code, fork the repo and make improvements. We’d like to see the app become widely used to manage CDN references to external libraries and style sheets.

Topic: Development

Sign in with

Or register

  • Any reason why I can't open the CDN manager project with VS2015 comunity?
  • Hi, Scot: This is great! I made a modification so that we could expose our own scripts in this way too. The Yahoo API understandably could not verify scripts hosted on our private servers, so we had to download the files ourselves. Here is the testCDN function I used:

    function testCDN(cdnEntry) {
    var pattern = /^https?:\\/\\/[^\\/]+\\//
    var cdnAuthority = cdnEntry.Url.match(pattern);
    var hostAuthority = getqueryStringValue("SPHostUrl").match(pattern);
    if (cdnAuthority && hostAuthority && cdnAuthority[0] === hostAuthority[0]) {
    return jQuery.ajax({
    url: cdnEntry.Url,
    dataType: 'script',
    success: function (data) {
    error: function (err) {
    } else {
    //Use YQL to test endpoint validity
    return jQuery.ajax({
    url: "" +
    "q=select%20*%20from%20xml%20where%20url%20%3D%20'" +
    encodeURIComponent(cdnEntry.Url) +
    dataType: 'jsonp',
    success: function (data) {
    var diagnostics = data.query.diagnostics;
    if (typeof (diagnostics.url["http-status-code"]) === 'undefined') {
    else {

    error: function (err) {
  • That's great, Dan! Can't wait to see what you come up with. Sounds like a great extension to what we have.
  • Nice work! I was just getting ready to build something similar to this on my own. My approach was something similar to a NuGet app where you point to the CDNs or Git repositories and the app would provision the files to your Site Assets library or some other configured location. Then, you could subscribe to these repositories and be alerted when new releases or versions were made available, plus handle swapping out the old version for the new one. So, rather than start all that from scratch, I'll take you up on the offer and fork the current work and start from there.
  • Excellent work, thank you! Great to see community standards on how we apply custom JS/CSS to SharePoint. Safe, simple, reusable. Keep up the great work! Jeff
  • Awesome work, Scot & Hugh. Definitely using this and pushing other devs to do the same.