1
1
/* global document */
2
-
3
2
const puppeteer = require ( 'puppeteer' )
4
- const crypto = require ( 'crypto' )
5
-
6
- function hashString ( str ) {
7
- return crypto . createHash ( 'md5' ) . update ( str , 'utf8' ) . digest ( 'hex' )
8
- }
9
3
10
4
function InvalidUrlError ( { url, statusCode, statusText} ) {
11
5
this . name = 'InvalidUrlError'
@@ -17,15 +11,14 @@ InvalidUrlError.prototype = Error.prototype
17
11
/**
18
12
* @param {string } url URL to get CSS from
19
13
* @param {string } waitUntil https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#pagegotourl-options
14
+ * @returns {string } All CSS that was found
20
15
*/
21
16
module . exports = async ( url , { waitUntil = 'networkidle0' } = { } ) => {
22
17
// Setup a browser instance
23
18
const browser = await puppeteer . launch ( )
24
19
25
20
// Create a new page and navigate to it
26
21
const page = await browser . newPage ( )
27
-
28
- // Start CSS coverage. This is the meat and bones of this module
29
22
await page . coverage . startCSSCoverage ( )
30
23
const response = await page . goto ( url , { waitUntil} )
31
24
@@ -43,22 +36,22 @@ module.exports = async (url, {waitUntil = 'networkidle0'} = {}) => {
43
36
)
44
37
}
45
38
46
- // Coverage contains a lot of <style> and <link> CSS,
47
- // but not all...
48
39
const coverage = await page . coverage . stopCSSCoverage ( )
49
40
50
41
// Get all CSS generated with the CSSStyleSheet API
51
42
// This is primarily for CSS-in-JS solutions
52
43
// See: https://developer.mozilla.org/en-US/docs/Web/API/CSSRule/cssText
53
44
const styleSheetsApiCss = await page . evaluate ( ( ) => {
54
45
return [ ...document . styleSheets ]
46
+ // Only take the stylesheets without href (BUT WHY)
55
47
. filter ( stylesheet => stylesheet . href === null )
56
- . map ( stylesheet =>
57
- [ ...stylesheet . cssRules ]
58
- . map ( cssStyleRule => cssStyleRule . cssText )
59
- . join ( '\n' )
60
- )
61
- . join ( '\n' )
48
+ . map ( stylesheet => {
49
+ return {
50
+ type : stylesheet . ownerNode . tagName . toLowerCase ( ) ,
51
+ href : stylesheet . href || document . location . href ,
52
+ css : [ ...stylesheet . cssRules ] . map ( ( { cssText} ) => cssText ) . join ( '\n' )
53
+ }
54
+ } )
62
55
} )
63
56
64
57
// Get all inline styles: <element style="">
@@ -71,38 +64,36 @@ module.exports = async (url, {waitUntil = 'networkidle0'} = {}) => {
71
64
// <h1 style="color: red;">Text</h1>
72
65
//
73
66
// CSSRule:
74
- // [x-inline-style-237a7d] { color: red; }
75
- // ^^^^^^
67
+ // [x-extract-css-inline-style] { color: red; }
76
68
//
77
- // The 6-digit hash is based on the actual CSS, so it's not
78
- // necessarily unique!
79
69
const inlineCssRules = await page . evaluate ( ( ) => {
80
70
return [ ...document . querySelectorAll ( '[style]' ) ]
81
71
. map ( element => element . getAttribute ( 'style' ) )
72
+ // Filter out empty style="" attributes
82
73
. filter ( Boolean )
83
74
} )
84
75
const inlineCss = inlineCssRules
85
- . map ( rule => {
86
- const hash = hashString ( rule ) . slice ( - 6 )
87
- return `[x-inline-style-${ hash } ] { ${ rule } }`
88
- } )
89
- . join ( '\n' )
76
+ . map ( rule => `[x-extract-css-inline-style] { ${ rule } }` )
77
+ . map ( css => ( { type : 'inline' , href : url , css} ) )
90
78
91
- await browser . close ( )
92
-
93
- // Turn the coverage Array into a single string of CSS
94
- const coverageCss = coverage
79
+ const links = coverage
95
80
// Filter out the <style> tags that were found in the coverage
96
81
// report since we've conducted our own search for them.
97
82
// A coverage CSS item with the same url as the url of the page
98
83
// we requested is an indication that this was a <style> tag
99
- . filter ( styles => styles . url !== url )
100
- // The `text` property contains the actual CSS
101
- . map ( ( { text} ) => text )
102
- . join ( '\n' )
84
+ . filter ( entry => entry . url !== url )
85
+ . map ( entry => ( {
86
+ href : entry . url ,
87
+ css : entry . text ,
88
+ type : 'link-or-import'
89
+ } ) )
90
+
91
+ await browser . close ( )
103
92
104
- const css = [ styleSheetsApiCss , coverageCss , inlineCss ]
105
- . filter ( Boolean )
93
+ const css = links
94
+ . concat ( styleSheetsApiCss )
95
+ . concat ( inlineCss )
96
+ . map ( ( { css} ) => css )
106
97
. join ( '\n' )
107
98
108
99
return Promise . resolve ( css )
0 commit comments