Bump dependencies

This commit is contained in:
Ben Zörb 2020-05-23 00:36:56 +02:00
parent f586a79eac
commit 7e59c3809d
No known key found for this signature in database
GPG Key ID: B5022087DA9E02FF
9 changed files with 2388 additions and 1517 deletions

39
cli.js
View File

@ -47,6 +47,7 @@ const cli = meow(help, {
ignore: {
type: 'string',
alias: 'i',
isMultiple: true,
},
minify: {
type: 'boolean',
@ -81,28 +82,28 @@ const cli = meow(help, {
});
// Cleanup cli flags
cli.flags = Object.entries(cli.flags).reduce((res, [key, val]) => {
cli.flags = Object.entries(cli.flags).reduce((result, [key, value]) => {
if (key.length <= 1) {
return res;
return result;
}
switch (key) {
case 'css':
case 'html':
try {
res[key] = read(val);
result[key] = read(value);
} catch (_) {}
break;
case 'base':
res.basePath = val;
result.basePath = value;
break;
case 'ignore':
if (!Array.isArray(val)) {
val = [val];
if (!Array.isArray(value)) {
value = [value];
}
res.ignore = (val || []).map(ignore => {
result.ignore = (value || []).map((ignore) => {
// Check regex
const {groups} = /^\/(?<expression>.*)\/(?<flags>[igmy]+)?$/.exec(ignore) || {};
const {expression, flags} = groups || {};
@ -115,11 +116,11 @@ cli.flags = Object.entries(cli.flags).reduce((res, [key, val]) => {
});
break;
default:
res[key] = val;
result[key] = value;
break;
}
return res;
return result;
}, {});
function processError(err) {
@ -138,34 +139,34 @@ function read(file) {
}
function run(data) {
const opts = defaults(cli.flags, {basePath: process.cwd()});
const options_ = defaults(cli.flags, {basePath: process.cwd()});
ok = true;
if (data) {
// Detect html
try {
css.parse(data);
opts.css = data;
options_.css = data;
} catch (_) {
opts.html = data;
options_.html = data;
}
}
(cli.input || []).forEach(file => {
const tmp = read(file);
(cli.input || []).forEach((file) => {
const temporary = read(file);
try {
css.parse(tmp);
opts.css = tmp;
css.parse(temporary);
options_.css = temporary;
} catch (_) {
opts.html = tmp;
options_.html = temporary;
}
});
if (!opts.html || !opts.css) {
if (!options_.html || !options_.css) {
cli.showHelp();
}
const {html, css: styles, ...options} = opts;
const {html, css: styles, ...options} = options_;
try {
const out = inlineCritical(html, styles, options);

View File

@ -37,8 +37,8 @@ const DEFAULT_OPTIONS = {
* @param {string} str Filepath
* @return {string} Normalized path
*/
function normalizePath(str) {
return process.platform === 'win32' ? slash(str) : str;
function normalizePath(string) {
return process.platform === 'win32' ? slash(string) : string;
}
/**
@ -56,7 +56,7 @@ function inline(html, styles, options) {
}
if (!Array.isArray(o.ignore)) {
o.ignore = [o.ignore].filter(i => i);
o.ignore = [o.ignore].filter((i) => i);
}
const document = new Dom(html, o);
@ -65,12 +65,12 @@ function inline(html, styles, options) {
const externalStyles = document.getExternalStyles();
const missingStyles = extractCss(styles, ...inlineStyles);
const links = externalStyles.filter(link => {
const links = externalStyles.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);
return stylesheet && !o.ignore.some((i) => (isRegExp(i) && i.test(href)) || i === href);
});
const targetSelectors = [
@ -95,16 +95,16 @@ function inline(html, styles, options) {
// Detect links to be removed
const [ref] = links;
const removable = [...document.querySelectorAll('link[rel="stylesheet"], link[rel="preload"][as="style"]')].filter(
link => {
(link) => {
// Filter ignored links
const href = link.getAttribute('href');
return !o.ignore.some(i => (isRegExp(i) && i.test(href)) || i === href);
return !o.ignore.some((i) => (isRegExp(i) && i.test(href)) || i === href);
}
);
// Add link tags before old links
// eslint-disable-next-line array-callback-return
o.replaceStylesheets.map(href => {
o.replaceStylesheets.map((href) => {
const link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
@ -121,7 +121,7 @@ function inline(html, styles, options) {
link.setAttribute('onload', "this.media='all'");
}
document.insertBefore(link, ref);
ref.before(link);
if (!o.polyfill && o.preload) {
const preload = document.createElement('link');
@ -129,13 +129,13 @@ function inline(html, styles, options) {
preload.setAttribute('href', link.getAttribute('href'));
preload.setAttribute('as', 'style');
document.insertBefore(preload, link);
link.before(preload);
}
});
// Remove old links
// eslint-disable-next-line array-callback-return
removable.map(link => {
removable.map((link) => {
if (link.parentElement.tagName === 'NOSCRIPT') {
document.remove(link.parentElement);
} else {
@ -145,7 +145,7 @@ function inline(html, styles, options) {
} else {
// Modify links and add clones to noscript block
// eslint-disable-next-line array-callback-return
links.map(link => {
links.map((link) => {
if (o.extract) {
const href = link.getAttribute('href');
const file = path.resolve(path.join(o.basePath || process.cwd, href));
@ -179,7 +179,7 @@ function inline(html, styles, options) {
preload.setAttribute('href', link.getAttribute('href'));
preload.setAttribute('rel', 'preload');
preload.setAttribute('as', 'style');
document.insertBefore(preload, link);
link.before(preload);
}
});
}

3742
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -30,33 +30,33 @@
"url": "https://github.com/bezoerb/inline-critical/issues"
},
"dependencies": {
"chalk": "^3.0.0",
"chalk": "^4.0.0",
"clean-css": "^4.2.3",
"css": "^2.2.4",
"detect-indent": "^6.0.0",
"fg-loadcss": "^2.1.0",
"get-stdin": "^7.0.0",
"get-stdin": "^8.0.0",
"indent-string": "^4.0.0",
"jsdom": "^15.2.1",
"jsdom": "^16.2.2",
"lodash.defaults": "^4.2.0",
"lodash.escaperegexp": "^4.1.2",
"lodash.isregexp": "^4.0.1",
"lodash.isstring": "^4.0.1",
"meow": "^5.0.0",
"meow": "^7.0.1",
"normalize-newline": "^3.0.0",
"postcss": "^7.0.30",
"postcss-discard": "^0.3.3",
"prettier": "^1.19.1",
"postcss-discard": "^0.3.7",
"prettier": "^2.0.5",
"reaver": "^2.0.0",
"slash": "^3.0.0",
"uglify-js": "^3.9.3"
},
"devDependencies": {
"execa": "^1.0.0",
"fs-extra": "^8.1.0",
"execa": "^4.0.2",
"fs-extra": "^9.0.0",
"jest": "^26.0.1",
"read-pkg-up": "^7.0.1",
"xo": "^0.25.3"
"xo": "^0.30.0"
},
"xo": {
"space": 2,

View File

@ -24,8 +24,8 @@ function getScript() {
* @param {array} arr Input Array
* @returns {array} Flattened Array
*/
function flatten(arr) {
return arr.reduce((a, b) => a.concat(b), []);
function flatten(array) {
return array.reduce((a, b) => a.concat(b), []);
}
/**
@ -37,11 +37,11 @@ function flatten(arr) {
*/
const getPartials = (html = '', tag = 'svg') => {
const result = [];
html.replace(new RegExp(`<${tag}(?:\\s[^>]+)?>`, 'ig'), (match, offset, str) => {
html.replace(new RegExp(`<${tag}(?:\\s[^>]+)?>`, 'ig'), (match, offset, string) => {
if (match.includes('/>')) {
result.push(str.slice(offset, offset + match.length));
result.push(string.slice(offset, offset + match.length));
} else {
result.push(str.slice(offset, str.indexOf(`</${tag}>`, offset) + `</${tag}>`.length));
result.push(string.slice(offset, string.indexOf(`</${tag}>`, offset) + `</${tag}>`.length));
}
return match;
@ -68,7 +68,7 @@ const replacePartials = (source, dest, tag) => {
const newTags = getPartials(dest, tag);
const oldTags = getPartials(result, tag);
return oldTags.reduce((str, code, index) => str.replace(code, newTags[index] || code), result);
return oldTags.reduce((string, code, index) => string.replace(code, newTags[index] || code), result);
}, source);
};
@ -106,10 +106,10 @@ class Dom {
}
if (this.noscriptPosition === 'head') {
return result.replace(/^([\s\t]*)(<\/\s*head>)/gim, `$1$1${this.noscript.join('\n$1$1')}\n$1$2`); // eslint-disable-line prefer-named-capture-group
return result.replace(/^([\s\t]*)(<\/\s*head>)/gim, `$1$1${this.noscript.join('\n$1$1')}\n$1$2`);
}
return result.replace(/^([\s\t]*)(<\/\s*body>)/gim, `$1$1${this.noscript.join('\n$1$1')}\n$1$2`); // eslint-disable-line prefer-named-capture-group
return result.replace(/^([\s\t]*)(<\/\s*body>)/gim, `$1$1${this.noscript.join('\n$1$1')}\n$1$2`);
}
createStyleNode(css, referenceIndent = this.headIndent.indent) {
@ -135,18 +135,18 @@ class Dom {
}
getInlineStyles() {
return [...this.document.querySelectorAll('head style')].map(node => node.textContent);
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'
(link) => link.parentElement.tagName !== 'NOSCRIPT'
);
}
querySelector(...selector) {
const s = flatten(selector)
.filter(s => s)
.filter((s) => s)
.join(',');
return this.document.querySelector(s);
@ -154,7 +154,7 @@ class Dom {
querySelectorAll(...selector) {
const s = flatten(selector)
.filter(s => s)
.filter((s) => s)
.join(',');
return this.document.querySelectorAll(s);
@ -211,7 +211,7 @@ class Dom {
maybeAddLoadcss() {
// Only add loadcss if it's not already included
const loadCssIncluded = [...this.document.querySelectorAll('script')].some(tag =>
const loadCssIncluded = [...this.document.querySelectorAll('script')].some((tag) =>
(tag.textContent || '').includes('loadCSS')
);
@ -222,7 +222,7 @@ class Dom {
// 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');
].filter((link) => link.parentElement.tagName !== 'NOSCRIPT');
const scriptAnchor = nodes.pop();
const script = this.document.createElement('script');
script.append(this.document.createTextNode(getScript()));

View File

@ -11,24 +11,24 @@ jest.setTimeout(10000);
describe('acceptance', () => {
test('Return version', async () => {
const {packageJson} = await readPkgUp();
const {stdout, stderr, code} = await run(['--version', '--no-update-notifier']);
const result = await run(['--version']);
const {stdout, stderr, exitCode} = result || {};
expect(stderr).toBeFalsy();
expect(code).toBe(0);
expect(exitCode).toBe(0);
expect(stdout).toBe(packageJson.version);
});
test('should work well with the critical CSS & html file passed as input', async () => {
const expected = await read('expected/index-inlined-async-final-print.html');
const {stdout, code} = await run(['test/fixtures/index.html', 'test/fixtures/critical.css', '--no-minify']);
const {stdout, exitCode} = await run(['test/fixtures/index.html', 'test/fixtures/critical.css', '--no-minify']);
expect(code).toBe(0);
expect(exitCode).toBe(0);
expect(strip(stdout)).toBe(strip(expected));
});
test('should work well with the critical CSS passed as input & html file passed as option', async () => {
const expected = await read('expected/index-inlined-async-final.html');
const {stdout, code} = await run([
const {stdout, exitCode} = await run([
'--html',
'test/fixtures/index.html',
'test/fixtures/critical.css',
@ -36,13 +36,13 @@ describe('acceptance', () => {
'--polyfill',
]);
expect(code).toBe(0);
expect(exitCode).toBe(0);
expect(strip(stdout)).toBe(strip(expected));
});
test('should work well with the critical CSS passed as option & html file passed as input', async () => {
const expected = await read('expected/index-inlined-async-final.html');
const {stdout, code} = await run([
const {stdout, exitCode} = await run([
'--css',
'test/fixtures/critical.css',
'test/fixtures/index.html',
@ -50,33 +50,33 @@ describe('acceptance', () => {
'--polyfill',
]);
expect(code).toBe(0);
expect(exitCode).toBe(0);
expect(strip(stdout)).toBe(strip(expected));
});
test('Work well with the critical CSS file piped to inline-critical and html file as input', async () => {
const expected = await read('expected/index-inlined-async-final-print.html');
const {stdout, code} = await pipe('fixtures/critical.css', ['test/fixtures/index.html', '--no-minify']);
expect(code).toBe(0);
const result = await pipe('fixtures/critical.css', ['test/fixtures/index.html', '--no-minify']);
const {stdout, exitCode} = result || {};
expect(exitCode).toBe(0);
expect(strip(stdout)).toBe(strip(expected));
});
test('Work well with the html file piped to inline-critical and critical CSS file as input', async () => {
const expected = await read('expected/index-inlined-async-final-print.html');
const {stdout, code} = await pipe('fixtures/index.html', ['test/fixtures/critical.css', '--no-minify']);
const {stdout, exitCode} = await pipe('fixtures/index.html', ['test/fixtures/critical.css', '--no-minify']);
expect(code).toBe(0);
expect(exitCode).toBe(0);
expect(strip(stdout)).toBe(strip(expected));
});
test('Exit with code != 0 and show help', async () => {
test('Exit with exitCode != 0 and show help', async () => {
expect.assertions(2);
try {
await run(['fixtures/not-exists.html']);
} catch (error) {
expect(error.stderr).toMatch('Usage:');
expect(error.code).not.toBe(0);
expect(error.exitCode).not.toBe(0);
}
});
});

View File

@ -15,7 +15,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 t,o=loadCSS.relpreload={};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(),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>

View File

@ -1,20 +1,19 @@
/* eslint-env jest */
'use strict';
const path = require('path');
const fs = require('fs-extra');
const readPkgUp = require('read-pkg-up');
const execa = require('execa');
const nn = require('normalize-newline');
const read = async file => {
const read = async (file) => {
const filepath = path.isAbsolute(file) ? file : path.join(__dirname, '..', file);
const content = await fs.readFile(filepath, 'utf8');
return nn(content);
};
const checkAndDelete = file => {
const checkAndDelete = (file) => {
const filepath = path.isAbsolute(file) ? file : path.join(__dirname, '..', file);
if (fs.existsSync(filepath)) {
fs.removeSync(filepath);
@ -24,7 +23,7 @@ const checkAndDelete = file => {
return false;
};
const strip = string => nn(string.replace(/[\r\n]+/gm, ' ').replace(/\s+/gm, ''));
const strip = (string) => nn(string.replace(/[\r\n]+/gm, ' ').replace(/\s+/gm, ''));
const getBin = async () => {
const {packageJson} = await readPkgUp();
@ -36,20 +35,20 @@ const run = async (args = []) => {
return execa('node', [bin, ...args]);
};
const getArgs = async (params = []) => {
const getArgs = async (parameters = []) => {
const bin = await getBin();
const origArgv = process.argv;
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
jest.mock('../../index', () => jest.fn(() => ''));
process.argv = ['node', bin, ...params];
process.argv = ['node', bin, ...parameters];
const inline = require('../..');
require('../../cli'); // eslint-disable-line import/no-unassigned-import
// wait for cli to run
await new Promise(resolve => setTimeout(resolve, 200));
await new Promise((resolve) => setTimeout(resolve, 200));
const [args] = inline.mock.calls;
const [html, styles, options] = args || ['', '', {}];
expect(inline).toHaveBeenCalledTimes(1);
@ -64,7 +63,7 @@ const pipe = async (file, args = []) => {
const cat = process.platform === 'win32' ? 'type' : 'cat';
const bin = await getBin();
const cmd = `${cat} ${path.normalize(filepath)} | node ${bin} ${args.join(' ')}`;
return execa.shell(cmd);
return execa(cmd, {shell: true});
};
module.exports = {

View File

@ -1,7 +1,5 @@
/* eslint-env jest */
'use strict';
const path = require('path');
const reaver = require('reaver');
const {extractCss} = require('../src/css.js');
@ -544,7 +542,6 @@ test('Ignore stylesheets wrapped in noscript', async () => {
const expected = await read('expected/index-noscript-inlined-minified-final.html');
const out = inline(html, css, {minify: true, polyfill: true});
expect(strip(out.toString('utf-8'))).toBe(strip(expected));
});