@automattic/jetpack-critical-css-gen 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -1
- package/package.json +17 -20
- package/build-browser/bundle.full.js +0 -37567
- package/build-browser/bundle.full.js.map +0 -1
- package/build-browser/bundle.js +0 -4
- package/build-browser/bundle.js.map +0 -1
- package/build-node/browser-interface-playwright.d.ts +0 -53
- package/build-node/browser-interface-playwright.js +0 -94
- package/build-node/browser-interface-playwright.js.map +0 -1
- package/build-node/browser-interface.d.ts +0 -77
- package/build-node/browser-interface.js +0 -124
- package/build-node/browser-interface.js.map +0 -1
- package/build-node/css-file-set.d.ts +0 -100
- package/build-node/css-file-set.js +0 -210
- package/build-node/css-file-set.js.map +0 -1
- package/build-node/errors.d.ts +0 -101
- package/build-node/errors.js +0 -103
- package/build-node/errors.js.map +0 -1
- package/build-node/generate-critical-css.d.ts +0 -24
- package/build-node/generate-critical-css.js +0 -162
- package/build-node/generate-critical-css.js.map +0 -1
- package/build-node/ignored-pseudo-elements.d.ts +0 -8
- package/build-node/ignored-pseudo-elements.js +0 -35
- package/build-node/ignored-pseudo-elements.js.map +0 -1
- package/build-node/minify-css.d.ts +0 -11
- package/build-node/minify-css.js +0 -19
- package/build-node/minify-css.js.map +0 -1
- package/build-node/node.d.ts +0 -5
- package/build-node/node.js +0 -6
- package/build-node/node.js.map +0 -1
- package/build-node/object-promise-all.d.ts +0 -12
- package/build-node/object-promise-all.js +0 -16
- package/build-node/object-promise-all.js.map +0 -1
- package/build-node/style-ast.d.ts +0 -164
- package/build-node/style-ast.js +0 -540
- package/build-node/style-ast.js.map +0 -1
- package/build-node/types.d.ts +0 -14
- package/build-node/types.js +0 -2
- package/build-node/types.js.map +0 -1
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { BrowserContext, Page } from 'playwright-core';
|
|
2
|
-
import { BrowserInterface, BrowserRunnable, FetchOptions } from './browser-interface.js';
|
|
3
|
-
import { Viewport } from './types.js';
|
|
4
|
-
export type Tab = {
|
|
5
|
-
page: Page;
|
|
6
|
-
statusCode: number | null;
|
|
7
|
-
};
|
|
8
|
-
export type TabsByUrl = {
|
|
9
|
-
[url: string]: Tab;
|
|
10
|
-
};
|
|
11
|
-
export declare class BrowserInterfacePlaywright extends BrowserInterface {
|
|
12
|
-
private context;
|
|
13
|
-
private urls;
|
|
14
|
-
private tabs;
|
|
15
|
-
/**
|
|
16
|
-
* Creates a new BrowserInterfacePlaywright instance.
|
|
17
|
-
*
|
|
18
|
-
* @param {BrowserContext} context - The playwright browser context to work with.
|
|
19
|
-
* @param {string[]} urls - Array of urls to evaluate. The reason we are taking this as an argument is because we want to load all of them in parallel.
|
|
20
|
-
*/
|
|
21
|
-
constructor(context: BrowserContext, urls: string[]);
|
|
22
|
-
private getTabs;
|
|
23
|
-
/**
|
|
24
|
-
* Open an array of urls in a new browser context.
|
|
25
|
-
*
|
|
26
|
-
* Take a browser instance and an array of urls to open in new tabs.
|
|
27
|
-
*
|
|
28
|
-
* @param {BrowserContext} context - Browser context to use.
|
|
29
|
-
* @param {string[]} urls - Array of urls to open.
|
|
30
|
-
* @return {Promise< TabsByUrl >} Promise resolving to the browser context.
|
|
31
|
-
*/
|
|
32
|
-
private openUrls;
|
|
33
|
-
/**
|
|
34
|
-
* Open url in a new tab in a given browserContext.
|
|
35
|
-
*
|
|
36
|
-
* @param {BrowserContext} browserContext - Browser context to use.
|
|
37
|
-
* @param {string} url - Url to open.
|
|
38
|
-
* @return {Promise<Page>} Promise resolving to the page instance.
|
|
39
|
-
*/
|
|
40
|
-
private newTab;
|
|
41
|
-
runInPage<ReturnType>(pageUrl: string, viewport: Viewport | null, method: BrowserRunnable<ReturnType>, ...args: unknown[]): Promise<ReturnType>;
|
|
42
|
-
/**
|
|
43
|
-
* Replacement for browser.fetch, uses node's fetch to simulate the same
|
|
44
|
-
* interface.
|
|
45
|
-
*
|
|
46
|
-
* @param {string} url - URL to fetch.
|
|
47
|
-
* @param {object} options - Fetch options.
|
|
48
|
-
* @param {string} _role - 'css' or 'html' indicating what kind of thing is being fetched.
|
|
49
|
-
* @return {Promise<Response>} A promise that resolves to the fetch response.
|
|
50
|
-
*/
|
|
51
|
-
fetch(url: string, options: FetchOptions, _role: 'css' | 'html'): Promise<Response>;
|
|
52
|
-
private isOkStatus;
|
|
53
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { BrowserInterface } from './browser-interface.js';
|
|
2
|
-
import { HttpError } from './errors.js';
|
|
3
|
-
import { objectPromiseAll } from './object-promise-all.js';
|
|
4
|
-
const PAGE_GOTO_TIMEOUT_MS = 5 * 60 * 1000;
|
|
5
|
-
export class BrowserInterfacePlaywright extends BrowserInterface {
|
|
6
|
-
/**
|
|
7
|
-
* Creates a new BrowserInterfacePlaywright instance.
|
|
8
|
-
*
|
|
9
|
-
* @param {BrowserContext} context - The playwright browser context to work with.
|
|
10
|
-
* @param {string[]} urls - Array of urls to evaluate. The reason we are taking this as an argument is because we want to load all of them in parallel.
|
|
11
|
-
*/
|
|
12
|
-
constructor(context, urls) {
|
|
13
|
-
super();
|
|
14
|
-
this.context = context;
|
|
15
|
-
this.urls = urls;
|
|
16
|
-
}
|
|
17
|
-
async getTabs() {
|
|
18
|
-
if (typeof this.tabs === 'undefined') {
|
|
19
|
-
await this.openUrls(this.context, this.urls);
|
|
20
|
-
}
|
|
21
|
-
return this.tabs;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Open an array of urls in a new browser context.
|
|
25
|
-
*
|
|
26
|
-
* Take a browser instance and an array of urls to open in new tabs.
|
|
27
|
-
*
|
|
28
|
-
* @param {BrowserContext} context - Browser context to use.
|
|
29
|
-
* @param {string[]} urls - Array of urls to open.
|
|
30
|
-
* @return {Promise< TabsByUrl >} Promise resolving to the browser context.
|
|
31
|
-
*/
|
|
32
|
-
async openUrls(context, urls) {
|
|
33
|
-
this.tabs = await objectPromiseAll(urls.reduce((set, url) => {
|
|
34
|
-
set[url] = this.newTab(context, url);
|
|
35
|
-
return set;
|
|
36
|
-
}, {}));
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Open url in a new tab in a given browserContext.
|
|
40
|
-
*
|
|
41
|
-
* @param {BrowserContext} browserContext - Browser context to use.
|
|
42
|
-
* @param {string} url - Url to open.
|
|
43
|
-
* @return {Promise<Page>} Promise resolving to the page instance.
|
|
44
|
-
*/
|
|
45
|
-
async newTab(browserContext, url) {
|
|
46
|
-
const tab = {
|
|
47
|
-
page: await browserContext.newPage(),
|
|
48
|
-
statusCode: null,
|
|
49
|
-
};
|
|
50
|
-
tab.page.on('response', async (response) => {
|
|
51
|
-
if (response.url() === url) {
|
|
52
|
-
tab.statusCode = response.status();
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
await tab.page.goto(url, { timeout: PAGE_GOTO_TIMEOUT_MS });
|
|
56
|
-
return tab;
|
|
57
|
-
}
|
|
58
|
-
async runInPage(pageUrl, viewport, method, ...args) {
|
|
59
|
-
const tabs = await this.getTabs();
|
|
60
|
-
const tab = tabs[pageUrl];
|
|
61
|
-
if (!tab || !tab.page) {
|
|
62
|
-
throw new Error(`Playwright interface does not include URL ${pageUrl}`);
|
|
63
|
-
}
|
|
64
|
-
// Bail early if the page returned a non-200 status code.
|
|
65
|
-
if (!tab.statusCode || !this.isOkStatus(tab.statusCode)) {
|
|
66
|
-
const error = new HttpError({ url: pageUrl, code: tab.statusCode });
|
|
67
|
-
this.trackUrlError(pageUrl, error);
|
|
68
|
-
throw error;
|
|
69
|
-
}
|
|
70
|
-
if (viewport) {
|
|
71
|
-
await tab.page.setViewportSize(viewport);
|
|
72
|
-
}
|
|
73
|
-
// The inner window in Playwright is the directly accessible main window object.
|
|
74
|
-
// The evaluating method does not need a separate window object.
|
|
75
|
-
// Call inner method within the Playwright context.
|
|
76
|
-
return tab.page.evaluate(method, { innerWindow: null, args });
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Replacement for browser.fetch, uses node's fetch to simulate the same
|
|
80
|
-
* interface.
|
|
81
|
-
*
|
|
82
|
-
* @param {string} url - URL to fetch.
|
|
83
|
-
* @param {object} options - Fetch options.
|
|
84
|
-
* @param {string} _role - 'css' or 'html' indicating what kind of thing is being fetched.
|
|
85
|
-
* @return {Promise<Response>} A promise that resolves to the fetch response.
|
|
86
|
-
*/
|
|
87
|
-
async fetch(url, options, _role) {
|
|
88
|
-
return fetch(url, options);
|
|
89
|
-
}
|
|
90
|
-
isOkStatus(statusCode) {
|
|
91
|
-
return statusCode >= 200 && statusCode < 300;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
//# sourceMappingURL=browser-interface-playwright.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"browser-interface-playwright.js","sourceRoot":"","sources":["../src/browser-interface-playwright.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAiC,MAAM,wBAAwB,CAAC;AACzF,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAM3D,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAE3C,MAAM,OAAO,0BAA2B,SAAQ,gBAAgB;IAG/D;;;;;OAKG;IACH,YACS,OAAuB,EACvB,IAAc;QAEtB,KAAK,EAAE,CAAC;QAHA,YAAO,GAAP,OAAO,CAAgB;QACvB,SAAI,GAAJ,IAAI,CAAU;IAGvB,CAAC;IAEO,KAAK,CAAC,OAAO;QACpB,IAAK,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,EAAG;YACvC,MAAM,IAAI,CAAC,QAAQ,CAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAE,CAAC;SAC/C;QAED,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,QAAQ,CAAE,OAAuB,EAAE,IAAc;QAC9D,IAAI,CAAC,IAAI,GAAG,MAAM,gBAAgB,CACjC,IAAI,CAAC,MAAM,CAAE,CAAE,GAAG,EAAE,GAAG,EAAG,EAAE;YAC3B,GAAG,CAAE,GAAG,CAAE,GAAG,IAAI,CAAC,MAAM,CAAE,OAAO,EAAE,GAAG,CAAE,CAAC;YACzC,OAAO,GAAG,CAAC;QACZ,CAAC,EAAE,EAAE,CAAE,CACP,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,MAAM,CAAE,cAA8B,EAAE,GAAW;QAChE,MAAM,GAAG,GAAG;YACX,IAAI,EAAE,MAAM,cAAc,CAAC,OAAO,EAAE;YACpC,UAAU,EAAE,IAAI;SAChB,CAAC;QACF,GAAG,CAAC,IAAI,CAAC,EAAE,CAAE,UAAU,EAAE,KAAK,EAAC,QAAQ,EAAC,EAAE;YACzC,IAAK,QAAQ,CAAC,GAAG,EAAE,KAAK,GAAG,EAAG;gBAC7B,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;aACnC;QACF,CAAC,CAAE,CAAC;QAEJ,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAE,GAAG,EAAE,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAE,CAAC;QAE9D,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,SAAS,CACd,OAAe,EACf,QAAyB,EACzB,MAAqC,EACrC,GAAG,IAAe;QAElB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAE,OAAO,CAAE,CAAC;QAE5B,IAAK,CAAE,GAAG,IAAI,CAAE,GAAG,CAAC,IAAI,EAAG;YAC1B,MAAM,IAAI,KAAK,CAAE,6CAA8C,OAAQ,EAAE,CAAE,CAAC;SAC5E;QAED,yDAAyD;QACzD,IAAK,CAAE,GAAG,CAAC,UAAU,IAAI,CAAE,IAAI,CAAC,UAAU,CAAE,GAAG,CAAC,UAAU,CAAE,EAAG;YAC9D,MAAM,KAAK,GAAG,IAAI,SAAS,CAAE,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,CAAE,CAAC;YACtE,IAAI,CAAC,aAAa,CAAE,OAAO,EAAE,KAAK,CAAE,CAAC;YACrC,MAAM,KAAK,CAAC;SACZ;QAED,IAAK,QAAQ,EAAG;YACf,MAAM,GAAG,CAAC,IAAI,CAAC,eAAe,CAAE,QAAQ,CAAE,CAAC;SAC3C;QAED,gFAAgF;QAChF,gEAAgE;QAChE,mDAAmD;QACnD,OAAO,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAE,MAAM,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,CAAE,CAAC;IACjE,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,KAAK,CAAE,GAAW,EAAE,OAAqB,EAAE,KAAqB;QACrE,OAAO,KAAK,CAAE,GAAG,EAAE,OAAO,CAAE,CAAC;IAC9B,CAAC;IAEO,UAAU,CAAE,UAAkB;QACrC,OAAO,UAAU,IAAI,GAAG,IAAI,UAAU,GAAG,GAAG,CAAC;IAC9C,CAAC;CACD"}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import type { Viewport } from './types.js';
|
|
2
|
-
export type BrowserRunnable<ReturnType> = (arg: unknown) => ReturnType;
|
|
3
|
-
export interface FetchOptions {
|
|
4
|
-
method?: 'POST' | 'GET';
|
|
5
|
-
}
|
|
6
|
-
export interface FetchResponse {
|
|
7
|
-
ok: boolean;
|
|
8
|
-
status: number;
|
|
9
|
-
text: () => Promise<string>;
|
|
10
|
-
}
|
|
11
|
-
export declare class BrowserInterface {
|
|
12
|
-
private urlErrors;
|
|
13
|
-
constructor();
|
|
14
|
-
trackUrlError(url: string, error: Error): void;
|
|
15
|
-
filterValidUrls(urls: string[]): string[];
|
|
16
|
-
runInPage<ReturnType>(_pageUrl: string, _viewport: Viewport | null, _method: BrowserRunnable<ReturnType>, ..._args: unknown[]): Promise<ReturnType>;
|
|
17
|
-
/**
|
|
18
|
-
* Context-specific wrapper for fetch; uses window.fetch in browsers, or a
|
|
19
|
-
* node library when using Puppeteer.
|
|
20
|
-
*
|
|
21
|
-
* @param {string} _url - The URL to fetch
|
|
22
|
-
* @param {FetchOptions} _options - Fetch options
|
|
23
|
-
* @param {'css' | 'html'} _role - Role of the fetch operation
|
|
24
|
-
*/
|
|
25
|
-
fetch(_url: string, _options: FetchOptions, _role: 'css' | 'html'): Promise<FetchResponse>;
|
|
26
|
-
cleanup(): Promise<void>;
|
|
27
|
-
getCssIncludes(pageUrl: string): Promise<{
|
|
28
|
-
[url: string]: {
|
|
29
|
-
media: string;
|
|
30
|
-
};
|
|
31
|
-
}>;
|
|
32
|
-
static innerGetCssIncludes({ innerWindow }: {
|
|
33
|
-
innerWindow: any;
|
|
34
|
-
}): any;
|
|
35
|
-
getInternalStyles(pageUrl: string): Promise<string>;
|
|
36
|
-
/**
|
|
37
|
-
* Get all internal styles as a combined string from the window.
|
|
38
|
-
*
|
|
39
|
-
* @param {object} wrappedArgs - Object containing the inner window.
|
|
40
|
-
* @param {Window} wrappedArgs.innerWindow - Window inside the browser interface.
|
|
41
|
-
* @return {string} Combined internal styles as a string.
|
|
42
|
-
*/
|
|
43
|
-
static innerGetInternalStyles({ innerWindow }: {
|
|
44
|
-
innerWindow: any;
|
|
45
|
-
}): string;
|
|
46
|
-
/**
|
|
47
|
-
* Given a set of CSS selectors (as object keys), along with "simplified" versions
|
|
48
|
-
* for easy querySelector calling (values), return an array of selectors which match
|
|
49
|
-
* _any_ element on the page.
|
|
50
|
-
*
|
|
51
|
-
* @param {object} wrappedArgs - Object containing the inner window and arguments.
|
|
52
|
-
* @param {Window} wrappedArgs.innerWindow - Window inside the browser interface.
|
|
53
|
-
* @param {Object[]} wrappedArgs.args - Array of arguments.
|
|
54
|
-
* {Object} wrappedArgs.args[selectors] - Map containing selectors (object keys), and simplified versions for easy matching (values).
|
|
55
|
-
* @return {string[]} Array of selectors matching above-the-fold elements.
|
|
56
|
-
*/
|
|
57
|
-
static innerFindMatchingSelectors({ innerWindow, args: [selectors] }: {
|
|
58
|
-
innerWindow: any;
|
|
59
|
-
args: [any];
|
|
60
|
-
}): string[];
|
|
61
|
-
/**
|
|
62
|
-
* Given a set of CSS selectors (as object keys), along with "simplified" versions
|
|
63
|
-
* for easy querySelector calling (values), return an array of selectors which match
|
|
64
|
-
* any above-the-fold element on the page.
|
|
65
|
-
*
|
|
66
|
-
* @param {object} wrappedArgs - Object containing the inner window and arguments.
|
|
67
|
-
* @param {Window} wrappedArgs.innerWindow - Window inside the browser interface.
|
|
68
|
-
* @param {Object[]} wrappedArgs.args - Array of arguments.
|
|
69
|
-
* {Object} wrappedArgs.args[selectors] - Map containing selectors (object keys), and simplified versions for easy matching (values).
|
|
70
|
-
* {string[]} wrappedArgs.args[pageSelectors] - String array containing selectors that appear anywhere on this page (as returned by innerFindMatchingSelectors) - should be a subset of keys in selectors.
|
|
71
|
-
* @return {string[]} Array of selectors matching above-the-fold elements.
|
|
72
|
-
*/
|
|
73
|
-
static innerFindAboveFoldSelectors({ innerWindow, args: [selectors, pageSelectors], }: {
|
|
74
|
-
innerWindow: any;
|
|
75
|
-
args: [any, any];
|
|
76
|
-
}): string[];
|
|
77
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
export class BrowserInterface {
|
|
2
|
-
constructor() {
|
|
3
|
-
this.urlErrors = {};
|
|
4
|
-
}
|
|
5
|
-
trackUrlError(url, error) {
|
|
6
|
-
this.urlErrors[url] = error;
|
|
7
|
-
}
|
|
8
|
-
filterValidUrls(urls) {
|
|
9
|
-
return urls.filter(url => !this.urlErrors[url]);
|
|
10
|
-
}
|
|
11
|
-
async runInPage(_pageUrl, _viewport, _method, ..._args) {
|
|
12
|
-
throw new Error('Undefined interface method: BrowserInterface.runInPage()');
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Context-specific wrapper for fetch; uses window.fetch in browsers, or a
|
|
16
|
-
* node library when using Puppeteer.
|
|
17
|
-
*
|
|
18
|
-
* @param {string} _url - The URL to fetch
|
|
19
|
-
* @param {FetchOptions} _options - Fetch options
|
|
20
|
-
* @param {'css' | 'html'} _role - Role of the fetch operation
|
|
21
|
-
*/
|
|
22
|
-
async fetch(_url, _options, _role) {
|
|
23
|
-
throw new Error('Undefined interface method: BrowserInterface.fetch()');
|
|
24
|
-
}
|
|
25
|
-
async cleanup() {
|
|
26
|
-
// No-op.
|
|
27
|
-
}
|
|
28
|
-
async getCssIncludes(pageUrl) {
|
|
29
|
-
return await this.runInPage(pageUrl, null, BrowserInterface.innerGetCssIncludes);
|
|
30
|
-
}
|
|
31
|
-
static innerGetCssIncludes({ innerWindow }) {
|
|
32
|
-
innerWindow = null === innerWindow ? window : innerWindow;
|
|
33
|
-
return [...innerWindow.document.getElementsByTagName('link')]
|
|
34
|
-
.filter(link => link.rel === 'stylesheet')
|
|
35
|
-
.reduce((set, link) => {
|
|
36
|
-
set[link.href] = {
|
|
37
|
-
media: link.media || null,
|
|
38
|
-
};
|
|
39
|
-
return set;
|
|
40
|
-
}, {});
|
|
41
|
-
}
|
|
42
|
-
async getInternalStyles(pageUrl) {
|
|
43
|
-
return await this.runInPage(pageUrl, null, BrowserInterface.innerGetInternalStyles);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Get all internal styles as a combined string from the window.
|
|
47
|
-
*
|
|
48
|
-
* @param {object} wrappedArgs - Object containing the inner window.
|
|
49
|
-
* @param {Window} wrappedArgs.innerWindow - Window inside the browser interface.
|
|
50
|
-
* @return {string} Combined internal styles as a string.
|
|
51
|
-
*/
|
|
52
|
-
static innerGetInternalStyles({ innerWindow }) {
|
|
53
|
-
innerWindow = null === innerWindow ? window : innerWindow;
|
|
54
|
-
const styleElements = Array.from(innerWindow.document.getElementsByTagName('style'));
|
|
55
|
-
return styleElements.reduce((styles, style) => {
|
|
56
|
-
styles += style.innerText;
|
|
57
|
-
return styles;
|
|
58
|
-
}, '');
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Given a set of CSS selectors (as object keys), along with "simplified" versions
|
|
62
|
-
* for easy querySelector calling (values), return an array of selectors which match
|
|
63
|
-
* _any_ element on the page.
|
|
64
|
-
*
|
|
65
|
-
* @param {object} wrappedArgs - Object containing the inner window and arguments.
|
|
66
|
-
* @param {Window} wrappedArgs.innerWindow - Window inside the browser interface.
|
|
67
|
-
* @param {Object[]} wrappedArgs.args - Array of arguments.
|
|
68
|
-
* {Object} wrappedArgs.args[selectors] - Map containing selectors (object keys), and simplified versions for easy matching (values).
|
|
69
|
-
* @return {string[]} Array of selectors matching above-the-fold elements.
|
|
70
|
-
*/
|
|
71
|
-
static innerFindMatchingSelectors({ innerWindow, args: [selectors] }) {
|
|
72
|
-
innerWindow = null === innerWindow ? window : innerWindow;
|
|
73
|
-
return Object.keys(selectors).filter(selector => {
|
|
74
|
-
try {
|
|
75
|
-
return !!innerWindow.document.querySelector(selectors[selector]);
|
|
76
|
-
}
|
|
77
|
-
catch (err) {
|
|
78
|
-
// Ignore invalid selectors.
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Given a set of CSS selectors (as object keys), along with "simplified" versions
|
|
85
|
-
* for easy querySelector calling (values), return an array of selectors which match
|
|
86
|
-
* any above-the-fold element on the page.
|
|
87
|
-
*
|
|
88
|
-
* @param {object} wrappedArgs - Object containing the inner window and arguments.
|
|
89
|
-
* @param {Window} wrappedArgs.innerWindow - Window inside the browser interface.
|
|
90
|
-
* @param {Object[]} wrappedArgs.args - Array of arguments.
|
|
91
|
-
* {Object} wrappedArgs.args[selectors] - Map containing selectors (object keys), and simplified versions for easy matching (values).
|
|
92
|
-
* {string[]} wrappedArgs.args[pageSelectors] - String array containing selectors that appear anywhere on this page (as returned by innerFindMatchingSelectors) - should be a subset of keys in selectors.
|
|
93
|
-
* @return {string[]} Array of selectors matching above-the-fold elements.
|
|
94
|
-
*/
|
|
95
|
-
static innerFindAboveFoldSelectors({ innerWindow, args: [selectors, pageSelectors], }) {
|
|
96
|
-
/**
|
|
97
|
-
* Inner helper function used inside browser / iframe to check if the given
|
|
98
|
-
* element is "above the fold".
|
|
99
|
-
*
|
|
100
|
-
* @param {HTMLElement} element - Element to check.
|
|
101
|
-
*/
|
|
102
|
-
innerWindow = null === innerWindow ? window : innerWindow;
|
|
103
|
-
const isAboveFold = element => {
|
|
104
|
-
const originalClearStyle = element.style.clear || '';
|
|
105
|
-
element.style.clear = 'none';
|
|
106
|
-
const rect = element.getBoundingClientRect();
|
|
107
|
-
element.style.clear = originalClearStyle;
|
|
108
|
-
return rect.top < innerWindow.innerHeight;
|
|
109
|
-
};
|
|
110
|
-
return pageSelectors.filter(s => {
|
|
111
|
-
if ('*' === selectors[s]) {
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
const matches = innerWindow.document.querySelectorAll(selectors[s]);
|
|
115
|
-
for (const match of matches) {
|
|
116
|
-
if (isAboveFold(match)) {
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return false;
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
//# sourceMappingURL=browser-interface.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"browser-interface.js","sourceRoot":"","sources":["../src/browser-interface.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { BrowserInterface } from './browser-interface.js';
|
|
2
|
-
import { StyleAST } from './style-ast.js';
|
|
3
|
-
import { FilterSpec } from './types.js';
|
|
4
|
-
type CSSFile = {
|
|
5
|
-
css: string;
|
|
6
|
-
ast: StyleAST;
|
|
7
|
-
pages: string[];
|
|
8
|
-
urls: string[];
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Represents a set of CSS files found on one or more HTML page. Automatically de-duplicates
|
|
12
|
-
* CSS files by URL and by content, and parses each into an Abstract Syntax Tree. Also tracks
|
|
13
|
-
* all errors that occur while loading or parsing CSS.
|
|
14
|
-
*/
|
|
15
|
-
export declare class CSSFileSet {
|
|
16
|
-
private browserInterface;
|
|
17
|
-
private knownUrls;
|
|
18
|
-
private cssFiles;
|
|
19
|
-
private errors;
|
|
20
|
-
private internalStyles;
|
|
21
|
-
constructor(browserInterface: BrowserInterface);
|
|
22
|
-
/**
|
|
23
|
-
* Add a set of CSS URLs from an HTML page to this set.
|
|
24
|
-
*
|
|
25
|
-
* @param {string} page - URL of the page the CSS URLs were found on.
|
|
26
|
-
* @param {object} cssIncludes - Included CSS Files. Keyed by URL.
|
|
27
|
-
*/
|
|
28
|
-
addMultiple(page: string, cssIncludes: {
|
|
29
|
-
[url: string]: {
|
|
30
|
-
media: string;
|
|
31
|
-
};
|
|
32
|
-
}): Promise<void>;
|
|
33
|
-
addInternalStyles(page: string, internalStyles: string): Promise<void>;
|
|
34
|
-
/**
|
|
35
|
-
* Add a CSS URL from an HTML page to this set.
|
|
36
|
-
*
|
|
37
|
-
* @param {string} page - URL of the page the CSS URL was found on.
|
|
38
|
-
* @param {string} cssUrl - The CSS file URL.
|
|
39
|
-
* @param {object} settings - Additional settings for the CSS file.
|
|
40
|
-
*/
|
|
41
|
-
add(page: string, cssUrl: string, settings?: {
|
|
42
|
-
[url: string]: string;
|
|
43
|
-
}): Promise<void>;
|
|
44
|
-
/**
|
|
45
|
-
* Collates an object describing the selectors found in the CSS files in this set, and which
|
|
46
|
-
* HTML page URLs include them (via CSS files)
|
|
47
|
-
*
|
|
48
|
-
* @return {object} - An object with selector text keys, each containing a Set of page URLs (strings)
|
|
49
|
-
*/
|
|
50
|
-
collateSelectorPages(): {
|
|
51
|
-
[selector: string]: Set<string>;
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* Applies filters to the properties or atRules in each AST in this set of CSS files.
|
|
55
|
-
* Mutates each AST in-place.
|
|
56
|
-
*
|
|
57
|
-
* @param {FilterSpec} filters - Object containing property and atRule filter functions.
|
|
58
|
-
*/
|
|
59
|
-
applyFilters(filters: FilterSpec): void;
|
|
60
|
-
/**
|
|
61
|
-
* Returns a new AST which is pruned appropriately for the specified contentWindow, and the
|
|
62
|
-
* set of selectors that are worth keeping. (i.e.: appear above the fold).
|
|
63
|
-
*
|
|
64
|
-
* @param {Set<string>} usefulSelectors - Set of selectors to keep.
|
|
65
|
-
* @return {StyleAST[]} Array of pruned StyleAST objects.
|
|
66
|
-
*/
|
|
67
|
-
prunedAsts(usefulSelectors: Set<string>): StyleAST[];
|
|
68
|
-
/**
|
|
69
|
-
* Internal method: Store the specified css found at the cssUrl for an HTML page,
|
|
70
|
-
* de-duplicating CSS files by content along the way.
|
|
71
|
-
*
|
|
72
|
-
* @param {string} page - URL of HTML page this CSS file was found on.
|
|
73
|
-
* @param {string} cssUrl - URL of the CSS file.
|
|
74
|
-
* @param {string} css - Content of the CSS File.
|
|
75
|
-
*/
|
|
76
|
-
storeCss(page: string, cssUrl: string, css: string): void;
|
|
77
|
-
/**
|
|
78
|
-
* Internal method: Add an extra reference to a previously known CSS file found either
|
|
79
|
-
* on a new HTML page, or at a new URL.
|
|
80
|
-
*
|
|
81
|
-
* @param {string} page - URL of the page this CSS file was found on.
|
|
82
|
-
* @param {string} cssUrl - URL of the CSS File.
|
|
83
|
-
* @param {object} matchingFile - Internal CSS File object.
|
|
84
|
-
*/
|
|
85
|
-
addExtraReference(page: string, cssUrl: string, matchingFile: CSSFile): void;
|
|
86
|
-
/**
|
|
87
|
-
* Stores an error that occurred while fetching or parsing CSS at the given URL.
|
|
88
|
-
*
|
|
89
|
-
* @param {string} url - CSS URL that failed to fetch or parse.
|
|
90
|
-
* @param {Error} err - Error object describing the problem.
|
|
91
|
-
*/
|
|
92
|
-
storeError(url: string, err: Error): void;
|
|
93
|
-
/**
|
|
94
|
-
* Returns a list of errors that occurred while fetching or parsing these CSS files.
|
|
95
|
-
*
|
|
96
|
-
* @return {Error[]} - List of errors that occurred.
|
|
97
|
-
*/
|
|
98
|
-
getErrors(): Error[];
|
|
99
|
-
}
|
|
100
|
-
export {};
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import { HttpError, UnknownError, UrlError } from './errors.js';
|
|
2
|
-
import { StyleAST } from './style-ast.js';
|
|
3
|
-
// Maximum number of iterations when pruning unused variables.
|
|
4
|
-
const maxVarPruneIterations = 10;
|
|
5
|
-
/**
|
|
6
|
-
* Represents a set of CSS files found on one or more HTML page. Automatically de-duplicates
|
|
7
|
-
* CSS files by URL and by content, and parses each into an Abstract Syntax Tree. Also tracks
|
|
8
|
-
* all errors that occur while loading or parsing CSS.
|
|
9
|
-
*/
|
|
10
|
-
export class CSSFileSet {
|
|
11
|
-
constructor(browserInterface) {
|
|
12
|
-
this.browserInterface = browserInterface;
|
|
13
|
-
this.internalStyles = {};
|
|
14
|
-
this.knownUrls = {};
|
|
15
|
-
this.cssFiles = [];
|
|
16
|
-
this.errors = [];
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Add a set of CSS URLs from an HTML page to this set.
|
|
20
|
-
*
|
|
21
|
-
* @param {string} page - URL of the page the CSS URLs were found on.
|
|
22
|
-
* @param {object} cssIncludes - Included CSS Files. Keyed by URL.
|
|
23
|
-
*/
|
|
24
|
-
async addMultiple(page, cssIncludes) {
|
|
25
|
-
await Promise.all(Object.keys(cssIncludes).map(url => this.add(page, url, cssIncludes[url])));
|
|
26
|
-
}
|
|
27
|
-
async addInternalStyles(page, internalStyles) {
|
|
28
|
-
this.internalStyles[page] = StyleAST.parse(internalStyles);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Add a CSS URL from an HTML page to this set.
|
|
32
|
-
*
|
|
33
|
-
* @param {string} page - URL of the page the CSS URL was found on.
|
|
34
|
-
* @param {string} cssUrl - The CSS file URL.
|
|
35
|
-
* @param {object} settings - Additional settings for the CSS file.
|
|
36
|
-
*/
|
|
37
|
-
async add(page, cssUrl, settings = {}) {
|
|
38
|
-
// Add by reference if we already know this file.
|
|
39
|
-
if (Object.prototype.hasOwnProperty.call(this.knownUrls, cssUrl)) {
|
|
40
|
-
if (this.knownUrls[cssUrl] instanceof Error) {
|
|
41
|
-
// We already know this URL failed. Bail early.
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
this.addExtraReference(page, cssUrl, this.knownUrls[cssUrl]);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
// Try to load this URL.
|
|
48
|
-
try {
|
|
49
|
-
const response = await this.browserInterface.fetch(cssUrl, {}, 'css');
|
|
50
|
-
if (!response.ok) {
|
|
51
|
-
throw new HttpError({ code: response.status, url: cssUrl });
|
|
52
|
-
}
|
|
53
|
-
let css = await response.text();
|
|
54
|
-
// If there is an implied media query from the css's <link> tag, wrap the CSS in it.
|
|
55
|
-
if (settings.media) {
|
|
56
|
-
css = '@media ' + settings.media + ' {\n' + css + '\n}';
|
|
57
|
-
}
|
|
58
|
-
this.storeCss(page, cssUrl, css);
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
let wrappedError = err;
|
|
62
|
-
// Wrap any unfamiliar fetch errors in an unknown error.
|
|
63
|
-
if (!(err instanceof UrlError)) {
|
|
64
|
-
wrappedError = new UnknownError({
|
|
65
|
-
url: cssUrl,
|
|
66
|
-
message: err.message,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
this.storeError(cssUrl, wrappedError);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Collates an object describing the selectors found in the CSS files in this set, and which
|
|
74
|
-
* HTML page URLs include them (via CSS files)
|
|
75
|
-
*
|
|
76
|
-
* @return {object} - An object with selector text keys, each containing a Set of page URLs (strings)
|
|
77
|
-
*/
|
|
78
|
-
collateSelectorPages() {
|
|
79
|
-
const selectors = {};
|
|
80
|
-
for (const file of this.cssFiles) {
|
|
81
|
-
file.ast.forEachSelector(selector => {
|
|
82
|
-
if (!selectors[selector]) {
|
|
83
|
-
selectors[selector] = new Set();
|
|
84
|
-
}
|
|
85
|
-
file.pages.forEach(pageUrl => selectors[selector].add(pageUrl));
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
return selectors;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Applies filters to the properties or atRules in each AST in this set of CSS files.
|
|
92
|
-
* Mutates each AST in-place.
|
|
93
|
-
*
|
|
94
|
-
* @param {FilterSpec} filters - Object containing property and atRule filter functions.
|
|
95
|
-
*/
|
|
96
|
-
applyFilters(filters) {
|
|
97
|
-
for (const file of this.cssFiles) {
|
|
98
|
-
file.ast.applyFilters(filters);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Returns a new AST which is pruned appropriately for the specified contentWindow, and the
|
|
103
|
-
* set of selectors that are worth keeping. (i.e.: appear above the fold).
|
|
104
|
-
*
|
|
105
|
-
* @param {Set<string>} usefulSelectors - Set of selectors to keep.
|
|
106
|
-
* @return {StyleAST[]} Array of pruned StyleAST objects.
|
|
107
|
-
*/
|
|
108
|
-
prunedAsts(usefulSelectors) {
|
|
109
|
-
// Perform basic pruning.
|
|
110
|
-
let asts = this.cssFiles.map(file => {
|
|
111
|
-
return file.ast.pruned(usefulSelectors);
|
|
112
|
-
});
|
|
113
|
-
const internallyUsedVariables = new Set();
|
|
114
|
-
Object.values(this.internalStyles).reduce((set, ast) => {
|
|
115
|
-
ast.getUsedVariables().forEach(v => set.add(v));
|
|
116
|
-
return set;
|
|
117
|
-
}, internallyUsedVariables);
|
|
118
|
-
// Repeatedly prune unused variables (up to maxVarPruneIterations), to catch vars which are
|
|
119
|
-
// only used to define other vars which aren't used.
|
|
120
|
-
let prevUsedVariables;
|
|
121
|
-
for (let i = 0; i < maxVarPruneIterations; i++) {
|
|
122
|
-
// Gather the set of used variables.
|
|
123
|
-
const usedVariables = asts.reduce((set, ast) => {
|
|
124
|
-
ast.getUsedVariables().forEach(v => set.add(v));
|
|
125
|
-
return set;
|
|
126
|
-
}, new Set());
|
|
127
|
-
// If the number of used vars hasn't changed since last iteration, stop early.
|
|
128
|
-
if (prevUsedVariables && prevUsedVariables.size === usedVariables.size) {
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
// Prune unused variables, keep a sum of pruned variables.
|
|
132
|
-
const prunedCount = asts.reduce((sum, ast) => {
|
|
133
|
-
sum += ast.pruneUnusedVariables(new Set([...usedVariables, ...internallyUsedVariables]));
|
|
134
|
-
return sum;
|
|
135
|
-
}, 0);
|
|
136
|
-
// If no variables were pruned this iteration, stop early.
|
|
137
|
-
if (prunedCount === 0) {
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
prevUsedVariables = usedVariables;
|
|
141
|
-
}
|
|
142
|
-
// Find all fonts used across all ASTs, and prune all that are not referenced.
|
|
143
|
-
const fontWhitelist = asts.reduce((set, ast) => {
|
|
144
|
-
ast.getUsedFontFamilies().forEach(font => set.add(font));
|
|
145
|
-
return set;
|
|
146
|
-
}, new Set());
|
|
147
|
-
// Remove any fonts that aren't used above the fold.
|
|
148
|
-
asts.forEach(ast => ast.pruneNonCriticalFonts(fontWhitelist));
|
|
149
|
-
// Throw away any ASTs without rules.
|
|
150
|
-
asts = asts.filter(ast => ast.ruleCount() > 0);
|
|
151
|
-
return asts;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Internal method: Store the specified css found at the cssUrl for an HTML page,
|
|
155
|
-
* de-duplicating CSS files by content along the way.
|
|
156
|
-
*
|
|
157
|
-
* @param {string} page - URL of HTML page this CSS file was found on.
|
|
158
|
-
* @param {string} cssUrl - URL of the CSS file.
|
|
159
|
-
* @param {string} css - Content of the CSS File.
|
|
160
|
-
*/
|
|
161
|
-
storeCss(page, cssUrl, css) {
|
|
162
|
-
// De-duplicate css contents in case cache busters in URLs or WAFs, etc confound URL de-duplication.
|
|
163
|
-
const matchingFile = this.cssFiles.find(file => file.css === css);
|
|
164
|
-
if (matchingFile) {
|
|
165
|
-
this.addExtraReference(page, cssUrl, matchingFile);
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
// Parse the CSS into an AST.
|
|
169
|
-
const ast = StyleAST.parse(css);
|
|
170
|
-
// Make sure relative URLs in the AST are absolute.
|
|
171
|
-
ast.absolutifyUrls(cssUrl);
|
|
172
|
-
const file = { css, ast, pages: [page], urls: [cssUrl] };
|
|
173
|
-
this.knownUrls[cssUrl] = file;
|
|
174
|
-
this.cssFiles.push(file);
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Internal method: Add an extra reference to a previously known CSS file found either
|
|
178
|
-
* on a new HTML page, or at a new URL.
|
|
179
|
-
*
|
|
180
|
-
* @param {string} page - URL of the page this CSS file was found on.
|
|
181
|
-
* @param {string} cssUrl - URL of the CSS File.
|
|
182
|
-
* @param {object} matchingFile - Internal CSS File object.
|
|
183
|
-
*/
|
|
184
|
-
addExtraReference(page, cssUrl, matchingFile) {
|
|
185
|
-
this.knownUrls[cssUrl] = matchingFile;
|
|
186
|
-
matchingFile.pages.push(page);
|
|
187
|
-
if (!matchingFile.urls.includes(cssUrl)) {
|
|
188
|
-
matchingFile.urls.push(cssUrl);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Stores an error that occurred while fetching or parsing CSS at the given URL.
|
|
193
|
-
*
|
|
194
|
-
* @param {string} url - CSS URL that failed to fetch or parse.
|
|
195
|
-
* @param {Error} err - Error object describing the problem.
|
|
196
|
-
*/
|
|
197
|
-
storeError(url, err) {
|
|
198
|
-
this.knownUrls[url] = err;
|
|
199
|
-
this.errors.push(err);
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Returns a list of errors that occurred while fetching or parsing these CSS files.
|
|
203
|
-
*
|
|
204
|
-
* @return {Error[]} - List of errors that occurred.
|
|
205
|
-
*/
|
|
206
|
-
getErrors() {
|
|
207
|
-
return this.errors;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
//# sourceMappingURL=css-file-set.js.map
|