{"id":13447465,"url":"https://github.com/peterbe/minimalcss","last_synced_at":"2025-10-08T19:32:34.568Z","repository":{"id":40827499,"uuid":"101454232","full_name":"peterbe/minimalcss","owner":"peterbe","description":"Extract the minimal CSS used in a set of URLs with puppeteer","archived":false,"fork":false,"pushed_at":"2023-01-03T16:48:53.000Z","size":1839,"stargazers_count":356,"open_issues_count":43,"forks_count":33,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-08-09T10:53:48.789Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://minimalcss.app/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peterbe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-26T01:31:53.000Z","updated_at":"2025-08-07T03:04:44.000Z","dependencies_parsed_at":"2023-02-01T08:01:14.170Z","dependency_job_id":null,"html_url":"https://github.com/peterbe/minimalcss","commit_stats":null,"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/peterbe/minimalcss","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterbe%2Fminimalcss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterbe%2Fminimalcss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterbe%2Fminimalcss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterbe%2Fminimalcss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peterbe","download_url":"https://codeload.github.com/peterbe/minimalcss/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterbe%2Fminimalcss/sbom","scorecard":{"id":728703,"data":{"date":"2025-08-11","repo":{"name":"github.com/peterbe/minimalcss","commit":"3bc6e5d3c36620ead93bca1c7de0d687be0ac490"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.5,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/node.js.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 1/24 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/peterbe/minimalcss/node.js.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/peterbe/minimalcss/node.js.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/peterbe/minimalcss/node.js.yml/master?enable=pin","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 20 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"34 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-3fjj-p79j-c9hh","Warn: Project is vulnerable to: GHSA-p6vg-p826-qp3v","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-fhjf-83wg-r2j9","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-4g88-fppr-53pp","Warn: Project is vulnerable to: GHSA-4jqc-8m5r-9rpr","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T13:44:10.754Z","repository_id":40827499,"created_at":"2025-08-22T13:44:10.754Z","updated_at":"2025-08-22T13:44:10.754Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000703,"owners_count":26082805,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T05:01:18.566Z","updated_at":"2025-10-08T19:32:34.535Z","avatar_url":"https://github.com/peterbe.png","language":"JavaScript","readme":"# minimalcss\n\n![Build status](https://github.com/peterbe/minimalcss/workflows/Node.js%20CI/badge.svg)\n[![NPM version](https://img.shields.io/npm/v/minimalcss.svg)](https://www.npmjs.com/package/minimalcss)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](#badge)\n[![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovateapp.com/)\n\nA Node library to extract the minimal CSS used in a set of URLs with puppeteer.\nUsed to find what minimal CSS is needed to render on first load, even with\n`document.onload` executed.\n\nThis minimal CSS is also known as [critical path CSS](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp)\nand ultimately a web performance technique to make web pages load faster\nat initial load.\n\n## What does it do\n\nYou supply a list of URLs that it opens (one at a time) and for each page\nit downloads all external CSS files (e.g.\n`\u003clink rel=\"stylesheet\" href=\"bootstrap.min.css\"\u003e`) and uses the DOM and\n`document.querySelector` to investigate which selectors, in the CSS, are\nactually in the DOM. That minimal payload of CSS is all you need to load\nthe URLs styled without having to make it block on CSS.\n\nUnder the hood it relies on the excellent\n[puppeteer library](https://github.com/GoogleChrome/puppeteer) which uses\nthe Headless Chome Node API. This means it runs (at the time of writing)\nChrome 62 and this library is maintained by the Google Chrome team.\n\nThe CSS to analyze (and hopefully minimize) is downloaded automatically just\nlike a browser opens and downloads CSS as mentioned in the DOM as `\u003clink\u003e`\ntags.\n\nThe CSS is parsed by [CSSTree](https://github.com/csstree/csstree) and the\nminification and compression is done with [CSSO](https://github.com/css/csso).\nAn AST of each CSS payload is sent into the Headless Chrome page evaluation\ntogether with a callback that compares with the DOM and then each minimal CSS\npayload is concatenated into one big string which then CSSO compresses into\none \"merged\" and minified CSS payload.\n\n## Usage\n\nInstall:\n\n```bash\nyarn add minimalcss --dev\n```\n\nYou can install it globally if you like:\n\n```bash\nyarn global add minimalcss\n```\n\n```bash\nnpm install [--save-dev|--global] minimalcss\n```\n\nNow you can run it:\n\n```bash\n./node_modules/.bin/minimalcss https://example.com/ https://example.com/aboutus \u003e minimal.min.css\n```\n\n## Prior art\n\n`minimalcss` isn't the first library to perform this task. What's unique and\nspecial about `minimalcss` is that it uses the Chrome Headless browser.\n\n* [penthouse](https://github.com/pocketjoso/penthouse) -\n  uses [puppeteer](https://github.com/GoogleChrome/puppeteer) (since version 1.0) and [CSSTree](https://github.com/csstree/csstree).\n  Supports only 1 URL at a time and can't you have to first save the CSS files\n  it should process.\n\n* [critical](https://github.com/addyosmani/critical) - uses `penthouse`\n  (see above) with its \"flaws\" meaning you can only do 1 URL (or HTML string)\n  and you have to prepare the CSS files too.\n\n* [UnCSS](https://github.com/giakki/uncss) - uses [jsdom](https://github.com/tmpvar/jsdom)\n  to render and execute JavaScript. Supports supplying multiple URLs but still\n  requires to manually supply the CSS files to process.\n\n* [mincss](https://github.com/peterbe/mincss) - Python project that uses\n  [lxml.html](http://lxml.de/lxmlhtml.html) to analyze the HTML statically\n  (by doing a `GET` of the URL as if done by a server). I.e.\n  it can't load the HTML as a real browser would and thus does not support a\n  DOM with possible JavaScript mutations on load.\n  It can optionally use `PhantomJS` to extract the HTML.\n\n## Killer features\n\n* You don't need to specify where the CSS is. It gets downloaded and parsed\n  automatically.\n\n* It uses [puppeteer](https://github.com/GoogleChrome/puppeteer) and\n  [CSSTree](https://github.com/csstree/csstree) which are both high quality\n  projects that are solid and well tested.\n\n* The CSS selectors downloaded is compared to the DOM before _and_ after\n  JavaScript code has changed the DOM. That means you can extract the\n  critical CSS needed to display properly before the JavaScript has kicked in.\n\n* Ability to analyze the remaining CSS selectors to see which keyframe\n  animations that they use and use this to delete keyframe definitions\n  that are no longer needed.\n\n* You can specify a [viewport](https://github.com/GoogleChrome/puppeteer/blob/v1.0.0/docs/api.md#pagesetviewportviewport),\n  which might cause the page to render slightly different. It does not\n  create the minimal CSS _only_ on DOM that is visible though.\n\n* If the CSS contains `@font-face { ... }` rules whose name is never\n  used in any remaining CSS selector, the whole `font-face` block is removed.\n\n## Help needed\n\nLet's make this a thriving community project!\n\nHelp needed with features, tooling, and much testing in real web performance\noptimization work.\n\n## API\n\n```javascript\nconst minimalcss = require('minimalcss');\n```\n\n### Get version `minimalcss.version`\n\nJust prints out the current version.\n\n### Run a minimization `minimalcss.run(options)`\n\nReturns a promise. The promise returns an object containing, amongst\nother things, the minified minimal CSS as a string.\nFor example:\n\n```javascript\nminimalcss\n  .minimize({ url: 'https://example.com/' })\n  .then(result =\u003e {\n    console.log('OUTPUT', result.finalCss.length, result.finalCss);\n  })\n  .catch(error =\u003e {\n    console.error(`Failed the minimize CSS: ${error}`);\n  });\n```\n\nThat `result` object that is returned by the `minimize` function contains:\n\n* `finalCss` - the minified minimal CSS as a string.\n* `stylesheetContents` - an object of stylesheet URLs as keys and their\n  content as text.\n\nOptionally, you can supply a list of URLs like this:\n\n```javascript\nminimalcss\n  .minimize({ urls: ['https://example.com/page1', 'https://example.com/page2'] })\n  ...\n```\n\nand `minimalcss` will try to merge the minimal critical CSS across all pages.\nBut we aware that this can be \"dangerous\" because of the inherit order of CSS.\n\n## API Options\n\nCalling `minimalcss.run(options)` takes an object whose only mandatory\nkey is `urls` or `url`. Other optional options are:\n\n* `debug` - all console logging during page rendering are included in the\n  stdout. Also, any malformed selector that cause errors in `document.querySelector`\n  will be raised as new errors.\n* `skippable` - function which takes\n  [request](https://pptr.dev/#?product=Puppeteer\u0026show=api-class-httprequest)\n  as an argument and returns boolean. If it returns true then given request\n  will be aborted (skipped). Can be used to block requests to Google Analytics\n  etc.\n* `loadimages` - If set to `true`, images will actually load.\n* `withoutjavascript` - If set to `false` it will _skip_ loading the page first\n  without JavaScript. By default `minimalcss` will evaluate the DOM as plain as\n  can be, and then with JavaScript enabled _and_ waiting for network activity\n  to be idle.\n* `disableJavaScript` - By default JavaScript is enabled. If set to `true` it will ignore `withoutjavascript` option and loading the page only one time without JavaScript.\n* `browser` - Instance of a [Browser](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-browser), which will be used instead of launching another one.\n* `userAgent` - specific user agent to use (string)\n* `viewport` - viewport object as specified in [page.setViewport](https://github.com/GoogleChrome/puppeteer/blob/v1.0.0/docs/api.md#pagesetviewportviewport)\n* `puppeteerArgs` - Args sent to puppeteer when launching. [List\n  of strings for headless Chrome](https://peter.sh/experiments/chromium-command-line-switches/).\n* `cssoOptions` - CSSO compress function [options](https://github.com/css/csso#compressast-options)\n* `timeout` - Maximum navigation time in milliseconds, defaults to 30 seconds, pass 0 to disable timeout.\n* `ignoreCSSErrors` - By default, any CSS parsing error throws an error in `minimalcss`. If you know it's safe to ignore (for example, third-party CSS resources), set this to `true`.\n* `ignoreJSErrors` - By default, any JavaScript error encountered by puppeteer\n* `ignoreRequestErrors` - When CSS files return 404 or another request error `minimalcss` will ignore this instead of throwing an error.\nwill be thrown by `minimalcss`. If you know it's safe to ignore errors (for example, on\nthird-party webpages), set this to `true`.\n* `styletags` - If set to `true`, on-page `\u003cstyle\u003e` tags are parsed along with external stylesheets. By default, only external stylesheets are parsed.\n* `enableServiceWorkers` - By default all Service Workers are disabled. This option enables them as is.\n* `whitelist` - Array of css selectors that should be left in final CSS. RegExp patterns are supported (e.g. `['sidebar', icon-.*, .*-error]`).\n\n## Warnings\n\n### Google Fonts\n\nSuppose you have this in your HTML:\n\n```html\n\u003clink href=\"https://fonts.googleapis.com/css?family=Lato\" rel=\"stylesheet\"\u003e\n```\n\nthen, `minimalcss` will consider this an external CSS stylesheet, load it\nand include it in the minimal CSS.\n\nThe problem is that Google Fonts will respond to that URL dynamically based\non the user agent. In other words a different CSS payload depending on who's\nasking. So, the user agent when `minimalcss` runs will be whatever\n`puppeteer` uses and it might not be the best CSS for other user agents.\nSo to avoid this predicament use the `skippable` option. On the command line\nyou can do that like this:\n\n```shell\n./node_modules/.bin/minimalcss --skip fonts.googleapis.com https://example.com\n```\n\nWith the API, you can do it like this:\n\n```javascript\nminimalcss\n  .minimize({\n    url: 'https://example.com',\n    skippable: request =\u003e {\n      return !!request.url().match('fonts.googleapis.com');\n    }\n  })\n  .then(result =\u003e {\n    ...\n  });\n```\n\n### Multiple URLs\n\n`minimalcss` can accept multiple URLs when figuring out the minimal CSS for\nall those URLs, combined. But **be careful**, this can be dangerous. If\nyou have one URL with this HTML:\n\n```html\n\u003chead\u003e\n  \u003clink rel=\"stylesheet\" href=\"base.css\"\u003e\n  \u003clink rel=\"stylesheet\" href=\"specific.css\"\u003e\n\u003c/head\u003e\n```\n\nand another URL with...:\n\n```html\n\u003chead\u003e\n  \u003clink rel=\"stylesheet\" href=\"base.css\"\u003e\n\u003c/head\u003e\n```\n\nWhen combining these, it will optimize the CSS in this order:\n\n1. `base.css`\n2. `specific.css`\n3. `base.css`\n\nBut if `specific.css` was meant to override something in `base.css` in the\nfirst URL, that might get undone when `base.css` becomes the last CSS\nto include.\n\n[See this issue for another good example](https://github.com/peterbe/minimalcss/issues/16) why running `minimalcss` across multiple URLs.\n\n### About `cheerio`\n\nWhen `minimalcss` evaluates each CSS selector to decide whether to keep it\nor not, some selectors might not be parseable. Possibly, the CSS employs\nhacks for specific browsers that\n[cheerio](https://www.npmjs.com/package/cheerio) doesn't support. Or\nthere might be CSS selectors that no browser or tool can understand\n(e.g a typo by the CSS author). If there's a problem parsing a CSS selector,\nthe default is to swallow the exception and let the CSS selector stay.\n\nAlso by default, all these warnings are hidden. To see them use the `--debug`\nflag (or `debug` API option). Then the CSS selector syntax errors are\nprinted on `stderr`.\n\n### About `@font-face`\n\n`minimalcss` will remove any `@font-face` rules whose name is not mentioned\nin any of the CSS selectors. But be aware that you might have a\n`@font-face { font-family: MyName; }` in some `/static/foo.css` but separately\nyou might have an inline style sheet that looks like this:\n\n```html\n\u003cstyle type=\"text/css\"\u003e\ndiv.something { font-family: MyName; }\n\u003c/style\u003e\n```\n\nIn this case the `@font-face { font-family: MyName; }` would be removed even\nthough it's mentioned from somewhere else.\n\n### About Blobs\n\nIf your document uses `Blob` to create injectable stylesheets into the DOM,\n`minimalcss` will _not_ be able to optimize that. It will be not be\nincluded in the final CSS.\n\n## Development\n\nFirst thing to get started, once you've cloned the repo is to install all\nthe dependencies:\n\n```sh\nyarn\n```\n\n### Testing\n\nTesting is done with [`jest`](https://facebook.github.io/jest/). At the\nbeginning of every test, a static file server is started on `localhost`\nand a `puppeteer` browser instance is created for every test.\n\nTo run the tests:\n\n```sh\nyarn jest\n```\n\nBest way to get into writing tests is to look at existing tests and copy.\n\n### Prettier\n\nAll code is expected to conform with [Prettier](https://prettier.io/) according\nto the the `.prettierrc` file in the root of the project.\n\nTo check that all your code conforms, run:\n\n```sh\nyarn lintcheck\n```\n\n## Use without a server\n\n[This blog post](https://www.peterbe.com/plog/how-to-use-minimalcss-without-a-server)\ndemonstrates technique to use `minimalcss` when you don't yet have a server.\nUsing the `http-server` package you can start a server right before you run\nand shut down as soon as you're done.\n\n## License\n\nCopyright (c) 2017-2020 [Peter Bengtsson](https://www.peterbe.com).\nSee the [LICENSE](/LICENSE) file for license rights and limitations (MIT).\n","funding_links":[],"categories":["JavaScript","📦 Legacy \u0026 Inactive Projects","Packages"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeterbe%2Fminimalcss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeterbe%2Fminimalcss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeterbe%2Fminimalcss/lists"}