├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── docker.yml │ └── test.yml ├── .gitignore ├── .npmrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── README.md ├── cli.js ├── index.js ├── license ├── package-lock.json ├── package.json ├── preview.png ├── src ├── array.js ├── config.js ├── core.js ├── errors.js └── file.js └── test ├── array.test.js ├── blackbox.test.js ├── cli.test.js ├── config.test.js ├── core.test.js ├── expected ├── generate-adaptive-useragent.css ├── generate-adaptive.css ├── generate-default-nostyle.css ├── generate-default-nostyle.html ├── generate-default.css ├── generate-ignore.css ├── generate-ignorefont.css ├── generate-ignorefont.html ├── generate-image-absolute.css ├── generate-image-big.css ├── generate-image-relative-subfolder.css ├── generate-image-relative.css ├── generate-image-skip.css ├── generate-image.css ├── generateInline-external-extract.html ├── generateInline-external-extract2.html ├── generateInline-external-minified.html ├── generateInline-external-minified2.html ├── generateInline-extract.html ├── generateInline-svg.html ├── generateInline.html ├── ignore.css ├── inline-image.html ├── inline-minified.html ├── inline.html ├── issue-192.css ├── issue-395.css ├── issue-566.css ├── main.css ├── path-prefix.css └── streams-default.html ├── file.test.js ├── fixtures ├── 403-css.html ├── 404-css.html ├── error.html ├── folder │ ├── generate-default.html │ ├── generate-image.html │ ├── index.html │ ├── relative-different.html │ ├── relative.html │ ├── styles │ │ └── issue-566.css │ └── subfolder │ │ ├── generate-image-absolute.html │ │ ├── head.html │ │ ├── issue-216.css │ │ └── relative.html ├── generate-adaptive-base64.html ├── generate-adaptive-inline.html ├── generate-adaptive.html ├── generate-default-nostyle.html ├── generate-default-querystring.html ├── generate-default.html ├── generate-ignorefont.html ├── generate-image.html ├── generateInline-external.html ├── generateInline-external2.html ├── generateInline-svg.html ├── generateInline.html ├── head.html ├── ignore.html ├── ignoreInlinedStyles.html ├── images │ ├── critical-big.png │ └── critical.png ├── include.html ├── inline-image.html ├── inline.html ├── issue-192.html ├── issue-304-nostyle.html ├── issue-304.html ├── issue-314.html ├── issue-395.html ├── issue-415.html ├── issue-562.html ├── issue-566.html ├── media-attr.html ├── path-prefix.html ├── preload.html ├── print.html ├── relative-different.html ├── remote-different.html ├── streams-default.html ├── styles │ ├── adaptive.css │ ├── bootstrap.css │ ├── critical-image-pregenerated.css │ ├── critical-pregenerated.css │ ├── font.css │ ├── ignore.css │ ├── image-absolute.css │ ├── image-big.css │ ├── image-relative.css │ ├── include.css │ ├── issue-192.css │ ├── issue-304.css │ ├── issue-415.css │ ├── issue-562.css │ ├── main.css │ ├── media-attr.css │ ├── path-prefix.css │ ├── print.css │ └── some │ │ └── path │ │ └── image.css └── useragent │ ├── generate-default-useragent.html │ └── styles │ ├── bootstrap.css │ └── main.css ├── helper └── index.js └── index.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.css] 12 | insert_final_newline = false 13 | 14 | [package.json] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # GitHub recommends pinning actions to a commit SHA. 7 | # To get a newer version, you will need to update the SHA. 8 | # You can also reference a tag or branch, but the action may change without warning. 9 | 10 | name: Create and publish a Docker image 11 | 12 | on: 13 | push: 14 | branches: 15 | - master 16 | 17 | env: 18 | REGISTRY: ghcr.io 19 | IMAGE_NAME: ${{ github.repository }} 20 | 21 | jobs: 22 | build-and-push-image: 23 | runs-on: ubuntu-latest 24 | permissions: 25 | contents: read 26 | packages: write 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v3 31 | with: 32 | fetch-depth: 0 33 | 34 | - name: Log in to the Container registry 35 | uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 36 | with: 37 | registry: ${{ env.REGISTRY }} 38 | username: ${{ github.actor }} 39 | password: ${{ secrets.GITHUB_TOKEN }} 40 | 41 | - name: Extract metadata (tags, labels) for Docker 42 | id: meta 43 | uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 44 | with: 45 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 46 | 47 | - name: Build and push Docker image 48 | uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc 49 | with: 50 | context: . 51 | push: true 52 | tags: ${{ steps.meta.outputs.tags }} 53 | labels: ${{ steps.meta.outputs.labels }} 54 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | CI: true 7 | 8 | jobs: 9 | run: 10 | name: Node ${{ matrix.node }} on ${{ matrix.os }} 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | node: [18, 20] 17 | os: [ubuntu-latest, windows-latest] 18 | 19 | steps: 20 | - name: Clone repository 21 | uses: actions/checkout@v3 22 | with: 23 | persist-credentials: false 24 | 25 | - name: Set up Node.js 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: ${{ matrix.node }} 29 | cache: npm 30 | 31 | - name: Install npm dependencies 32 | run: npm ci 33 | 34 | - name: Run tests 35 | run: npm test 36 | 37 | - name: Patch lcov.info 38 | run: sed -i -- 's/SF:..\//SF:.\//g' ./coverage/lcov.info 39 | 40 | - name: Coveralls Parallel 41 | uses: coverallsapp/github-action@master 42 | env: 43 | NODE_COVERALLS_DEBUG: 1 44 | with: 45 | github-token: ${{ secrets.github_token }} 46 | flag-name: run-${{ matrix.os }}-${{ matrix.node }} 47 | parallel: true 48 | 49 | finish: 50 | needs: run 51 | runs-on: ubuntu-latest 52 | steps: 53 | - name: Coveralls Finished 54 | uses: coverallsapp/github-action@master 55 | with: 56 | github-token: ${{ secrets.github_token }} 57 | parallel-finished: true 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage/ 2 | /node_modules/ 3 | /test/fixture/bower_components/bootstrap/dist/css/* 4 | /test/fixture/test-* 5 | /test/fixture/tmp-* 6 | /test/fixtures/styles/bootstrap.beffebca.css 7 | /test/fixtures/styles/main.d41d8cd9.css 8 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | lockfile-version=2 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Critical is an open source project. It is licensed using the 2 | [Apache Software License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). 3 | We really appreciate pull requests and bug reports, here are our guidelines: 4 | 5 | 1. If filing a bug report, please verify the issue is with Critical first. A good sanity check is: 6 | does the issue have to do with styles not being correctly captured? If so, test with [Penthouse](https://github.com/pocketjoso/penthouse). 7 | If it works with Penthouse then it's a Critical bug and we encourage you to open up a [new ticket](https://github.com/addyosmani/critical/issues/new) with details. 8 | Does the bug have to do with inlining styles, general module failures or installation issues? Those are also 9 | possibly Critical bugs and we will strive to take a look at them. 10 | 1. Working on a patch? File a bug at https://github.com/addyosmani/critical/issues (if there 11 | isn’t one already). If your patch is going to be large it might be a good idea 12 | to get the discussion started early. We are happy to discuss it in a new issue beforehand. 13 | 1. Make sure that patches provide justification for why they should be merged. 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-slim 2 | 3 | ARG CRITICAL_VERSION=5.0.4 4 | 5 | ARG PACKAGES="\ 6 | libx11-6\ 7 | libx11-xcb1\ 8 | libxcomposite1\ 9 | libxcursor1\ 10 | libxdamage1\ 11 | libxext6\ 12 | libxi6\ 13 | libxtst6\ 14 | libglib2.0-0\ 15 | libnss3\ 16 | libcups2\ 17 | libxss1\ 18 | libexpat1\ 19 | libxrandr2\ 20 | libasound2\ 21 | libatk1.0-0\ 22 | libatk-bridge2.0-0\ 23 | libpangocairo-1.0-0\ 24 | libgtk-3-0\ 25 | " 26 | RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache 27 | # hadolint ignore=DL3008 28 | RUN --mount=type=cache,id=build-apt-cache,sharing=locked,target=/var/cache/apt \ 29 | --mount=type=cache,id=build-apt-lib,sharing=locked,target=/var/lib/apt \ 30 | apt-get update -qq \ 31 | && apt-get install --no-install-recommends -y ${PACKAGES} \ 32 | && rm -rf /var/lib/apt/lists /var/cache/apt/archives 33 | 34 | RUN --mount=type=cache,id=build-npm-cache,sharing=locked,target=/root/.npm \ 35 | npm install -g critical@${CRITICAL_VERSION} 36 | 37 | WORKDIR /site 38 | 39 | CMD ["critical", "--help"] 40 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import os from 'node:os'; 3 | import process from 'node:process'; 4 | import stdin from 'get-stdin'; 5 | import groupArgs from 'group-args'; 6 | import indentString from 'indent-string'; 7 | import {escapeRegExp, isObject, isString, reduce} from 'lodash-es'; 8 | import meow from 'meow'; 9 | import pico from 'picocolors'; 10 | import {validate} from './src/config.js'; 11 | import {generate} from './index.js'; 12 | 13 | const help = ` 14 | Usage: critical [