├── .gitignore ├── .nowignore ├── dev.js ├── now.json ├── package.json ├── index.js ├── readme.md └── public └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.nowignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | node_modules 4 | readme.md 5 | dev.js 6 | -------------------------------------------------------------------------------- /dev.js: -------------------------------------------------------------------------------- 1 | const http = require('http') 2 | const extractCssFromUrl = require('.') 3 | 4 | http.createServer(extractCssFromUrl).listen(1337, () => { 5 | console.log(`Server started at http://localhost:1337`) 6 | }) 7 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "public": true, 4 | "alias": "extract-css", 5 | "builds": [ 6 | { "src": "public/*", "use": "@now/static" }, 7 | { 8 | "src": "index.js", 9 | "use": "@now/node", 10 | "config": { "maxLambdaSize": "40mb" } 11 | } 12 | ], 13 | "routes": [ 14 | { "src": "/", "dest": "/public/index.html" }, 15 | { "src": "/(.+)", "dest": "/index.js" } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "extract-css", 3 | "version": "0.1.0", 4 | "description": "Get all the CSS from a page by passing a url. Uses Puppeteer to render the page with Chrome and traverse the DOM looking for link[rel=stylesheet] and style tags", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "xo", 8 | "dev": "nodemon dev.js" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "chrome-aws-lambda": "^1.12.0", 13 | "puppeteer-core": "^1.12.2" 14 | }, 15 | "devDependencies": { 16 | "nodemon": "^1.18.10", 17 | "prettier": "^1.16.4", 18 | "puppeteer": "^1.12.2", 19 | "xo": "^0.24.0" 20 | }, 21 | "xo": { 22 | "prettier": true 23 | }, 24 | "prettier": { 25 | "semi": false, 26 | "singleQuote": true, 27 | "useTabs": true, 28 | "bracketSpacing": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { ENV } = process.env 2 | const puppeteer = require(ENV && ENV === 'dev' ? 'puppeteer' : 'puppeteer-core') 3 | const chrome = require('chrome-aws-lambda') 4 | 5 | async function extractCssWithCoverageFromUrl(requestUrl) { 6 | // Setup a browser instance 7 | const browser = await puppeteer.launch({ 8 | args: chrome.args, 9 | executablePath: await chrome.executablePath, 10 | headless: true 11 | }) 12 | 13 | // Create a new page and navigate to it 14 | const page = await browser.newPage() 15 | await page.coverage.startCSSCoverage() 16 | await page.goto(requestUrl) 17 | const coverage = await page.coverage.stopCSSCoverage() 18 | 19 | // Close the browser to close the connection and free up resources 20 | await browser.close() 21 | 22 | // Turn the coverage into a usable format 23 | return coverage.map(css => css.text).join('') 24 | } 25 | 26 | module.exports = async (req, res) => { 27 | const url = req.url.slice(1) 28 | 29 | try { 30 | const css = await extractCssWithCoverageFromUrl(url) 31 | res.statusCode = 200 32 | res.setHeader('Content-Type', 'text/css') 33 | return res.end(css) 34 | } catch (error) { 35 | res.statusCode = 400 36 | res.setHeader('Content-Type', 'application/json') 37 | return res.end(JSON.stringify(error, null, 2)) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |
2 |

Extract CSS

3 |

Get all the CSS from a webpage.

4 |
5 | 6 | [![Platform: Now V2](https://img.shields.io/badge/platform-Now%20V2-50e3c2.svg)](https://zeit.co/now) 7 | 8 | ## The problem 9 | 10 | The folks from [CSS Stats](https://cssstats.com/) have created [get-css](https://github.com/cssstats/cssstats/tree/master/packages/get-css), a package to get all the CSS from a given webpage. One downside, however, is that it only works for server side rendered applications. 11 | 12 | ## The solution 13 | 14 | This package uses an actual browser under the hood to get all the CSS and exposes an HTTP endpoint that accepts a url to get the CSS from. 15 | 16 | ## Local testing 17 | 18 | I have no idea how local testing for Now is supposed to work, so I created a tiny HTTP server in `dev.js` that calls the actual function that gets deployed. 19 | Run `npm run dev` to run a local version of the function for local testing. 20 | 21 | ## Deployment 22 | 23 | Using [Now](https://zeit.co/now): `now`. 24 | 25 | ## Credits 26 | 27 | - This repo is pretty much an exact copy of [this example from Zeit](https://github.com/zeit/now-examples/tree/master/puppeteer-screenshot). 28 | - The idea to get all the CSS from a webpage comes from [CSS Stats](https://github.com/cssstats/cssstats) 29 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Extract CSS 7 | 37 | 38 | 39 |

Extract CSS

40 |

Get all the CSS from a single webpage.

41 | 42 |

Example request urls:

43 | 61 | 62 |

63 | Source code 64 | available on GitHub. 67 |

68 | 69 | 70 | --------------------------------------------------------------------------------