Tutorial: Speed up CSS load on Umbraco 8
Reducing load times with code-splitting
With larger sites, it is usually the case that whole sections won’t ever be touched by a single user’s journey. This can unnecessarily add load time, and waste valuable seconds for users.
An easy solution to implement is code splitting, creating small bundles of CSS that are relevant to the section users are on. This can be further sped up by using Umbraco’s Client Dependency Module to stitch these tiny packages together, creating lightweight CSS files with little redundant code.
What we are going to do:
- Create a gulp task that creates separate CSS files for each SCSS file
- Use Umbraco & Client Dependency to render minimal CSS for each view
Getting Started
This is primarily a front end tutorial, so let’s assume that you have Umbraco set up and running. This tutorial has been tested on V8 of Umbraco, although the same process works equally well on V7 projects.
Prerequisites
- A basic understanding of using npm & the command line
- A basic understanding of SCSS, and JS
- A basic understanding of Umbraco Templates & Partials
Setting Up Gulp
To get started, we need to install gulp & the gulp-cli, so open up the cli in the root of your project:
npm install gulp-cli -g
npm install gulp gulp-autoprefixer gulp-sass gulp-changed -D
Gulp is a tool to automate repetitive tasks, and has endless plugins available for it. We have also installed:
- gulp-autoprefixer which will handle prefixing for browser support for us
- gulp-sass which converts SCSS down to CSS
- gulp-changed which watches for file changes, speeding up further tasks
Next job is to create a gulpfile.js file in the root of our project. This is the base file where all tasks live.
Creating Separate Tasks
As gulp files can turn to spaghetti pretty quickly, I prefer to split out all my tasks into reusable separate modules, so lets create a folder in the root called gulp-tasks and create a new js file in there called scss-compiler, that unsurprisingly will hold the code we use to compile SCSS.
The scss-compiler will contain a versatile task which creates a CSS equivelent version of each SCSS file, in the root CSS folder (which umbraco will have already created for us).
What’s happening here? Well first, we are exporting the module, which we will later import into our main gulpfile. It expects arguments of the plugins required to run it, and the filePaths it is going to be processing.
The SassPaths holds any framework dependent styles, which in the example about, is for foundation sites.
Next gulp.src runs through each filePath supplied and:
- changed checks if the file supplied has changes, else it will ignore it, saving valuable compiling time
- sass (a.k.a gulp-sass) generates static CSS from the SCSS supplied, “compressed” meaning that it is smushed down to have minimal white spaces
- autoprefixer will take any browser specific needs and prefix them for the specified browsers, for this case, its the last two versions of the Edge, Chrome and Firebox, and then IE11 up (so only…)
- gulp.dest puts our transformed mini file in the css folder
- done tells gulp that this task is finished, as Gulp runs asynchronously using promises, it needs a resolution to this promise.
Feeding the Gulpfile
In the gulp file, we need to first declare all of the packages we intend to use
// gulpfile.js
const gulp = require('gulp');const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const changed = require('gulp-changed');
Our newly created module can also be imported into the gulpfile
// gulpfile.js
const gulp = require('gulp');const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const changed = require('gulp-changed');const sassCompiler = require('./gulp-tasks/scss-compiler');
Which means we are all hooked up and ready to build our first task. As this will be our main task, we can use gulp’s default task, allowing us to just type gulp
in the command line to run it.
To more easily allow us to run our SCSS tasks in parallel we can create a const
to keep things tidy
const defaulSCSSTasks = gulp.parallel(sassCompiler(gulp, sass, changed, autoprefixer, 'scss/*.scss'));
We can run multiple tasks inside the parallel by comma separating them. Using “*” we can catch all files within a folder, making a robust and short directory for gulp to read through.
We add this new const
into the default, and create a gulp watch to check for changes in the files.
Structuring SCSS Nicely
My preference with structuring the SCSS is to follow the structure of umbraco templates:
scss/*.scss <-- Global files
scss/views/*.scss <-- Views
scss/views/partials/*.scss <-- Partials
This makes pairing files a piece of cake, each view and partial is paired up with its own SCSS file, keeping everything tidy. For bonus points, wrap each of your views and partials in a unique class, and enjoy the extra benefits of cascading styles and nesting.
// In your view or partial:
<div class="partial-name">
<div class="foo">
...
</div>
<div class="bar">
...
</div>
</div>// In your SCSS filepartial-name {
.foo{
... specificity ;)
}
.bar{
...
}
}
Dreamy.
Linking Up Variables
One of the more tricky sides of this approach is that because each file is seperate when output, we need to make sure that they import global variables. This can be done by adding imports to the top of each file, as they only reference files with variables in, size isn’t affected with duplicate code.
@import 'settings';
@import 'foundation';
Again, the example above is for foundation, but the principle works the same for other frameworks.
Run your gulp file with gulp -w
and all being well, you should have a host of CSS files in your CSS
folder.
Client Dependencies
The final piece of the puzzle is hooking up Client Dependency. Umbraco’s built in CSS and JS optimiser and compiler.
It comes with a host of handy features, and is well worth digging into to get the most of.
In your master template, (where ever your <head> lives
), you will need to add
@using ClientDependency.Core.Mvc
Alongside your other using
statements, and just before your closing </head>
tag, you will need to insert
@Html.Raw(Html.RenderCssHere())
This is the injection site for the final <link>
tag Client dependency generates.
Finally, in each view/partial that has it’s own styles, add in a reference to it’s css file at the top:
@using ClientDependency.Core.Mvc
@{
Html.RequiresCss("~/css/carousel.css");
}
Now, sit back, and enjoy your speedy css.
Bonus: Debugging
While this technique creates Uber minified cached files on the fly in live mode, you get the pleasure of separate files for each CSS file while working locally, just make sure in your web.config
you have debug="true"
set.
You may from time to time need to give Client Dependency a kick, which is simple enough, just locate the config(Config/ClientDependency.config
) and bump up the version number by one.