Skip to content

Instantly share code, notes, and snippets.

@lloiacono
Created November 30, 2016 08:43
Show Gist options
  • Save lloiacono/b629cb603f38490c78366ec71c64c2b4 to your computer and use it in GitHub Desktop.
Save lloiacono/b629cb603f38490c78366ec71c64c2b4 to your computer and use it in GitHub Desktop.
Grunt Penthouse and Css minify for extracting critical Css for embedding into HTML-head

Dutchwebworks Grunt Penthouse & Cssmin workflow

By Dennis Burger, Waddinxveen aug. 2014

This Grunt workflow task is using grunt-penthouse and grunt-contrib-cssmin plugins to extract Critical Path (above-the-fold content) Css from various URL's. This extracted Css can then be (re)inserted as embedded Css (using a HTML <style> -tag) back into the HTML-head of the corresponding webpage.

Using a lazy-loading technique, the other Css files could be loaded into the HTML-DOM later by Javascript. This greatly speeds up the initial page rendering and perception of page speed.

Google PageSpeed Insights recommends inlining this Critical Path Css into the HTML page to stop Css rendering blocking issues in the webbrowser. Website performance (and initial page render speed) are more and more becoming a important search-engine ranking factor.

Prerequisites

One-time setup

When NodeJS and Grunt command-line tools (CLI) are installed open a Terminal (or MS-DOS command-line) window and cd into the directory where the Gruntfile.js file resides.

First make sure the required NPM Node packages (Grunt plugins) are installed in the familiar node_modules/ directory (ignore this directory in version-control) by running:

sudo npm install

On Windows, omit the sudo part.

Grunt configuration

Open the Gruntfile.js and configure the various path's in the config section. Like the (local) domain name of the website and the required (PhantomJS) screen width and height. The height is important, every Css rule used within this space (by the webbrowser) will be extracted.

Pages and their separate critical Css files

In the penthouse section, change, copy/paste the config blocks for each page (URL). Each page will have it's own critical (minified) Css file. Name the Css files accordingly.

Generating the Critical Path Css

First open a Terminal (or MS-DOS command-line) window to cd into the same directory as the Gruntfile.js. Then run the (default) Grunt task:

grunt

This will open each configured page URL (in the penthouse section) using a headless / webkit (command-line) webbrowser called PhantomJS. The Grunt penthouse task will extract the visible Css (using the configured width and height) and save it to the outfile output file.

A separate Grunt task named cssmin (will automatically run after the penthouse task) will minify the extracted Css into a separate *.min.css version of each Css file.

Embed the critical extracted Css

The last step is to (manually) embed this extract minified Css into the corresponding page's HTML-head.

Or one could use for example PHP to embed this extracted critical Css directly into the HTML-head from the minfied Css file as a <style> tag.

/*
Grunt task for extracting critical Css for embedding into HTML-head with <style> tag
Dutchwebworks, aug. 2014
*/
module.exports = function(grunt) {
/**********************************************************************
1. Load all Grunt dependency NPM packages listed in `package.json`
**********************************************************************/
grunt.loadNpmTasks('grunt-penthouse');
grunt.loadNpmTasks('grunt-contrib-cssmin');
/**********************************************************************
2. Configure Grunt tasks
**********************************************************************/
grunt.initConfig({
pkg: grunt.file.readJSON('./package.json'), // Json file to read
config: {
domainName: 'http://website.com', // Domain name of the site
sceenWidth: 1024, // PhantomJS screen width
screenHeight: 700, // PhantomJS screen height
cssDir: './css', // Local css path
},
meta: { // List of meta-data used by other tasks like file banners
banner: '/*!\n' + // Banner info prefixed to minified files (see `package.json`)
' * ' + 'Name: <%= pkg.name %>\n' +
' * ' + 'Author: <%= pkg.author %>\n' +
' * ' + 'Version: <%= pkg.version %>\n' +
' * ' + 'Date: <%= grunt.template.today("yyyy-mm-dd") %>\n' +
' */\n'
,
},
penthouse: {
// Homepage
homepage: {
url: '<%= config.domainName %>/', // Using a slash for the homepage
width: '<%= config.sceenWidth %>',
height: '<%= config.screenHeight %>',
css: '<%= config.cssDir %>/style.css', // Input Css file to extract Css from
outfile: '<%= config.cssDir %>/_critical_homepage_<%= config.sceenWidth %>x<%= config.screenHeight %>px.css', // Output file containing the critical Css
},
// Product catalog page
catalog: {
url: '<%= config.domainName %>/catalog', // Permalink URL of catalog page
width: '<%= config.sceenWidth %>',
height: '<%= config.screenHeight %>',
css: '<%= config.cssDir %>/style.css', // Input Css file to extract Css from
outfile: '<%= config.cssDir %>/_critical_catalog_<%= config.sceenWidth %>x<%= config.screenHeight %>px.css', // Output file containing the critical Css
},
},
cssmin: {
options: {
// banner: '<%= meta.banner %>' // Optional minify banner
},
minify: {
expand: true,
cwd: '<%= config.cssDir %>',
// src: ['*.css', '!style.css', '!print.css', '!*.min.css'], // demo of excluding files
src: ['_*.css'], // Only minify files starting with underscore
dest: '<%= config.cssDir %>/',
ext: '.min.css'
}
}
});
/**********************************************************************
3. Registered Grunt tasks
**********************************************************************/
grunt.registerTask('default', ['penthouse', 'cssmin']);
};
The MIT License (MIT)
Copyright (c) 2014 Dennis Burger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
"name": "grunt-penthouse-cssmin-test",
"author": "Dennis Burger <[email protected]>",
"version": "0.1.0",
"main": "gruntfile.js",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-penthouse": "~0.1.1",
"grunt-contrib-cssmin": "~0.10.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment