Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Extract the minimal CSS used in a set of URLs with puppeteer

License

NotificationsYou must be signed in to change notification settings

peterbe/minimalcss

Repository files navigation

Build statusNPM versionstyled with prettierRenovate enabled

A Node library to extract the minimal CSS used in a set of URLs with puppeteer.Used to find what minimal CSS is needed to render on first load, even withdocument.onload executed.

This minimal CSS is also known ascritical path CSSand ultimately a web performance technique to make web pages load fasterat initial load.

What does it do

You supply a list of URLs that it opens (one at a time) and for each pageit downloads all external CSS files (e.g.<link rel="stylesheet" href="bootstrap.min.css">) and uses the DOM anddocument.querySelector to investigate which selectors, in the CSS, areactually in the DOM. That minimal payload of CSS is all you need to loadthe URLs styled without having to make it block on CSS.

Under the hood it relies on the excellentpuppeteer library which usesthe Headless Chome Node API. This means it runs (at the time of writing)Chrome 62 and this library is maintained by the Google Chrome team.

The CSS to analyze (and hopefully minimize) is downloaded automatically justlike a browser opens and downloads CSS as mentioned in the DOM as<link>tags.

The CSS is parsed byCSSTree and theminification and compression is done withCSSO.An AST of each CSS payload is sent into the Headless Chrome page evaluationtogether with a callback that compares with the DOM and then each minimal CSSpayload is concatenated into one big string which then CSSO compresses intoone "merged" and minified CSS payload.

Usage

Install:

yarn add minimalcss --dev

You can install it globally if you like:

yarn global add minimalcss
npm install [--save-dev|--global] minimalcss

Now you can run it:

./node_modules/.bin/minimalcss https://example.com/ https://example.com/aboutus> minimal.min.css

Prior art

minimalcss isn't the first library to perform this task. What's unique andspecial aboutminimalcss is that it uses the Chrome Headless browser.

  • penthouse -usespuppeteer (since version 1.0) andCSSTree.Supports only 1 URL at a time and can't you have to first save the CSS filesit should process.

  • critical - usespenthouse(see above) with its "flaws" meaning you can only do 1 URL (or HTML string)and you have to prepare the CSS files too.

  • UnCSS - usesjsdomto render and execute JavaScript. Supports supplying multiple URLs but stillrequires to manually supply the CSS files to process.

  • mincss - Python project that useslxml.html to analyze the HTML statically(by doing aGET of the URL as if done by a server). I.e.it can't load the HTML as a real browser would and thus does not support aDOM with possible JavaScript mutations on load.It can optionally usePhantomJS to extract the HTML.

Killer features

  • You don't need to specify where the CSS is. It gets downloaded and parsedautomatically.

  • It usespuppeteer andCSSTree which are both high qualityprojects that are solid and well tested.

  • The CSS selectors downloaded is compared to the DOM beforeand afterJavaScript code has changed the DOM. That means you can extract thecritical CSS needed to display properly before the JavaScript has kicked in.

  • Ability to analyze the remaining CSS selectors to see which keyframeanimations that they use and use this to delete keyframe definitionsthat are no longer needed.

  • You can specify aviewport,which might cause the page to render slightly different. It does notcreate the minimal CSSonly on DOM that is visible though.

  • If the CSS contains@font-face { ... } rules whose name is neverused in any remaining CSS selector, the wholefont-face block is removed.

Help needed

Let's make this a thriving community project!

Help needed with features, tooling, and much testing in real web performanceoptimization work.

API

constminimalcss=require('minimalcss');

Get versionminimalcss.version

Just prints out the current version.

Run a minimizationminimalcss.run(options)

Returns a promise. The promise returns an object containing, amongstother things, the minified minimal CSS as a string.For example:

minimalcss.minimize({url:'https://example.com/'}).then(result=>{console.log('OUTPUT',result.finalCss.length,result.finalCss);}).catch(error=>{console.error(`Failed the minimize CSS:${error}`);});

Thatresult object that is returned by theminimize function contains:

  • finalCss - the minified minimal CSS as a string.
  • stylesheetContents - an object of stylesheet URLs as keys and theircontent as text.

Optionally, you can supply a list of URLs like this:

minimalcss.minimize({urls:['https://example.com/page1','https://example.com/page2']})...

andminimalcss will try to merge the minimal critical CSS across all pages.But we aware that this can be "dangerous" because of the inherit order of CSS.

API Options

Callingminimalcss.run(options) takes an object whose only mandatorykey isurls orurl. Other optional options are:

  • debug - all console logging during page rendering are included in thestdout. Also, any malformed selector that cause errors indocument.querySelectorwill be raised as new errors.
  • skippable - function which takesrequestas an argument and returns boolean. If it returns true then given requestwill be aborted (skipped). Can be used to block requests to Google Analyticsetc.
  • loadimages - If set totrue, images will actually load.
  • withoutjavascript - If set tofalse it willskip loading the page firstwithout JavaScript. By defaultminimalcss will evaluate the DOM as plain ascan be, and then with JavaScript enabledand waiting for network activityto be idle.
  • disableJavaScript - By default JavaScript is enabled. If set totrue it will ignorewithoutjavascript option and loading the page only one time without JavaScript.
  • browser - Instance of aBrowser, which will be used instead of launching another one.
  • userAgent - specific user agent to use (string)
  • viewport - viewport object as specified inpage.setViewport
  • puppeteerArgs - Args sent to puppeteer when launching.Listof strings for headless Chrome.
  • cssoOptions - CSSO compress functionoptions
  • timeout - Maximum navigation time in milliseconds, defaults to 30 seconds, pass 0 to disable timeout.
  • ignoreCSSErrors - By default, any CSS parsing error throws an error inminimalcss. If you know it's safe to ignore (for example, third-party CSS resources), set this totrue.
  • ignoreJSErrors - By default, any JavaScript error encountered by puppeteer
  • ignoreRequestErrors - When CSS files return 404 or another request errorminimalcss will ignore this instead of throwing an error.will be thrown byminimalcss. If you know it's safe to ignore errors (for example, onthird-party webpages), set this totrue.
  • styletags - If set totrue, on-page<style> tags are parsed along with external stylesheets. By default, only external stylesheets are parsed.
  • enableServiceWorkers - By default all Service Workers are disabled. This option enables them as is.
  • whitelist - Array of css selectors that should be left in final CSS. RegExp patterns are supported (e.g.['sidebar', icon-.*, .*-error]).

Warnings

Google Fonts

Suppose you have this in your HTML:

<linkhref="https://fonts.googleapis.com/css?family=Lato"rel="stylesheet">

then,minimalcss will consider this an external CSS stylesheet, load itand include it in the minimal CSS.

The problem is that Google Fonts will respond to that URL dynamically basedon the user agent. In other words a different CSS payload depending on who'sasking. So, the user agent whenminimalcss runs will be whateverpuppeteer uses and it might not be the best CSS for other user agents.So to avoid this predicament use theskippable option. On the command lineyou can do that like this:

./node_modules/.bin/minimalcss --skip fonts.googleapis.com https://example.com

With the API, you can do it like this:

minimalcss.minimize({url:'https://example.com',skippable:request=>{return!!request.url().match('fonts.googleapis.com');}}).then(result=>{    ...});

Multiple URLs

minimalcss can accept multiple URLs when figuring out the minimal CSS forall those URLs, combined. Butbe careful, this can be dangerous. Ifyou have one URL with this HTML:

<head><linkrel="stylesheet"href="base.css"><linkrel="stylesheet"href="specific.css"></head>

and another URL with...:

<head><linkrel="stylesheet"href="base.css"></head>

When combining these, it will optimize the CSS in this order:

  1. base.css
  2. specific.css
  3. base.css

But ifspecific.css was meant to override something inbase.css in thefirst URL, that might get undone whenbase.css becomes the last CSSto include.

See this issue for another good example why runningminimalcss across multiple URLs.

Aboutcheerio

Whenminimalcss evaluates each CSS selector to decide whether to keep itor not, some selectors might not be parseable. Possibly, the CSS employshacks for specific browsers thatcheerio doesn't support. Orthere might be CSS selectors that no browser or tool can understand(e.g a typo by the CSS author). If there's a problem parsing a CSS selector,the default is to swallow the exception and let the CSS selector stay.

Also by default, all these warnings are hidden. To see them use the--debugflag (ordebug API option). Then the CSS selector syntax errors areprinted onstderr.

About@font-face

minimalcss will remove any@font-face rules whose name is not mentionedin any of the CSS selectors. But be aware that you might have a@font-face { font-family: MyName; } in some/static/foo.css but separatelyyou might have an inline style sheet that looks like this:

<styletype="text/css">div.something {font-family: MyName; }</style>

In this case the@font-face { font-family: MyName; } would be removed eventhough it's mentioned from somewhere else.

About Blobs

If your document usesBlob to create injectable stylesheets into the DOM,minimalcss willnot be able to optimize that. It will be not beincluded in the final CSS.

Development

First thing to get started, once you've cloned the repo is to install allthe dependencies:

yarn

Testing

Testing is done withjest. At thebeginning of every test, a static file server is started onlocalhostand apuppeteer browser instance is created for every test.

To run the tests:

yarn jest

Best way to get into writing tests is to look at existing tests and copy.

Prettier

All code is expected to conform withPrettier accordingto the the.prettierrc file in the root of the project.

To check that all your code conforms, run:

yarn lintcheck

Use without a server

This blog postdemonstrates technique to useminimalcss when you don't yet have a server.Using thehttp-server package you can start a server right before you runand shut down as soon as you're done.

License

Copyright (c) 2017-2020Peter Bengtsson.See theLICENSE file for license rights and limitations (MIT).

About

Extract the minimal CSS used in a set of URLs with puppeteer

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors15


[8]ページ先頭

©2009-2025 Movatter.jp