mirror of
https://github.com/danog/inline-critical.git
synced 2024-11-30 04:29:07 +01:00
Switched to jsdom (#240)
This commit is contained in:
parent
da6b0fc1b8
commit
e37904080a
8
cli.js
8
cli.js
@ -3,6 +3,7 @@
|
||||
const os = require('os');
|
||||
const fs = require('fs');
|
||||
const meow = require('meow');
|
||||
const chalk = require('chalk');
|
||||
const indentString = require('indent-string');
|
||||
const stdin = require('get-stdin');
|
||||
const css = require('css');
|
||||
@ -42,6 +43,7 @@ const cli = meow(help, {
|
||||
minify: {
|
||||
type: 'boolean',
|
||||
alias: 'm',
|
||||
default: true,
|
||||
},
|
||||
extract: {
|
||||
type: 'boolean',
|
||||
@ -101,10 +103,10 @@ cli.flags = _.reduce(
|
||||
);
|
||||
|
||||
function processError(err) {
|
||||
process.stderr.write(indentString('Error: ' + (err.message || err), 4));
|
||||
process.stderr.write(chalk.red(indentString('Error: ' + (err.message || err), 2)));
|
||||
process.stderr.write(os.EOL);
|
||||
process.stderr.write(indentString(help, 4));
|
||||
// Process.exit(1);
|
||||
process.stderr.write(indentString(help, 2));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function read(file) {
|
||||
|
269
index.js
269
index.js
@ -13,42 +13,20 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const isString = require('lodash/isString');
|
||||
const isRegExp = require('lodash/isRegExp');
|
||||
const filter = require('lodash/filter');
|
||||
const _ = require('lodash');
|
||||
const UglifyJS = require('uglify-js');
|
||||
const reaver = require('reaver');
|
||||
const postcss = require('postcss');
|
||||
const discard = require('postcss-discard');
|
||||
const cheerio = require('cheerio');
|
||||
const render = require('dom-serializer');
|
||||
const CleanCSS = require('clean-css');
|
||||
const slash = require('slash');
|
||||
const normalizeNewline = require('normalize-newline');
|
||||
const resolve = require('resolve');
|
||||
const detectIndent = require('detect-indent');
|
||||
const prettier = require('prettier');
|
||||
|
||||
const Dom = require('./src/dom');
|
||||
const {prettifyCss, extractCss} = require('./src/css');
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
minify: true,
|
||||
extract: false,
|
||||
polyfill: true,
|
||||
ignore: [],
|
||||
stylesheets: [],
|
||||
replaceStylesheets: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* Get loadcss + cssrelpreload script
|
||||
*
|
||||
* @returns {string} Minified loadcss script
|
||||
*/
|
||||
function getScript() {
|
||||
const loadCssMain = resolve.sync('fg-loadcss');
|
||||
const loadCssBase = path.dirname(loadCssMain);
|
||||
|
||||
const loadCSS = read(path.join(loadCssBase, 'cssrelpreload.js'));
|
||||
return UglifyJS.minify(loadCSS).code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixup slashes in file paths for windows
|
||||
*
|
||||
@ -59,74 +37,6 @@ function normalizePath(str) {
|
||||
return process.platform === 'win32' ? slash(str) : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read file *
|
||||
* @param {string} file Filepath
|
||||
* @returns {string} Content
|
||||
*/
|
||||
function read(file) {
|
||||
return fs.readFileSync(file, 'utf8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the indentation of the link tags
|
||||
* @param {string} html Html source
|
||||
* @param {Cheerio} $el Cheerio object
|
||||
* @returns {string} Indetation
|
||||
*/
|
||||
function getIndent(html, $el) {
|
||||
const regName = new RegExp(_.escapeRegExp(_.get($el, 'name')));
|
||||
const regHref = new RegExp(_.escapeRegExp(_.get($el, 'attribs.href')));
|
||||
const regRel = new RegExp(_.escapeRegExp(_.get($el, 'attribs.rel')));
|
||||
const lines = _.filter(html.split(/[\r\n]+/), line => {
|
||||
return regName.test(line) && regHref.test(line) && regRel.test(line);
|
||||
});
|
||||
return detectIndent(lines.join('\n')).indent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minify CSS
|
||||
* @param {string} styles CSS
|
||||
* @returns {string} Minified css string
|
||||
*/
|
||||
function minifyCSS(styles) {
|
||||
return new CleanCSS().minify(styles).styles; // eslint-disable-line prefer-destructuring
|
||||
}
|
||||
|
||||
function prettifyCSS(styles) {
|
||||
return prettier.format(styles, {parser: 'css'});
|
||||
}
|
||||
|
||||
function extract(css, critical, minify = true) {
|
||||
const minCss = minifyCSS(css);
|
||||
const minCritical = minifyCSS(critical);
|
||||
const diff = normalizeNewline(postcss(discard({css: minCritical})).process(minCss).css);
|
||||
if (minify) {
|
||||
return diff;
|
||||
}
|
||||
|
||||
return prettifyCSS(diff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to prevent cheerio from messing with svg contrnt.
|
||||
* Should be merged afe´ter https://github.com/fb55/htmlparser2/pull/259
|
||||
* @param {string} str HTML String
|
||||
* @returns {array} SVG Strings found in HTML
|
||||
*/
|
||||
const getSvgs = (str = '') => {
|
||||
const indices = [];
|
||||
let start = str.indexOf('<svg', 0);
|
||||
let end = str.indexOf('</svg>', start) + 6;
|
||||
while (start >= 0) {
|
||||
indices.push({start, end});
|
||||
start = str.indexOf('<svg', end);
|
||||
end = str.indexOf('</svg>', end) + 6;
|
||||
}
|
||||
|
||||
return indices.map(({start, end}) => str.substring(start, end));
|
||||
};
|
||||
|
||||
/**
|
||||
* Main function ;)
|
||||
* @param {string} html HTML String
|
||||
@ -141,122 +51,115 @@ function inline(html, styles, options) {
|
||||
html = String(html);
|
||||
}
|
||||
|
||||
const $ = cheerio.load(html, {
|
||||
decodeEntities: false,
|
||||
});
|
||||
|
||||
// Process style tags
|
||||
const inlineStyles = $('head style')
|
||||
.map((i, el) => $(el).html())
|
||||
.get()
|
||||
.join('\n');
|
||||
|
||||
// Only inline the missing styles
|
||||
const missing = extract(styles, inlineStyles, o.minify);
|
||||
const inlined = `${inlineStyles}\n${missing}`;
|
||||
|
||||
const allLinks = $('link[rel="stylesheet"], link[rel="preload"][as="style"]').filter(function() {
|
||||
return !$(this).parents('noscript').length;
|
||||
});
|
||||
|
||||
let links = allLinks.filter('[rel="stylesheet"]');
|
||||
|
||||
const target = o.selector || allLinks.get(0) || $('head script').get(0);
|
||||
const {indent} = detectIndent(html);
|
||||
const targetIndent = getIndent(html, target);
|
||||
const $target = $(target);
|
||||
|
||||
if (!Array.isArray(o.ignore)) {
|
||||
o.ignore = [o.ignore].filter(i => i);
|
||||
}
|
||||
|
||||
if (o.ignore.length > 0) {
|
||||
links = filter(links, link => {
|
||||
const href = $(link).attr('href');
|
||||
return !o.ignore.some(i => (isRegExp(i) && i.test(href)) || i === href);
|
||||
});
|
||||
}
|
||||
const document = new Dom(html, o);
|
||||
|
||||
if (missing) {
|
||||
const elements = [
|
||||
'<style>',
|
||||
indent +
|
||||
missing
|
||||
.replace(/(\r\n|\r|\n)/g, '$1' + targetIndent + indent)
|
||||
.replace(/^[\s\t]+$/g, '')
|
||||
.trim(),
|
||||
'</style>',
|
||||
'',
|
||||
]
|
||||
.join('\n' + targetIndent)
|
||||
.replace(/(\r\n|\r|\n)[\s\t]+(\r\n|\r|\n)/g, '$1$2');
|
||||
const inlineStyles = document.getInlineStyles();
|
||||
const extarnalStyles = document.getExternalStyles();
|
||||
const missingStyles = extractCss(styles, ...inlineStyles);
|
||||
|
||||
if ($target.length > 0) {
|
||||
// Insert inline styles right before first <link rel="stylesheet" /> or other target
|
||||
$target.before(elements);
|
||||
const links = extarnalStyles.filter(link => {
|
||||
// Only take stylesheets
|
||||
const stylesheet = link.getAttribute('rel') === 'stylesheet';
|
||||
// Filter ignored links
|
||||
const href = link.getAttribute('href');
|
||||
return stylesheet && !o.ignore.some(i => (isRegExp(i) && i.test(href)) || i === href);
|
||||
});
|
||||
|
||||
const targetSelectors = [
|
||||
o.selector,
|
||||
':not(noscript) > link[rel="stylesheet"]',
|
||||
':not(noscript) > link[rel="preload"][as="style"]',
|
||||
'head script',
|
||||
];
|
||||
|
||||
const target = document.querySelector(targetSelectors);
|
||||
const inlined = `${inlineStyles}\n${missingStyles}`;
|
||||
|
||||
if (missingStyles) {
|
||||
if (o.minify) {
|
||||
document.addInlineStyles(missingStyles, target);
|
||||
} else {
|
||||
// Just append to the head
|
||||
$('head').append(elements);
|
||||
document.addInlineStyles(prettifyCss(missingStyles, document.indent), target);
|
||||
}
|
||||
}
|
||||
|
||||
if (links.length > 0) {
|
||||
// Modify links and ad clones to noscript block
|
||||
$(links).each(function(idx, el) {
|
||||
if (o.extract && !o.basePath) {
|
||||
throw new Error('Option `basePath` is missing and required when using `extract`!');
|
||||
if (o.replaceStylesheets.length > 0 && links.length > 0) {
|
||||
// Detect links to be removed
|
||||
const [ref] = links;
|
||||
const removable = [...document.querySelectorAll('link[rel="stylesheet"], link[rel="preload"][as="style"]')].filter(
|
||||
link => {
|
||||
// Filter ignored links
|
||||
const href = link.getAttribute('href');
|
||||
return !o.ignore.some(i => (isRegExp(i) && i.test(href)) || i === href);
|
||||
}
|
||||
);
|
||||
|
||||
const $el = $(el);
|
||||
const elIndent = getIndent(html, el);
|
||||
// Add link tags before old links
|
||||
// eslint-disable-next-line array-callback-return
|
||||
o.replaceStylesheets.map(href => {
|
||||
const link = document.createElement('link');
|
||||
link.setAttribute('rel', 'stylesheet');
|
||||
link.setAttribute('href', href);
|
||||
|
||||
const noscript = document.createElement('noscript');
|
||||
noscript.append(link.cloneNode());
|
||||
|
||||
link.setAttribute('rel', 'preload');
|
||||
link.setAttribute('as', 'style');
|
||||
link.setAttribute('onload', "this.onload=null;this.rel='stylesheet'");
|
||||
|
||||
document.insertBefore(link, ref);
|
||||
document.insertBefore(noscript, ref);
|
||||
});
|
||||
|
||||
// Remove old links
|
||||
// eslint-disable-next-line array-callback-return
|
||||
removable.map(link => {
|
||||
if (link.parentElement.tagName === 'NOSCRIPT') {
|
||||
document.remove(link.parentElement);
|
||||
} else {
|
||||
document.remove(link);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Modify links and add clones to noscript block
|
||||
// eslint-disable-next-line array-callback-return
|
||||
links.map(link => {
|
||||
if (o.extract) {
|
||||
const href = $el.attr('href');
|
||||
const file = path.resolve(path.join(o.basePath, href));
|
||||
const href = link.getAttribute('href');
|
||||
const file = path.resolve(path.join(o.basePath || process.cwd, href));
|
||||
if (fs.existsSync(file)) {
|
||||
const orig = fs.readFileSync(file);
|
||||
const diff = extract(orig, inlined, o.minify);
|
||||
const diff = extractCss(orig, inlined, o.minify);
|
||||
const filename = reaver.rev(file, diff);
|
||||
|
||||
fs.writeFileSync(filename, diff);
|
||||
$el.attr('href', normalizePath(reaver.rev(href, diff)));
|
||||
link.setAttribute('href', normalizePath(reaver.rev(href, diff)));
|
||||
} else if (!/\/\//.test(href)) {
|
||||
throw new Error(`Error: file "${href}" not found in "${o.basePath || process.cwd}". Specify base path.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Add each fallback right behind the current style to keep source order when ignoring stylesheets
|
||||
$el.after('\n' + elIndent + '<noscript>' + render(this) + '</noscript>');
|
||||
const noscript = document.createElement('noscript');
|
||||
noscript.append(link.cloneNode());
|
||||
document.insertAfter(noscript, link);
|
||||
|
||||
// Add preload atttibutes to actual link element
|
||||
$el.attr('rel', 'preload');
|
||||
$el.attr('as', 'style');
|
||||
$el.attr('onload', "this.onload=null;this.rel='stylesheet'");
|
||||
link.setAttribute('rel', 'preload');
|
||||
link.setAttribute('as', 'style');
|
||||
link.setAttribute('onload', "this.onload=null;this.rel='stylesheet'");
|
||||
});
|
||||
|
||||
// Only add loadcss if it's not already included
|
||||
const loadCssIncluded = $('script')
|
||||
.get()
|
||||
.some(tag => ($(tag).html() || '').includes('loadCSS'));
|
||||
|
||||
if (!loadCssIncluded && o.polyfill) {
|
||||
// Add loadcss + cssrelpreload polyfill
|
||||
const scriptAnchor = $('link[rel="stylesheet"], noscript')
|
||||
.filter(function() {
|
||||
return !$(this).parents('noscript').length;
|
||||
})
|
||||
.last()
|
||||
.get(0);
|
||||
|
||||
$(scriptAnchor).after('\n' + targetIndent + '<script>' + getScript() + '</script>');
|
||||
}
|
||||
}
|
||||
|
||||
const output = $.html();
|
||||
// Add loadcss if it's not already loaded
|
||||
if (o.polyfill) {
|
||||
document.maybeAddLoadcss();
|
||||
}
|
||||
|
||||
// Quickfix until https://github.com/fb55/htmlparser2/pull/259 is merged/fixed
|
||||
const svgs = getSvgs(html);
|
||||
const quickfixed = getSvgs(output).reduce((str, code, index) => str.replace(code, svgs[index] || code), output);
|
||||
|
||||
return Buffer.from(quickfixed);
|
||||
return Buffer.from(document.serialize());
|
||||
}
|
||||
|
||||
module.exports = inline;
|
||||
|
3572
package-lock.json
generated
3572
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,7 @@
|
||||
"url": "https://github.com/bezoerb/inline-critical/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "0.22.0",
|
||||
"chalk": "^2.4.1",
|
||||
"clean-css": "^4.2.1",
|
||||
"css": "^2.2.4",
|
||||
"detect-indent": "5.0.0",
|
||||
@ -37,6 +37,7 @@
|
||||
"fs-extra": "^7.0.1",
|
||||
"get-stdin": "^6.0.0",
|
||||
"indent-string": "^3.2.0",
|
||||
"jsdom": "^13.1.0",
|
||||
"lodash": "^4.17.11",
|
||||
"meow": "^5.0.0",
|
||||
"normalize-newline": "3.0.0",
|
||||
|
50
src/css.js
Normal file
50
src/css.js
Normal file
@ -0,0 +1,50 @@
|
||||
const prettier = require('prettier');
|
||||
const CleanCSS = require('clean-css');
|
||||
const postcss = require('postcss');
|
||||
const discard = require('postcss-discard');
|
||||
const normalizeNewline = require('normalize-newline');
|
||||
|
||||
/**
|
||||
* Minify CSS
|
||||
* @param {string} styles CSS
|
||||
* @returns {string} Minified css string
|
||||
*/
|
||||
function minifyCss(styles) {
|
||||
return new CleanCSS().minify(styles).styles; // eslint-disable-line prefer-destructuring
|
||||
}
|
||||
|
||||
/**
|
||||
* Prettify CSS
|
||||
* @param {string} styles CSS
|
||||
* @param {object} indent Result object returned by detect-indent
|
||||
* @returns {string} Prettified css string
|
||||
*/
|
||||
function prettifyCss(styles, indent = {}) {
|
||||
return prettier.format(styles, {
|
||||
parser: 'css',
|
||||
useTabs: indent.type === 'tab',
|
||||
tabWidth: indent.amount || 2,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove styles
|
||||
* @param {string} styles CSS
|
||||
* @param {array<string>} css CSS
|
||||
* @returns {string} css string not containing any of the styles defined in css array
|
||||
*/
|
||||
function extractCss(styles, ...css) {
|
||||
const _styles = normalizeNewline(minifyCss(styles || ''));
|
||||
const _css = normalizeNewline(minifyCss(css.join('\n')));
|
||||
if (_css.trim() !== '') {
|
||||
return postcss(discard({css: _css})).process(_styles).css;
|
||||
}
|
||||
|
||||
return _styles;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
minifyCss,
|
||||
prettifyCss,
|
||||
extractCss,
|
||||
};
|
206
src/dom.js
Normal file
206
src/dom.js
Normal file
@ -0,0 +1,206 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const {JSDOM} = require('jsdom');
|
||||
const resolve = require('resolve');
|
||||
const detectIndent = require('detect-indent');
|
||||
const flatten = require('lodash/flatten');
|
||||
const UglifyJS = require('uglify-js');
|
||||
|
||||
/**
|
||||
* Get loadcss + cssrelpreload script
|
||||
*
|
||||
* @returns {string} Minified loadcss script
|
||||
*/
|
||||
function getScript() {
|
||||
const loadCssMain = resolve.sync('fg-loadcss');
|
||||
const loadCssBase = path.dirname(loadCssMain);
|
||||
|
||||
const loadCSS = fs.readFileSync(path.join(loadCssBase, 'cssrelpreload.js'), 'utf8');
|
||||
return UglifyJS.minify(loadCSS).code.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all subsctings of of the passed tags
|
||||
* Does not work with self closing tags
|
||||
* @param {string} html Html string
|
||||
* @param {string} tag Tagname
|
||||
* @returns {array<string>} Array with aöö substrings
|
||||
*/
|
||||
const getPartials = (html = '', tag = 'svg') => {
|
||||
const indices = [];
|
||||
let start = html.indexOf(`<${tag}`, 0);
|
||||
let end = html.indexOf(`</${tag}>`, start) + `</${tag}>`.length;
|
||||
while (start >= 0) {
|
||||
indices.push({start, end});
|
||||
start = html.indexOf(`<${tag}`, end);
|
||||
end = html.indexOf(`</${tag}>`, end) + `</${tag}>`.length;
|
||||
}
|
||||
|
||||
return indices.map(({start, end}) => html.substring(start, end));
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace all partials defined by tagname in source with the corresponding
|
||||
* partials found in dest
|
||||
* @param {string} source Source HTML String
|
||||
* @param {string} dest Dest HTML String
|
||||
* @param {string} tag Tagname (svg or math)
|
||||
* @returns {array} SVG Strings found in HTML
|
||||
*/
|
||||
const replacePartials = (source, dest, tag) => {
|
||||
if (!Array.isArray(tag)) {
|
||||
tag = [tag];
|
||||
}
|
||||
|
||||
return tag.reduce((result, tag) => {
|
||||
// Only replace head so we don't mess with the orignal markup
|
||||
const newTags = getPartials(dest, tag);
|
||||
const oldTags = getPartials(result, tag);
|
||||
|
||||
return oldTags.reduce((str, code, index) => str.replace(code, newTags[index] || code), result);
|
||||
}, source);
|
||||
};
|
||||
|
||||
class Dom {
|
||||
constructor(html, {minify = true} = {}) {
|
||||
const jsdom = new JSDOM(html);
|
||||
const {window} = jsdom;
|
||||
const {document} = window;
|
||||
document.$jsdom = jsdom;
|
||||
|
||||
this.minify = minify;
|
||||
this.html = html;
|
||||
this.document = document;
|
||||
this.window = window;
|
||||
this.jsdom = jsdom;
|
||||
|
||||
this.indent = detectIndent(html);
|
||||
this.headIndent = detectIndent(this.document.querySelector('head').innerHTML);
|
||||
}
|
||||
|
||||
serialize() {
|
||||
const html = this.jsdom.serialize();
|
||||
|
||||
// Only replace head so we don't mess with the orignal markup
|
||||
// See https://github.com/fb55/htmlparser2/pull/259 (htmlparser2)
|
||||
// See https://runkit.com/582b0e9ebe07a80014bf1e82/58400d2db3ef0f0013bae090 (parse5)
|
||||
// The current parsers have problems with foreign context elements like svg & math
|
||||
return replacePartials(this.html, html, 'head');
|
||||
}
|
||||
|
||||
createStyleNode(css, referenceIndent = this.headIndent.indent) {
|
||||
if (this.minify) {
|
||||
const styles = this.document.createElement('style');
|
||||
styles.append(this.document.createTextNode(css));
|
||||
return styles;
|
||||
}
|
||||
|
||||
const textIndent = String(referenceIndent + this.indent.indent);
|
||||
const text = css
|
||||
.trim()
|
||||
.split(/[\r\n]+/)
|
||||
.join(`\n${textIndent}`);
|
||||
|
||||
const styles = this.document.createElement('style');
|
||||
styles.append(this.document.createTextNode('\n' + textIndent + text + '\n' + referenceIndent));
|
||||
return styles;
|
||||
}
|
||||
|
||||
createElement(tag) {
|
||||
return this.document.createElement(tag);
|
||||
}
|
||||
|
||||
getInlineStyles() {
|
||||
return [...this.document.querySelectorAll('head style')].map(node => node.textContent);
|
||||
}
|
||||
|
||||
getExternalStyles() {
|
||||
return [...this.document.querySelectorAll('link[rel="stylesheet"], link[rel="preload"][as="style"]')].filter(
|
||||
link => link.parentElement.tagName !== 'NOSCRIPT'
|
||||
);
|
||||
}
|
||||
|
||||
querySelector(...selector) {
|
||||
const s = flatten(selector)
|
||||
.filter(s => s)
|
||||
.join(',');
|
||||
|
||||
return this.document.querySelector(s);
|
||||
}
|
||||
|
||||
querySelectorAll(...selector) {
|
||||
const s = flatten(selector)
|
||||
.filter(s => s)
|
||||
.join(',');
|
||||
|
||||
return this.document.querySelectorAll(s);
|
||||
}
|
||||
|
||||
addInlineStyles(css, target) {
|
||||
if (target) {
|
||||
this.insertStylesBefore(css, target);
|
||||
} else {
|
||||
this.appendStyles(css, this.querySelector('head'));
|
||||
}
|
||||
}
|
||||
|
||||
insertStylesBefore(css, referenceNode) {
|
||||
const styles = this.createStyleNode(css);
|
||||
referenceNode.before(styles);
|
||||
styles.after(this.document.createTextNode('\n' + this.headIndent.indent));
|
||||
}
|
||||
|
||||
appendStyles(css, referenceNode) {
|
||||
const styles = this.createStyleNode(css);
|
||||
referenceNode.append(styles);
|
||||
styles.before(this.document.createTextNode(this.headIndent.indent));
|
||||
styles.after(this.document.createTextNode('\n' + this.headIndent.indent));
|
||||
}
|
||||
|
||||
insertBefore(node, referenceNode) {
|
||||
referenceNode.before(node);
|
||||
node.after(this.document.createTextNode('\n' + this.headIndent.indent));
|
||||
}
|
||||
|
||||
insertAfter(node, referenceNode) {
|
||||
referenceNode.after(node);
|
||||
referenceNode.after(this.document.createTextNode('\n' + this.headIndent.indent));
|
||||
}
|
||||
|
||||
remove(node) {
|
||||
while (
|
||||
node.previousSibling &&
|
||||
node.previousSibling.nodeName === '#text' &&
|
||||
node.previousSibling.textContent.trim() === ''
|
||||
) {
|
||||
node.previousSibling.remove();
|
||||
}
|
||||
node.remove();
|
||||
}
|
||||
|
||||
maybeAddLoadcss() {
|
||||
// Only add loadcss if it's not already included
|
||||
const loadCssIncluded = [...this.document.querySelectorAll('script')].some(tag =>
|
||||
(tag.textContent || '').includes('loadCSS')
|
||||
);
|
||||
|
||||
if (loadCssIncluded) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add loadcss + cssrelpreload polyfill
|
||||
const nodes = [
|
||||
...this.document.querySelectorAll('head link[rel="stylesheet"],head link[rel="preload"],head noscript'),
|
||||
].filter(link => link.parentElement.tagName !== 'NOSCRIPT');
|
||||
const scriptAnchor = nodes.pop();
|
||||
const script = this.document.createElement('script');
|
||||
script.append(this.document.createTextNode(getScript()));
|
||||
|
||||
if (scriptAnchor) {
|
||||
scriptAnchor.after(script);
|
||||
scriptAnchor.after(this.document.createTextNode('\n' + this.headIndent.indent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Dom;
|
@ -277,10 +277,10 @@
|
||||
float: right !important;
|
||||
}
|
||||
</style>
|
||||
<link rel="preload" href="/css/cartoon.2808011f.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="/css/cartoon.2808011f.css"></noscript>
|
||||
<link rel="preload" href="/bower_components/bootstrap/dist/css/bootstrap.10a09ad4.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.10a09ad4.css"></noscript>
|
||||
<link rel="preload" href="/css/cartoon.08b3295a.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="/css/cartoon.08b3295a.css"></noscript>
|
||||
<link rel="preload" href="/bower_components/bootstrap/dist/css/bootstrap.c8dce395.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.c8dce395.css"></noscript>
|
||||
<script>!function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.addEventListener?t.removeEventListener("load",a):t.attachEvent&&t.detachEvent("onload",a),t.setAttribute("onload",null),t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script>
|
||||
<!-- endbuild -->
|
||||
|
||||
|
@ -1,64 +1,63 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>critical css test</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>critical css test</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||
|
||||
<!-- build:css styles/main.css -->
|
||||
<style>
|
||||
body{padding-top:20px;padding-bottom:20px}.header{padding-left:15px;padding-right:15px}.header{border-bottom:1px solid #e5e5e5}.header h3{margin-top:0;margin-bottom:0;line-height:40px;padding-bottom:19px}.jumbotron{text-align:center;border-bottom:1px solid #e5e5e5}.jumbotron .btn{font-size:21px;padding:14px 24px}@media screen and (min-width:768px){.container{max-width:730px}.header{padding-left:0;padding-right:0}.header{margin-bottom:30px}.jumbotron{border-bottom:0}}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:0 0}h1{margin:.67em 0;font-size:2em}@media print{*{color:#000!important;text-shadow:none!important;background:0 0!important;box-shadow:none!important}a{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}a[href^="#"]:after{content:""}h3,p{orphans:3;widows:3}h3{page-break-after:avoid}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}a{color:#428bca;text-decoration:none}h1,h3{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1,h3{margin-top:20px;margin-bottom:10px}h1{font-size:36px}h3{font-size:24px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.text-muted{color:#999}ul{margin-top:0;margin-bottom:10px}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a{color:#fff;background-color:#428bca}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.container:after,.container:before,.nav:after,.nav:before{display:table;content:" "}.container:after,.nav:after{clear:both}.pull-right{float:right!important}
|
||||
</style>
|
||||
<link rel="preload" href="css/cartoon.08b3295a.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="css/cartoon.08b3295a.css"></noscript>
|
||||
<link rel="preload" href="bower_components/bootstrap/dist/css/bootstrap.c8dce395.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.c8dce395.css"></noscript>
|
||||
<script>!function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.addEventListener?t.removeEventListener("load",a):t.attachEvent&&t.detachEvent("onload",a),t.setAttribute("onload",null),t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:css styles/main.css -->
|
||||
<style>body{padding-top:20px;padding-bottom:20px}.header{padding-left:15px;padding-right:15px}.header{border-bottom:1px solid #e5e5e5}.header h3{margin-top:0;margin-bottom:0;line-height:40px;padding-bottom:19px}.jumbotron{text-align:center;border-bottom:1px solid #e5e5e5}.jumbotron .btn{font-size:21px;padding:14px 24px}@media screen and (min-width:768px){.container{max-width:730px}.header{padding-left:0;padding-right:0}.header{margin-bottom:30px}.jumbotron{border-bottom:0}}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:0 0}h1{margin:.67em 0;font-size:2em}@media print{*{color:#000!important;text-shadow:none!important;background:0 0!important;box-shadow:none!important}a{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}a[href^="#"]:after{content:""}h3,p{orphans:3;widows:3}h3{page-break-after:avoid}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}a{color:#428bca;text-decoration:none}h1,h3{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1,h3{margin-top:20px;margin-bottom:10px}h1{font-size:36px}h3{font-size:24px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.text-muted{color:#999}ul{margin-top:0;margin-bottom:10px}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a{color:#fff;background-color:#428bca}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.container:after,.container:before,.nav:after,.nav:before{display:table;content:" "}.container:after,.nav:after{clear:both}.pull-right{float:right!important}</style>
|
||||
<link rel="preload" href="css/cartoon.08b3295a.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="css/cartoon.08b3295a.css"></noscript>
|
||||
<link rel="preload" href="bower_components/bootstrap/dist/css/bootstrap.c8dce395.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.c8dce395.css"></noscript>
|
||||
<script>!function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.addEventListener?t.removeEventListener("load",a):t.attachEvent&&t.detachEvent("onload",a),t.setAttribute("onload",null),t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script>
|
||||
<!-- endbuild -->
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 10]>
|
||||
<p class="browsehappy">
|
||||
You are using an <strong>outdated</strong> browser. Please
|
||||
<a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
|
||||
</p>
|
||||
<![endif]-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 10]>
|
||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade
|
||||
your browser</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<ul class="nav nav-pills pull-right">
|
||||
<li class="active"><a href="#">Home</a></li>
|
||||
<li><a href="#">About</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
<h3 class="text-muted">critical css test</h3>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<ul class="nav nav-pills pull-right">
|
||||
<li class="active"><a href="#">Home</a></li>
|
||||
<li><a href="#">About</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
<h3 class="text-muted">critical css test</h3>
|
||||
</div>
|
||||
<div class="jumbotron">
|
||||
<h1>'Allo, 'Allo!</h1>
|
||||
|
||||
<div class="jumbotron">
|
||||
<h1>'Allo, 'Allo!</h1>
|
||||
<p class="lead">Always a pleasure scaffolding your apps.</p>
|
||||
|
||||
<p class="lead">Always a pleasure scaffolding your apps.</p>
|
||||
<p><a class="btn btn-lg btn-success" href="#">Splendid!</a></p>
|
||||
</div>
|
||||
|
||||
<p><a class="btn btn-lg btn-success" href="#">Splendid!</a></p>
|
||||
</div>
|
||||
<div class="row marketing">
|
||||
<div class="col-lg-6">
|
||||
<h4>HTML5 Boilerplate</h4>
|
||||
|
||||
<div class="row marketing">
|
||||
<div class="col-lg-6">
|
||||
<h4>HTML5 Boilerplate</h4>
|
||||
<p>
|
||||
HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
||||
sites.
|
||||
</p>
|
||||
|
||||
<p>HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
||||
sites.</p>
|
||||
<h4>Bootstrap</h4>
|
||||
|
||||
<h4>Bootstrap</h4>
|
||||
<p>Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.</p>
|
||||
<div class="footer"><p>♥ from the Yeoman team</p></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>♥ from the Yeoman team</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,330 +1,331 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>critical css test</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>critical css test</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||
|
||||
<!-- build:css styles/main.css -->
|
||||
<style>
|
||||
body {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.header {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.header {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
.header h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
line-height: 40px;
|
||||
padding-bottom: 19px;
|
||||
}
|
||||
.jumbotron {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
.jumbotron .btn {
|
||||
font-size: 21px;
|
||||
padding: 14px 24px;
|
||||
}
|
||||
@media screen and (min-width: 768px) {
|
||||
.container {
|
||||
max-width: 730px;
|
||||
<!-- build:css styles/main.css -->
|
||||
<style>
|
||||
body {
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.header {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.header {
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
.header h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
line-height: 40px;
|
||||
padding-bottom: 19px;
|
||||
}
|
||||
.jumbotron {
|
||||
border-bottom: 0;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
}
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
a {
|
||||
background: 0 0;
|
||||
}
|
||||
h1 {
|
||||
margin: 0.67em 0;
|
||||
font-size: 2em;
|
||||
}
|
||||
@media print {
|
||||
* {
|
||||
color: #000 !important;
|
||||
text-shadow: none !important;
|
||||
background: 0 0 !important;
|
||||
box-shadow: none !important;
|
||||
.jumbotron .btn {
|
||||
font-size: 21px;
|
||||
padding: 14px 24px;
|
||||
}
|
||||
@media screen and (min-width: 768px) {
|
||||
.container {
|
||||
max-width: 730px;
|
||||
}
|
||||
.header {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.header {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.jumbotron {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
a {
|
||||
text-decoration: underline;
|
||||
background: 0 0;
|
||||
}
|
||||
a[href]:after {
|
||||
content: " (" attr(href) ")";
|
||||
h1 {
|
||||
margin: 0.67em 0;
|
||||
font-size: 2em;
|
||||
}
|
||||
a[href^="#"]:after {
|
||||
content: "";
|
||||
@media print {
|
||||
* {
|
||||
color: #000 !important;
|
||||
text-shadow: none !important;
|
||||
background: 0 0 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
a[href]:after {
|
||||
content: " (" attr(href) ")";
|
||||
}
|
||||
a[href^="#"]:after {
|
||||
content: "";
|
||||
}
|
||||
h3,
|
||||
p {
|
||||
orphans: 3;
|
||||
widows: 3;
|
||||
}
|
||||
h3 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
}
|
||||
h3,
|
||||
p {
|
||||
orphans: 3;
|
||||
widows: 3;
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:after,
|
||||
:before {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html {
|
||||
font-size: 62.5%;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
}
|
||||
a {
|
||||
color: #428bca;
|
||||
text-decoration: none;
|
||||
}
|
||||
h1,
|
||||
h3 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
h1,
|
||||
h3 {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
h3 {
|
||||
page-break-after: avoid;
|
||||
font-size: 24px;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
}
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:after,
|
||||
:before {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html {
|
||||
font-size: 62.5%;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.42857143;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
}
|
||||
a {
|
||||
color: #428bca;
|
||||
text-decoration: none;
|
||||
}
|
||||
h1,
|
||||
h3 {
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
color: inherit;
|
||||
}
|
||||
h1,
|
||||
h3 {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
.lead {
|
||||
margin-bottom: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
line-height: 1.4;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.lead {
|
||||
font-size: 21px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
line-height: 1.4;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.lead {
|
||||
font-size: 21px;
|
||||
}
|
||||
}
|
||||
.text-muted {
|
||||
color: #999;
|
||||
}
|
||||
ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.text-muted {
|
||||
color: #999;
|
||||
}
|
||||
ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.container {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
width: 750px;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
width: 970px;
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
width: 750px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
width: 1170px;
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
width: 970px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
width: 1170px;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
background-image: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.btn-success {
|
||||
color: #fff;
|
||||
background-color: #5cb85c;
|
||||
border-color: #4cae4c;
|
||||
}
|
||||
.btn-lg {
|
||||
padding: 10px 16px;
|
||||
font-size: 18px;
|
||||
line-height: 1.33;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.nav {
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.nav > li {
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
.nav > li > a {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.nav-pills > li {
|
||||
float: left;
|
||||
}
|
||||
.nav-pills > li > a {
|
||||
border-radius: 4px;
|
||||
}
|
||||
.nav-pills > li + li {
|
||||
margin-left: 2px;
|
||||
}
|
||||
.nav-pills > li.active > a {
|
||||
color: #fff;
|
||||
background-color: #428bca;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
background-image: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.btn-success {
|
||||
color: #fff;
|
||||
background-color: #5cb85c;
|
||||
border-color: #4cae4c;
|
||||
}
|
||||
.btn-lg {
|
||||
padding: 10px 16px;
|
||||
font-size: 18px;
|
||||
line-height: 1.33;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.nav {
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.nav > li {
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
.nav > li > a {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.nav-pills > li {
|
||||
float: left;
|
||||
}
|
||||
.nav-pills > li > a {
|
||||
border-radius: 4px;
|
||||
}
|
||||
.nav-pills > li + li {
|
||||
margin-left: 2px;
|
||||
}
|
||||
.nav-pills > li.active > a {
|
||||
color: #fff;
|
||||
background-color: #428bca;
|
||||
}
|
||||
.jumbotron {
|
||||
padding: 30px;
|
||||
margin-bottom: 30px;
|
||||
color: inherit;
|
||||
background-color: #eee;
|
||||
}
|
||||
.jumbotron h1 {
|
||||
color: inherit;
|
||||
}
|
||||
.jumbotron p {
|
||||
margin-bottom: 15px;
|
||||
font-size: 21px;
|
||||
font-weight: 200;
|
||||
}
|
||||
.container .jumbotron {
|
||||
border-radius: 6px;
|
||||
}
|
||||
@media screen and (min-width: 768px) {
|
||||
.jumbotron {
|
||||
padding-top: 48px;
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
.container .jumbotron {
|
||||
padding-right: 60px;
|
||||
padding-left: 60px;
|
||||
padding: 30px;
|
||||
margin-bottom: 30px;
|
||||
color: inherit;
|
||||
background-color: #eee;
|
||||
}
|
||||
.jumbotron h1 {
|
||||
font-size: 63px;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
.container:after,
|
||||
.container:before,
|
||||
.nav:after,
|
||||
.nav:before {
|
||||
display: table;
|
||||
content: " ";
|
||||
}
|
||||
.container:after,
|
||||
.nav:after {
|
||||
clear: both;
|
||||
}
|
||||
.pull-right {
|
||||
float: right !important;
|
||||
}
|
||||
</style>
|
||||
<link rel="preload" href="css/cartoon.2808011f.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="css/cartoon.2808011f.css"></noscript>
|
||||
<link rel="preload" href="bower_components/bootstrap/dist/css/bootstrap.10a09ad4.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.10a09ad4.css"></noscript>
|
||||
<script>!function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.addEventListener?t.removeEventListener("load",a):t.attachEvent&&t.detachEvent("onload",a),t.setAttribute("onload",null),t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script>
|
||||
<!-- endbuild -->
|
||||
.jumbotron p {
|
||||
margin-bottom: 15px;
|
||||
font-size: 21px;
|
||||
font-weight: 200;
|
||||
}
|
||||
.container .jumbotron {
|
||||
border-radius: 6px;
|
||||
}
|
||||
@media screen and (min-width: 768px) {
|
||||
.jumbotron {
|
||||
padding-top: 48px;
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
.container .jumbotron {
|
||||
padding-right: 60px;
|
||||
padding-left: 60px;
|
||||
}
|
||||
.jumbotron h1 {
|
||||
font-size: 63px;
|
||||
}
|
||||
}
|
||||
.container:after,
|
||||
.container:before,
|
||||
.nav:after,
|
||||
.nav:before {
|
||||
display: table;
|
||||
content: " ";
|
||||
}
|
||||
.container:after,
|
||||
.nav:after {
|
||||
clear: both;
|
||||
}
|
||||
.pull-right {
|
||||
float: right !important;
|
||||
}
|
||||
</style>
|
||||
<link rel="preload" href="css/cartoon.08b3295a.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="css/cartoon.08b3295a.css"></noscript>
|
||||
<link rel="preload" href="bower_components/bootstrap/dist/css/bootstrap.c8dce395.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.c8dce395.css"></noscript>
|
||||
<script>!function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.addEventListener?t.removeEventListener("load",a):t.attachEvent&&t.detachEvent("onload",a),t.setAttribute("onload",null),t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script>
|
||||
<!-- endbuild -->
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 10]>
|
||||
<p class="browsehappy">
|
||||
You are using an <strong>outdated</strong> browser. Please
|
||||
<a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
|
||||
</p>
|
||||
<![endif]-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 10]>
|
||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade
|
||||
your browser</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<ul class="nav nav-pills pull-right">
|
||||
<li class="active"><a href="#">Home</a></li>
|
||||
<li><a href="#">About</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
<h3 class="text-muted">critical css test</h3>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<ul class="nav nav-pills pull-right">
|
||||
<li class="active"><a href="#">Home</a></li>
|
||||
<li><a href="#">About</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
<h3 class="text-muted">critical css test</h3>
|
||||
</div>
|
||||
<div class="jumbotron">
|
||||
<h1>'Allo, 'Allo!</h1>
|
||||
|
||||
<div class="jumbotron">
|
||||
<h1>'Allo, 'Allo!</h1>
|
||||
<p class="lead">Always a pleasure scaffolding your apps.</p>
|
||||
|
||||
<p class="lead">Always a pleasure scaffolding your apps.</p>
|
||||
<p><a class="btn btn-lg btn-success" href="#">Splendid!</a></p>
|
||||
</div>
|
||||
|
||||
<p><a class="btn btn-lg btn-success" href="#">Splendid!</a></p>
|
||||
</div>
|
||||
<div class="row marketing">
|
||||
<div class="col-lg-6">
|
||||
<h4>HTML5 Boilerplate</h4>
|
||||
|
||||
<div class="row marketing">
|
||||
<div class="col-lg-6">
|
||||
<h4>HTML5 Boilerplate</h4>
|
||||
<p>
|
||||
HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
||||
sites.
|
||||
</p>
|
||||
|
||||
<p>HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
||||
sites.</p>
|
||||
<h4>Bootstrap</h4>
|
||||
|
||||
<h4>Bootstrap</h4>
|
||||
<p>Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.</p>
|
||||
<div class="footer"><p>♥ from the Yeoman team</p></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>♥ from the Yeoman team</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -279,8 +279,8 @@
|
||||
</style>
|
||||
<link rel="preload" href="css/main.d41d8cd9.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="css/main.d41d8cd9.css"></noscript>
|
||||
<link rel="preload" href="bower_components/bootstrap/dist/css/bootstrap.10a09ad4.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.10a09ad4.css"></noscript>
|
||||
<link rel="preload" href="bower_components/bootstrap/dist/css/bootstrap.c8dce395.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.c8dce395.css"></noscript>
|
||||
<link href="http://fonts.googleapis.com/css?family=Open+Sans" rel="preload" type="text/css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link href="http://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css"></noscript>
|
||||
<script>!function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.addEventListener?t.removeEventListener("load",a):t.attachEvent&&t.detachEvent("onload",a),t.setAttribute("onload",null),t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script>
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
<!-- endbuild -->
|
||||
<noscript>
|
||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
|
||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
|
||||
</noscript>
|
||||
<script>!function(n){"use strict";n.loadCSS||(n.loadCSS=function(){});var o=loadCSS.relpreload={};if(o.support=function(){var e;try{e=n.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),o.bindMediaToggle=function(t){var e=t.media||"all";function a(){t.addEventListener?t.removeEventListener("load",a):t.attachEvent&&t.detachEvent("onload",a),t.setAttribute("onload",null),t.media=e}t.addEventListener?t.addEventListener("load",a):t.attachEvent&&t.attachEvent("onload",a),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(a,3e3)},o.poly=function(){if(!o.support())for(var t=n.document.getElementsByTagName("link"),e=0;e<t.length;e++){var a=t[e];"preload"!==a.rel||"style"!==a.getAttribute("as")||a.getAttribute("data-loadcss")||(a.setAttribute("data-loadcss",!0),o.bindMediaToggle(a))}},!o.support()){o.poly();var t=n.setInterval(o.poly,500);n.addEventListener?n.addEventListener("load",function(){o.poly(),n.clearInterval(t)}):n.attachEvent&&n.attachEvent("onload",function(){o.poly(),n.clearInterval(t)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:n.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script>
|
||||
</head>
|
||||
|
91
test/fixtures/cartoon.html
vendored
91
test/fixtures/cartoon.html
vendored
@ -1,58 +1,59 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>critical css test</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>critical css test</title>
|
||||
<meta name="description" content="" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||
|
||||
<!-- build:css styles/main.css -->
|
||||
<link rel="stylesheet" href="css/cartoon.css">
|
||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css"/>
|
||||
<!-- endbuild -->
|
||||
<!-- build:css styles/main.css -->
|
||||
<link rel="stylesheet" href="css/cartoon.css" />
|
||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
|
||||
<!-- endbuild -->
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 10]>
|
||||
<p class="browsehappy">
|
||||
You are using an <strong>outdated</strong> browser. Please
|
||||
<a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
|
||||
</p>
|
||||
<![endif]-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 10]>
|
||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade
|
||||
your browser</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<ul class="nav nav-pills pull-right">
|
||||
<li class="active"><a href="#">Home</a></li>
|
||||
<li><a href="#">About</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
<h3 class="text-muted">critical css test</h3>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<ul class="nav nav-pills pull-right">
|
||||
<li class="active"><a href="#">Home</a></li>
|
||||
<li><a href="#">About</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
<h3 class="text-muted">critical css test</h3>
|
||||
</div>
|
||||
<div class="jumbotron">
|
||||
<h1>'Allo, 'Allo!</h1>
|
||||
|
||||
<div class="jumbotron">
|
||||
<h1>'Allo, 'Allo!</h1>
|
||||
<p class="lead">Always a pleasure scaffolding your apps.</p>
|
||||
|
||||
<p class="lead">Always a pleasure scaffolding your apps.</p>
|
||||
<p><a class="btn btn-lg btn-success" href="#">Splendid!</a></p>
|
||||
</div>
|
||||
|
||||
<p><a class="btn btn-lg btn-success" href="#">Splendid!</a></p>
|
||||
</div>
|
||||
<div class="row marketing">
|
||||
<div class="col-lg-6">
|
||||
<h4>HTML5 Boilerplate</h4>
|
||||
|
||||
<div class="row marketing">
|
||||
<div class="col-lg-6">
|
||||
<h4>HTML5 Boilerplate</h4>
|
||||
<p>
|
||||
HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
||||
sites.
|
||||
</p>
|
||||
|
||||
<p>HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
||||
sites.</p>
|
||||
<h4>Bootstrap</h4>
|
||||
|
||||
<h4>Bootstrap</h4>
|
||||
<p>Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.</p>
|
||||
<div class="footer"><p>♥ from the Yeoman team</p></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>♥ from the Yeoman team</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
65
test/fixtures/entities2.html
vendored
65
test/fixtures/entities2.html
vendored
@ -1,24 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title>asd</title>
|
||||
</head>
|
||||
<body>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewbox="0 0 563 87.9" enable-background="new 0 0 563 87.9" xml:space="preserve" width="167px" height="26px" fill="#fff">
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title>asd</title>
|
||||
</head>
|
||||
<body>
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewbox="0 0 563 87.9"
|
||||
enable-background="new 0 0 563 87.9"
|
||||
xml:space="preserve"
|
||||
width="167px"
|
||||
height="26px"
|
||||
fill="#fff"
|
||||
>
|
||||
<polygon />
|
||||
<polygon />
|
||||
<polygon fill="#DD7B27" points="55.92,7 91.96,61.76 20.24,61.76 "/>
|
||||
<polygon fill="#DD7B27" points="55.92,7 91.96,61.76 20.24,61.76 " />
|
||||
<polygon />
|
||||
<g id="layer1" transform="translate(-192.905,-516.02064)">
|
||||
<path
|
||||
style="fill:#000000"
|
||||
d="M 197.67968,534.31563 C 197.40468,534.31208 196.21788,532.53719 195.04234,530.37143 L 192.905,526.43368 L 193.45901,525.87968 C 193.76371,525.57497 194.58269,525.32567 195.27896,525.32567 L 196.5449,525.32567 L 197.18129,527.33076 L 197.81768,529.33584 L 202.88215,523.79451 C 205.66761,520.74678 208.88522,517.75085 210.03239,517.13691 L 212.11815,516.02064 L 207.90871,520.80282 C 205.59351,523.43302 202.45735,527.55085 200.93947,529.95355 C 199.42159,532.35625 197.95468,534.31919 197.67968,534.31563 z "
|
||||
id="path2223" />
|
||||
</g>
|
||||
</svg>
|
||||
<svg>
|
||||
<symbol viewbox="0 0 24 24" id="shape-clock"> <title>clock</title> <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" /> <path d="M0 0h24v24H0z" fill="none" /> <path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z" /> </symbol>
|
||||
</svg>
|
||||
</body>
|
||||
<path
|
||||
style="fill:#000000"
|
||||
d="M 197.67968,534.31563 C 197.40468,534.31208 196.21788,532.53719 195.04234,530.37143 L 192.905,526.43368 L 193.45901,525.87968 C 193.76371,525.57497 194.58269,525.32567 195.27896,525.32567 L 196.5449,525.32567 L 197.18129,527.33076 L 197.81768,529.33584 L 202.88215,523.79451 C 205.66761,520.74678 208.88522,517.75085 210.03239,517.13691 L 212.11815,516.02064 L 207.90871,520.80282 C 205.59351,523.43302 202.45735,527.55085 200.93947,529.95355 C 199.42159,532.35625 197.95468,534.31919 197.67968,534.31563 z "
|
||||
id="path2223"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<symbol viewbox="0 0 24 24" id="shape-clock">
|
||||
<title>clock</title>
|
||||
<path
|
||||
d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"
|
||||
/>
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z" />
|
||||
</symbol>
|
||||
</svg>
|
||||
<math>
|
||||
(<array align="c"> <item>
|
||||
&ldet;<array align="cc">
|
||||
<item>x<sub>11</sub>
|
||||
<item>x<sub>12</sub>
|
||||
<item>x<sub>21</sub>
|
||||
<item>x<sub>22</sub>
|
||||
</array><rd>&rdet;
|
||||
<item> y <item> z
|
||||
</array>)
|
||||
</math>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,30 +1,11 @@
|
||||
/* eslint-env jest */
|
||||
const path = require('path');
|
||||
const reaver = require('reaver');
|
||||
const postcss = require('postcss');
|
||||
const discard = require('postcss-discard');
|
||||
const normalizeNewline = require('normalize-newline');
|
||||
const CleanCSS = require('clean-css');
|
||||
const prettier = require('prettier');
|
||||
const {extractCss} = require('../src/css.js');
|
||||
const inline = require('..');
|
||||
|
||||
const {read, checkAndDelete, strip} = require('./helper');
|
||||
|
||||
function minifyCSS(styles) {
|
||||
return new CleanCSS().minify(styles).styles; // eslint-disable-line prefer-destructuring
|
||||
}
|
||||
|
||||
const extract = (css, critical, minify = false) => {
|
||||
css = minifyCSS(css);
|
||||
critical = minifyCSS(critical);
|
||||
const result = normalizeNewline(postcss(discard({css: critical})).process(css).css);
|
||||
if (minify) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return prettier.format(result, {parser: 'css'});
|
||||
};
|
||||
|
||||
jest.setTimeout(20000);
|
||||
|
||||
test('Inline css', async () => {
|
||||
@ -65,7 +46,7 @@ test('Inline and minify css', async () => {
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('should inline and extract css', async () => {
|
||||
test('Inline and extract css', async () => {
|
||||
const html = await read('fixtures/cartoon.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
const expected = await read('expected/cartoon-expected.html');
|
||||
@ -76,8 +57,8 @@ test('should inline and extract css', async () => {
|
||||
]);
|
||||
|
||||
const reved = [
|
||||
reaver.rev('fixtures/css/cartoon.css', extract(styles[0], css)),
|
||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extract(styles[1], css)),
|
||||
reaver.rev('fixtures/css/cartoon.css', extractCss(styles[0], css)),
|
||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extractCss(styles[1], css)),
|
||||
];
|
||||
|
||||
const out = inline(html, css, {
|
||||
@ -93,7 +74,7 @@ test('should inline and extract css', async () => {
|
||||
expect(strip(out.toString('utf8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('should extract and minify css', async () => {
|
||||
test('Extract and minify css', async () => {
|
||||
const html = await read('fixtures/cartoon.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
const expected = await read('expected/cartoon-expected-minified.html');
|
||||
@ -104,8 +85,8 @@ test('should extract and minify css', async () => {
|
||||
]);
|
||||
|
||||
const reved = [
|
||||
reaver.rev('fixtures/css/cartoon.css', extract(styles[0], css, true)),
|
||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extract(styles[1], css, true)),
|
||||
reaver.rev('fixtures/css/cartoon.css', extractCss(styles[0], css)),
|
||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extractCss(styles[1], css)),
|
||||
];
|
||||
|
||||
const out = inline(html, css, {
|
||||
@ -120,7 +101,7 @@ test('should extract and minify css', async () => {
|
||||
expect(strip(out.toString('utf8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('should inline and extract css correctly with absolute paths', async () => {
|
||||
test('Inline and extract css correctly with absolute paths', async () => {
|
||||
const html = await read('fixtures/cartoon-absolute.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
const expected = await read('expected/cartoon-absolute-expected.html');
|
||||
@ -131,8 +112,8 @@ test('should inline and extract css correctly with absolute paths', async () =>
|
||||
]);
|
||||
|
||||
const reved = [
|
||||
reaver.rev('fixtures/css/cartoon.css', extract(styles[0], css)),
|
||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extract(styles[1], css)),
|
||||
reaver.rev('fixtures/css/cartoon.css', extractCss(styles[0], css)),
|
||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extractCss(styles[1], css)),
|
||||
];
|
||||
|
||||
const out = inline(html, css, {
|
||||
@ -148,14 +129,14 @@ test('should inline and extract css correctly with absolute paths', async () =>
|
||||
expect(strip(out.toString('utf8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('should not strip of svg closing tags', async () => {
|
||||
test('Does not strip of svg closing tags', async () => {
|
||||
const html = await read('fixtures/entities.html');
|
||||
const out = inline(html, '', {minify: false});
|
||||
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(html));
|
||||
});
|
||||
|
||||
test('should not strip of svg closing tags test 2', async () => {
|
||||
test('Does not strip svg closing tags test 2', async () => {
|
||||
const html = await read('fixtures/svg.html');
|
||||
const expected = await read('expected/test-svg.html');
|
||||
const css = 'html{font-size:16;}';
|
||||
@ -164,7 +145,7 @@ test('should not strip of svg closing tags test 2', async () => {
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('should not keep external urls', async () => {
|
||||
test('Also preload external urls', async () => {
|
||||
function strip2(string) {
|
||||
return string.replace(/\s+/gm, '');
|
||||
}
|
||||
@ -176,7 +157,7 @@ test('should not keep external urls', async () => {
|
||||
expect(strip2(out.toString('utf-8'))).toBe(strip2(expected));
|
||||
});
|
||||
|
||||
test('should not extract on external urls', async () => {
|
||||
test("Don't try to extract for external urls", async () => {
|
||||
const html = await read('fixtures/external.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
const expected = await read('expected/external-extract-expected.html');
|
||||
@ -187,8 +168,8 @@ test('should not extract on external urls', async () => {
|
||||
]);
|
||||
|
||||
const reved = [
|
||||
reaver.rev('fixtures/css/main.css', extract(styles[0], css)),
|
||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extract(styles[1], css)),
|
||||
reaver.rev('fixtures/css/main.css', extractCss(styles[0], css)),
|
||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extractCss(styles[1], css)),
|
||||
];
|
||||
|
||||
const out = inline(html, css, {
|
||||
@ -203,13 +184,13 @@ test('should not extract on external urls', async () => {
|
||||
expect(strip(out.toString('utf8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('should keep self closing svg elements', async () => {
|
||||
test('Keep self closing svg elements', async () => {
|
||||
const html = await read('fixtures/entities2.html');
|
||||
const out = inline(html, '', {minify: false});
|
||||
const out = inline(html, '');
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(html));
|
||||
});
|
||||
|
||||
test('should respect ignore option with string array', async () => {
|
||||
test('Respect ignore option with string array', async () => {
|
||||
function strip2(string) {
|
||||
return string.replace(/\s+/gm, '');
|
||||
}
|
||||
@ -225,7 +206,7 @@ test('should respect ignore option with string array', async () => {
|
||||
expect(strip2(out.toString('utf-8'))).toBe(strip2(expected));
|
||||
});
|
||||
|
||||
test('should respect single ignore option with string', async () => {
|
||||
test('Respect single ignore option with string', async () => {
|
||||
function strip2(string) {
|
||||
return string.replace(/\s+/gm, '');
|
||||
}
|
||||
@ -241,7 +222,7 @@ test('should respect single ignore option with string', async () => {
|
||||
expect(strip2(out.toString('utf-8'))).toBe(strip2(expected));
|
||||
});
|
||||
|
||||
test('should respect ignore option with RegExp array', async () => {
|
||||
test('Respect ignore option with RegExp array', async () => {
|
||||
function strip2(string) {
|
||||
return string.replace(/\s+/gm, '');
|
||||
}
|
||||
@ -257,7 +238,7 @@ test('should respect ignore option with RegExp array', async () => {
|
||||
expect(strip2(out.toString('utf-8'))).toBe(strip2(expected));
|
||||
});
|
||||
|
||||
test('should respect selector option', async () => {
|
||||
test('Respect selector option', async () => {
|
||||
const html = await read('fixtures/index.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
|
||||
@ -270,7 +251,7 @@ test('should respect selector option', async () => {
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('should ignore stylesheets wrapped in noscript', async () => {
|
||||
test('Ignore stylesheets wrapped in noscript', async () => {
|
||||
const html = await read('fixtures/index-noscript.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
|
||||
@ -280,7 +261,7 @@ test('should ignore stylesheets wrapped in noscript', async () => {
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test("should skip loadcss if it's already present and used for all existing link tags", async () => {
|
||||
test("Skip loadcss if it's already present and used for all existing link tags", async () => {
|
||||
const html = await read('fixtures/loadcss.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
|
||||
@ -290,7 +271,7 @@ test("should skip loadcss if it's already present and used for all existing link
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('consider existing style tags', async () => {
|
||||
test('Consider existing style tags', async () => {
|
||||
const html = await read('fixtures/index-inlined.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
|
||||
@ -300,7 +281,7 @@ test('consider existing style tags', async () => {
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test("don't add loadcss twice", async () => {
|
||||
test("Don't add loadcss twice", async () => {
|
||||
const html = await read('fixtures/loadcss-again.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
|
||||
@ -309,3 +290,16 @@ test("don't add loadcss twice", async () => {
|
||||
|
||||
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
|
||||
});
|
||||
|
||||
test('Replace stylesheets', async () => {
|
||||
const html = await read('fixtures/cartoon.html');
|
||||
const css = await read('fixtures/critical.css');
|
||||
|
||||
const out = inline(html, css, {
|
||||
replaceStylesheets: ['replace/all.css'],
|
||||
});
|
||||
|
||||
expect(out.toString('utf8')).not.toMatch('css/cartoon.css');
|
||||
expect(out.toString('utf8')).not.toMatch('css/bootstrap.css');
|
||||
expect(out.toString('utf8')).toMatch('href="replace/all.css"');
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user