inline-critical/index.js

91 lines
2.6 KiB
JavaScript
Raw Normal View History

2014-08-04 00:01:39 +02:00
/**
* Module to inline styles while loading the existing stylesheets async
*
* @author Ben Zörb @bezoerb https://github.com/bezoerb
* @copyright Copyright (c) 2014 Ben Zörb
*
* Licensed under the MIT license.
* http://bezoerb.mit-license.org/
* All rights reserved.
*/
'use strict';
var fs = require('fs');
var path = require('path');
var cave = require('cave');
2014-10-20 16:44:53 +02:00
var reaver = require('reaver');
2014-08-04 00:01:39 +02:00
var cheerio = require('cheerio');
var CleanCSS = require('clean-css');
2014-11-25 17:21:43 +01:00
var slash = require('slash');
/**
* Fixup slashes in file paths for windows
*/
function normalizePath(str) {
return process.platform === 'win32' ? slash(str) : str;
}
2014-08-04 00:01:39 +02:00
module.exports = function(html, styles, options) {
2014-08-04 00:01:39 +02:00
var $ = cheerio.load(String(html));
var links = $('link[rel="stylesheet"]');
var noscript = $('<noscript>\n</noscript>');
var o = options || {};
2014-08-04 00:01:39 +02:00
// minify if minify option is set
if (o.minify) {
2014-08-04 00:01:39 +02:00
styles = new CleanCSS().minify(styles);
}
// insert inline styles right before first <link rel="stylesheet" />
links.eq(0).before('<style type="text/css">\n' + styles + '\n</style>\n');
// insert noscript block right after stylesheets
links.eq(0).first().after(noscript);
var hrefs = links.map(function(idx, el) {
2014-10-20 16:44:53 +02:00
return $(this).attr('href');
2014-08-04 00:01:39 +02:00
}).toArray();
// extract styles from stylesheets if extract option is set
if (o.extract) {
if (!o.basePath) {
throw new Error('Option `basePath` is missing and required when using `extract`!');
}
2014-10-20 16:44:53 +02:00
hrefs = hrefs.map(function(href) {
var file = path.resolve(o.basePath, href);
if (!fs.existsSync(file)) {
return;
}
var diff = cave(file, { css: styles });
2014-10-20 16:44:53 +02:00
fs.writeFileSync(reaver.rev(file, diff), diff);
2014-11-25 17:21:43 +01:00
return reaver.rev(normalizePath(href), diff);
});
}
2014-10-20 16:44:53 +02:00
// wrap links to stylesheets in noscript block so that they will evaluated when js is turned off
links.each(function (idx) {
var el = $(this);
el.attr('href', hrefs[idx]);
noscript.append(el);
noscript.append('\n');
});
2014-08-04 00:01:39 +02:00
// build js block to load blocking stylesheets
$('body').append('<script>\n' +
'(function(d,u){' +
'for (var i in u) {' +
'var l=d.createElement(\'link\');' +
'var r=d.getElementsByTagName(\'script\')[0];' +
2014-08-04 00:01:39 +02:00
'l.type=\'text/css\';' +
'l.rel=\'stylesheet\';' +
'l.media=\'only x\';' +
2014-08-04 00:01:39 +02:00
'l.href=u[i];' +
'r.parentNode.insertBefore(l,r);' +
2014-09-02 08:26:10 +02:00
'(function(l){setTimeout( function(){l.media=\'all\';});})(l)' +
2014-08-04 00:01:39 +02:00
'}' +
'}(document,[\'' + hrefs.join('\',\'') + '\']));\n' +
'</script>\n');
return new Buffer($.html());
};