|
1 |
| -const got = require('got') |
2 |
| -const chromium = require('chrome-aws-lambda') |
3 | 1 | const normalizeUrl = require('normalize-url')
|
4 | 2 | const isUrl = require('is-url')
|
5 | 3 | const LRU = require('lru-cache')
|
| 4 | +const {extractCss} = require('./_chromium') |
6 | 5 |
|
7 | 6 | const cssCache = new LRU({
|
8 | 7 | max: 500,
|
9 |
| - maxAge: 60 * 1000 |
| 8 | + maxAge: 60 * 1000 // 1 minute |
10 | 9 | })
|
11 | 10 |
|
12 |
| -const extractCss = async url => { |
13 |
| - const browser = await chromium.puppeteer.launch({ |
14 |
| - executablePath: await chromium.executablePath, |
15 |
| - args: chromium.args, |
16 |
| - headless: true |
17 |
| - }) |
18 |
| - |
19 |
| - const page = await browser.newPage() |
20 |
| - |
21 |
| - // Start CSS coverage. This is the meat and bones of this module |
22 |
| - await page.coverage.startCSSCoverage() |
23 |
| - |
24 |
| - const response = await page.goto(url, {waitUntil: 'networkidle2'}) |
25 |
| - |
26 |
| - // Make sure that we only try to extract CSS from valid pages. |
27 |
| - // Bail out if the response is an invalid request (400, 500) |
28 |
| - if (response.status() >= 400) { |
29 |
| - await browser.close() // Don't leave any resources behind |
30 |
| - |
31 |
| - return Promise.reject( |
32 |
| - new Error( |
33 |
| - `There was an error retrieving CSS from ${url}.\n\tHTTP status code: ${response.statusCode} (${response.statusText})` |
34 |
| - ) |
35 |
| - ) |
36 |
| - } |
37 |
| - |
38 |
| - // Coverage contains a lot of <style> and <link> CSS, |
39 |
| - // but not all... |
40 |
| - const coverage = await page.coverage.stopCSSCoverage() |
41 |
| - |
42 |
| - // Get all CSS generated with the CSSStyleSheet API |
43 |
| - // See: https://developer.mozilla.org/en-US/docs/Web/API/CSSRule/cssText |
44 |
| - const styleSheetsApiCss = await page.evaluate(() => { |
45 |
| - /* global document */ |
46 |
| - return [...document.styleSheets] |
47 |
| - .filter(stylesheet => stylesheet.href === null) |
48 |
| - .map(stylesheet => |
49 |
| - [...stylesheet.cssRules] |
50 |
| - .map(cssStyleRule => cssStyleRule.cssText) |
51 |
| - .join('') |
52 |
| - ) |
53 |
| - .join('') |
54 |
| - }) |
55 |
| - |
56 |
| - await browser.close() |
57 |
| - |
58 |
| - // Turn the coverage Array into a single string of CSS |
59 |
| - const coverageCss = coverage |
60 |
| - // Filter out the <style> tags that were found in the coverage |
61 |
| - // report since we've conducted our own search for them. |
62 |
| - // A coverage CSS item with the same url as the url of the page |
63 |
| - // we requested is an indication that this was a <style> tag |
64 |
| - .filter(styles => styles.url !== url) |
65 |
| - // The `text` property contains the actual CSS |
66 |
| - .map(({text}) => text) |
67 |
| - .join('') |
68 |
| - |
69 |
| - return Promise.resolve(styleSheetsApiCss + coverageCss) |
70 |
| -} |
71 |
| - |
72 | 11 | module.exports = async (req, res) => {
|
73 | 12 | const url = normalizeUrl(req.url.slice(1), {stripWWW: false})
|
74 | 13 |
|
75 | 14 | if (!isUrl(url)) {
|
76 | 15 | res.statusCode = 406
|
77 | 16 | res.setHeader('Content-Type', 'application/json')
|
| 17 | + |
78 | 18 | return res.end(
|
79 | 19 | JSON.stringify({
|
80 | 20 | message: 'The provided URL is not valid'
|
81 | 21 | })
|
82 | 22 | )
|
83 | 23 | }
|
84 | 24 |
|
| 25 | + res.setHeader('Content-Type', 'text/css') |
| 26 | + res.statusCode = 200 |
| 27 | + |
85 | 28 | if (cssCache.has(url)) {
|
86 |
| - res.setHeader('Content-Type', 'text/css') |
87 |
| - res.statusCode = 200 |
88 | 29 | return res.end(cssCache.get(url))
|
89 | 30 | }
|
90 | 31 |
|
91 | 32 | try {
|
92 |
| - const css = url.endsWith('.css') ? |
93 |
| - (await got(url)).body : |
94 |
| - await extractCss(url) |
95 |
| - |
96 |
| - res.setHeader('Content-Type', 'text/css') |
97 |
| - res.statusCode = 200 |
| 33 | + const css = await extractCss(url) |
98 | 34 | cssCache.set(url, css)
|
| 35 | + |
99 | 36 | return res.end(css)
|
100 | 37 | } catch (error) {
|
101 | 38 | res.statusCode = 500
|
102 | 39 | res.setHeader('Content-Type', 'application/json')
|
| 40 | + |
103 | 41 | return res.end(JSON.stringify(error))
|
104 | 42 | }
|
105 | 43 | }
|
0 commit comments