mirror of
https://github.com/danog/inline-critical.git
synced 2024-12-02 09:27:56 +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 os = require('os');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const meow = require('meow');
|
const meow = require('meow');
|
||||||
|
const chalk = require('chalk');
|
||||||
const indentString = require('indent-string');
|
const indentString = require('indent-string');
|
||||||
const stdin = require('get-stdin');
|
const stdin = require('get-stdin');
|
||||||
const css = require('css');
|
const css = require('css');
|
||||||
@ -42,6 +43,7 @@ const cli = meow(help, {
|
|||||||
minify: {
|
minify: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
alias: 'm',
|
alias: 'm',
|
||||||
|
default: true,
|
||||||
},
|
},
|
||||||
extract: {
|
extract: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
@ -101,10 +103,10 @@ cli.flags = _.reduce(
|
|||||||
);
|
);
|
||||||
|
|
||||||
function processError(err) {
|
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(os.EOL);
|
||||||
process.stderr.write(indentString(help, 4));
|
process.stderr.write(indentString(help, 2));
|
||||||
// Process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function read(file) {
|
function read(file) {
|
||||||
|
267
index.js
267
index.js
@ -13,42 +13,20 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const isString = require('lodash/isString');
|
const isString = require('lodash/isString');
|
||||||
const isRegExp = require('lodash/isRegExp');
|
const isRegExp = require('lodash/isRegExp');
|
||||||
const filter = require('lodash/filter');
|
|
||||||
const _ = require('lodash');
|
|
||||||
const UglifyJS = require('uglify-js');
|
|
||||||
const reaver = require('reaver');
|
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 slash = require('slash');
|
||||||
const normalizeNewline = require('normalize-newline');
|
|
||||||
const resolve = require('resolve');
|
const Dom = require('./src/dom');
|
||||||
const detectIndent = require('detect-indent');
|
const {prettifyCss, extractCss} = require('./src/css');
|
||||||
const prettier = require('prettier');
|
|
||||||
|
|
||||||
const DEFAULT_OPTIONS = {
|
const DEFAULT_OPTIONS = {
|
||||||
minify: true,
|
minify: true,
|
||||||
extract: false,
|
extract: false,
|
||||||
polyfill: true,
|
polyfill: true,
|
||||||
ignore: [],
|
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
|
* Fixup slashes in file paths for windows
|
||||||
*
|
*
|
||||||
@ -59,74 +37,6 @@ function normalizePath(str) {
|
|||||||
return process.platform === 'win32' ? slash(str) : 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 ;)
|
* Main function ;)
|
||||||
* @param {string} html HTML String
|
* @param {string} html HTML String
|
||||||
@ -141,122 +51,115 @@ function inline(html, styles, options) {
|
|||||||
html = String(html);
|
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)) {
|
if (!Array.isArray(o.ignore)) {
|
||||||
o.ignore = [o.ignore].filter(i => i);
|
o.ignore = [o.ignore].filter(i => i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o.ignore.length > 0) {
|
const document = new Dom(html, o);
|
||||||
links = filter(links, link => {
|
|
||||||
const href = $(link).attr('href');
|
const inlineStyles = document.getInlineStyles();
|
||||||
return !o.ignore.some(i => (isRegExp(i) && i.test(href)) || i === href);
|
const extarnalStyles = document.getExternalStyles();
|
||||||
|
const missingStyles = extractCss(styles, ...inlineStyles);
|
||||||
|
|
||||||
|
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);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (missing) {
|
const targetSelectors = [
|
||||||
const elements = [
|
o.selector,
|
||||||
'<style>',
|
':not(noscript) > link[rel="stylesheet"]',
|
||||||
indent +
|
':not(noscript) > link[rel="preload"][as="style"]',
|
||||||
missing
|
'head script',
|
||||||
.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');
|
|
||||||
|
|
||||||
if ($target.length > 0) {
|
const target = document.querySelector(targetSelectors);
|
||||||
// Insert inline styles right before first <link rel="stylesheet" /> or other target
|
const inlined = `${inlineStyles}\n${missingStyles}`;
|
||||||
$target.before(elements);
|
|
||||||
|
if (missingStyles) {
|
||||||
|
if (o.minify) {
|
||||||
|
document.addInlineStyles(missingStyles, target);
|
||||||
} else {
|
} else {
|
||||||
// Just append to the head
|
document.addInlineStyles(prettifyCss(missingStyles, document.indent), target);
|
||||||
$('head').append(elements);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (links.length > 0) {
|
if (o.replaceStylesheets.length > 0 && links.length > 0) {
|
||||||
// Modify links and ad clones to noscript block
|
// Detect links to be removed
|
||||||
$(links).each(function(idx, el) {
|
const [ref] = links;
|
||||||
if (o.extract && !o.basePath) {
|
const removable = [...document.querySelectorAll('link[rel="stylesheet"], link[rel="preload"][as="style"]')].filter(
|
||||||
throw new Error('Option `basePath` is missing and required when using `extract`!');
|
link => {
|
||||||
|
// Filter ignored links
|
||||||
|
const href = link.getAttribute('href');
|
||||||
|
return !o.ignore.some(i => (isRegExp(i) && i.test(href)) || i === href);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const $el = $(el);
|
// Add link tags before old links
|
||||||
const elIndent = getIndent(html, el);
|
// 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) {
|
if (o.extract) {
|
||||||
const href = $el.attr('href');
|
const href = link.getAttribute('href');
|
||||||
const file = path.resolve(path.join(o.basePath, href));
|
const file = path.resolve(path.join(o.basePath || process.cwd, href));
|
||||||
if (fs.existsSync(file)) {
|
if (fs.existsSync(file)) {
|
||||||
const orig = fs.readFileSync(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);
|
const filename = reaver.rev(file, diff);
|
||||||
|
|
||||||
fs.writeFileSync(filename, 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
|
const noscript = document.createElement('noscript');
|
||||||
$el.after('\n' + elIndent + '<noscript>' + render(this) + '</noscript>');
|
noscript.append(link.cloneNode());
|
||||||
|
document.insertAfter(noscript, link);
|
||||||
|
|
||||||
// Add preload atttibutes to actual link element
|
link.setAttribute('rel', 'preload');
|
||||||
$el.attr('rel', 'preload');
|
link.setAttribute('as', 'style');
|
||||||
$el.attr('as', 'style');
|
link.setAttribute('onload', "this.onload=null;this.rel='stylesheet'");
|
||||||
$el.attr('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
|
return Buffer.from(document.serialize());
|
||||||
const svgs = getSvgs(html);
|
|
||||||
const quickfixed = getSvgs(output).reduce((str, code, index) => str.replace(code, svgs[index] || code), output);
|
|
||||||
|
|
||||||
return Buffer.from(quickfixed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = inline;
|
module.exports = inline;
|
||||||
|
3478
package-lock.json
generated
3478
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"
|
"url": "https://github.com/bezoerb/inline-critical/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cheerio": "0.22.0",
|
"chalk": "^2.4.1",
|
||||||
"clean-css": "^4.2.1",
|
"clean-css": "^4.2.1",
|
||||||
"css": "^2.2.4",
|
"css": "^2.2.4",
|
||||||
"detect-indent": "5.0.0",
|
"detect-indent": "5.0.0",
|
||||||
@ -37,6 +37,7 @@
|
|||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
"get-stdin": "^6.0.0",
|
"get-stdin": "^6.0.0",
|
||||||
"indent-string": "^3.2.0",
|
"indent-string": "^3.2.0",
|
||||||
|
"jsdom": "^13.1.0",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"meow": "^5.0.0",
|
"meow": "^5.0.0",
|
||||||
"normalize-newline": "3.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;
|
float: right !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="preload" href="/css/cartoon.2808011f.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
<link rel="preload" href="/css/cartoon.08b3295a.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||||
<noscript><link rel="stylesheet" href="/css/cartoon.2808011f.css"></noscript>
|
<noscript><link rel="stylesheet" href="/css/cartoon.08b3295a.css"></noscript>
|
||||||
<link rel="preload" href="/bower_components/bootstrap/dist/css/bootstrap.10a09ad4.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
<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.10a09ad4.css"></noscript>
|
<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>
|
<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 -->
|
<!-- endbuild -->
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html class="no-js">
|
<html class="no-js">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
@ -8,21 +8,20 @@
|
|||||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||||
|
|
||||||
<!-- build:css styles/main.css -->
|
<!-- build:css styles/main.css -->
|
||||||
<style>
|
<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>
|
||||||
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'">
|
<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>
|
<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'">
|
<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>
|
<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>
|
<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 -->
|
<!-- endbuild -->
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!--[if lt IE 10]>
|
<!--[if lt IE 10]>
|
||||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade
|
<p class="browsehappy">
|
||||||
your browser</a> to improve your experience.</p>
|
You are using an <strong>outdated</strong> browser. Please
|
||||||
|
<a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
|
||||||
|
</p>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -47,8 +46,10 @@
|
|||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<h4>HTML5 Boilerplate</h4>
|
<h4>HTML5 Boilerplate</h4>
|
||||||
|
|
||||||
<p>HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
<p>
|
||||||
sites.</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>
|
||||||
|
|
||||||
@ -56,9 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer"><p>♥ from the Yeoman team</p></div>
|
||||||
<p>♥ from the Yeoman team</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html class="no-js">
|
<html class="no-js">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
@ -277,18 +277,19 @@
|
|||||||
float: right !important;
|
float: right !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="preload" href="css/cartoon.2808011f.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
<link rel="preload" href="css/cartoon.08b3295a.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||||
<noscript><link rel="stylesheet" href="css/cartoon.2808011f.css"></noscript>
|
<noscript><link rel="stylesheet" href="css/cartoon.08b3295a.css"></noscript>
|
||||||
<link rel="preload" href="bower_components/bootstrap/dist/css/bootstrap.10a09ad4.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
<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.10a09ad4.css"></noscript>
|
<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>
|
<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 -->
|
<!-- endbuild -->
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!--[if lt IE 10]>
|
<!--[if lt IE 10]>
|
||||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade
|
<p class="browsehappy">
|
||||||
your browser</a> to improve your experience.</p>
|
You are using an <strong>outdated</strong> browser. Please
|
||||||
|
<a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
|
||||||
|
</p>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -313,8 +314,10 @@
|
|||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<h4>HTML5 Boilerplate</h4>
|
<h4>HTML5 Boilerplate</h4>
|
||||||
|
|
||||||
<p>HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
<p>
|
||||||
sites.</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>
|
||||||
|
|
||||||
@ -322,9 +325,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer"><p>♥ from the Yeoman team</p></div>
|
||||||
<p>♥ from the Yeoman team</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -279,8 +279,8 @@
|
|||||||
</style>
|
</style>
|
||||||
<link rel="preload" href="css/main.d41d8cd9.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
<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>
|
<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'">
|
<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.10a09ad4.css"></noscript>
|
<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'">
|
<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>
|
<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>
|
<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 -->
|
<!-- endbuild -->
|
||||||
<noscript>
|
<noscript>
|
||||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
|
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
|
||||||
</noscript>
|
</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>
|
<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>
|
</head>
|
||||||
|
27
test/fixtures/cartoon.html
vendored
27
test/fixtures/cartoon.html
vendored
@ -1,22 +1,23 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html class="no-js">
|
<html class="no-js">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<title>critical css test</title>
|
<title>critical css test</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||||
|
|
||||||
<!-- build:css styles/main.css -->
|
<!-- build:css styles/main.css -->
|
||||||
<link rel="stylesheet" href="css/cartoon.css">
|
<link rel="stylesheet" href="css/cartoon.css" />
|
||||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
|
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
|
||||||
<!-- endbuild -->
|
<!-- endbuild -->
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!--[if lt IE 10]>
|
<!--[if lt IE 10]>
|
||||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade
|
<p class="browsehappy">
|
||||||
your browser</a> to improve your experience.</p>
|
You are using an <strong>outdated</strong> browser. Please
|
||||||
|
<a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
|
||||||
|
</p>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -41,8 +42,10 @@
|
|||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<h4>HTML5 Boilerplate</h4>
|
<h4>HTML5 Boilerplate</h4>
|
||||||
|
|
||||||
<p>HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or
|
<p>
|
||||||
sites.</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>
|
||||||
|
|
||||||
@ -50,9 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer"><p>♥ from the Yeoman team</p></div>
|
||||||
<p>♥ from the Yeoman team</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
39
test/fixtures/entities2.html
vendored
39
test/fixtures/entities2.html
vendored
@ -5,7 +5,19 @@
|
|||||||
<title>asd</title>
|
<title>asd</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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">
|
<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 />
|
<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 " />
|
||||||
@ -14,11 +26,30 @@
|
|||||||
<path
|
<path
|
||||||
style="fill:#000000"
|
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 "
|
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" />
|
id="path2223"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
<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>
|
<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>
|
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,30 +1,11 @@
|
|||||||
/* eslint-env jest */
|
/* eslint-env jest */
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const reaver = require('reaver');
|
const reaver = require('reaver');
|
||||||
const postcss = require('postcss');
|
const {extractCss} = require('../src/css.js');
|
||||||
const discard = require('postcss-discard');
|
|
||||||
const normalizeNewline = require('normalize-newline');
|
|
||||||
const CleanCSS = require('clean-css');
|
|
||||||
const prettier = require('prettier');
|
|
||||||
const inline = require('..');
|
const inline = require('..');
|
||||||
|
|
||||||
const {read, checkAndDelete, strip} = require('./helper');
|
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);
|
jest.setTimeout(20000);
|
||||||
|
|
||||||
test('Inline css', async () => {
|
test('Inline css', async () => {
|
||||||
@ -65,7 +46,7 @@ test('Inline and minify css', async () => {
|
|||||||
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
|
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 html = await read('fixtures/cartoon.html');
|
||||||
const css = await read('fixtures/critical.css');
|
const css = await read('fixtures/critical.css');
|
||||||
const expected = await read('expected/cartoon-expected.html');
|
const expected = await read('expected/cartoon-expected.html');
|
||||||
@ -76,8 +57,8 @@ test('should inline and extract css', async () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const reved = [
|
const reved = [
|
||||||
reaver.rev('fixtures/css/cartoon.css', extract(styles[0], css)),
|
reaver.rev('fixtures/css/cartoon.css', extractCss(styles[0], css)),
|
||||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extract(styles[1], css)),
|
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extractCss(styles[1], css)),
|
||||||
];
|
];
|
||||||
|
|
||||||
const out = inline(html, 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));
|
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 html = await read('fixtures/cartoon.html');
|
||||||
const css = await read('fixtures/critical.css');
|
const css = await read('fixtures/critical.css');
|
||||||
const expected = await read('expected/cartoon-expected-minified.html');
|
const expected = await read('expected/cartoon-expected-minified.html');
|
||||||
@ -104,8 +85,8 @@ test('should extract and minify css', async () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const reved = [
|
const reved = [
|
||||||
reaver.rev('fixtures/css/cartoon.css', extract(styles[0], css, true)),
|
reaver.rev('fixtures/css/cartoon.css', extractCss(styles[0], css)),
|
||||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extract(styles[1], css, true)),
|
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extractCss(styles[1], css)),
|
||||||
];
|
];
|
||||||
|
|
||||||
const out = inline(html, 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));
|
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 html = await read('fixtures/cartoon-absolute.html');
|
||||||
const css = await read('fixtures/critical.css');
|
const css = await read('fixtures/critical.css');
|
||||||
const expected = await read('expected/cartoon-absolute-expected.html');
|
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 = [
|
const reved = [
|
||||||
reaver.rev('fixtures/css/cartoon.css', extract(styles[0], css)),
|
reaver.rev('fixtures/css/cartoon.css', extractCss(styles[0], css)),
|
||||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extract(styles[1], css)),
|
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extractCss(styles[1], css)),
|
||||||
];
|
];
|
||||||
|
|
||||||
const out = inline(html, 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));
|
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 html = await read('fixtures/entities.html');
|
||||||
const out = inline(html, '', {minify: false});
|
const out = inline(html, '', {minify: false});
|
||||||
|
|
||||||
expect(strip(out.toString('utf-8'))).toBe(strip(html));
|
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 html = await read('fixtures/svg.html');
|
||||||
const expected = await read('expected/test-svg.html');
|
const expected = await read('expected/test-svg.html');
|
||||||
const css = 'html{font-size:16;}';
|
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));
|
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) {
|
function strip2(string) {
|
||||||
return string.replace(/\s+/gm, '');
|
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));
|
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 html = await read('fixtures/external.html');
|
||||||
const css = await read('fixtures/critical.css');
|
const css = await read('fixtures/critical.css');
|
||||||
const expected = await read('expected/external-extract-expected.html');
|
const expected = await read('expected/external-extract-expected.html');
|
||||||
@ -187,8 +168,8 @@ test('should not extract on external urls', async () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const reved = [
|
const reved = [
|
||||||
reaver.rev('fixtures/css/main.css', extract(styles[0], css)),
|
reaver.rev('fixtures/css/main.css', extractCss(styles[0], css)),
|
||||||
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extract(styles[1], css)),
|
reaver.rev('fixtures/bower_components/bootstrap/dist/css/bootstrap.css', extractCss(styles[1], css)),
|
||||||
];
|
];
|
||||||
|
|
||||||
const out = inline(html, 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));
|
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 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));
|
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) {
|
function strip2(string) {
|
||||||
return string.replace(/\s+/gm, '');
|
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));
|
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) {
|
function strip2(string) {
|
||||||
return string.replace(/\s+/gm, '');
|
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));
|
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) {
|
function strip2(string) {
|
||||||
return string.replace(/\s+/gm, '');
|
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));
|
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 html = await read('fixtures/index.html');
|
||||||
const css = await read('fixtures/critical.css');
|
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));
|
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 html = await read('fixtures/index-noscript.html');
|
||||||
const css = await read('fixtures/critical.css');
|
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));
|
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 html = await read('fixtures/loadcss.html');
|
||||||
const css = await read('fixtures/critical.css');
|
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));
|
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 html = await read('fixtures/index-inlined.html');
|
||||||
const css = await read('fixtures/critical.css');
|
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));
|
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 html = await read('fixtures/loadcss-again.html');
|
||||||
const css = await read('fixtures/critical.css');
|
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));
|
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