├── .gitignore ├── .travis.yml ├── README.md ├── index.d.ts ├── index.js ├── integration.sh ├── integration ├── check-gen-html.js ├── index.html ├── main.js ├── package.json ├── style.css └── webpack.config.js ├── package.json ├── spec └── support │ └── jasmine.json ├── src ├── critical.spec.ts └── critical.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - '5' 5 | 6 | cache: 7 | directories: 8 | - node_modules 9 | 10 | install: 11 | - npm install 12 | 13 | script: 14 | - npm test 15 | - ./integration.sh 16 | 17 | notifications: 18 | webhooks: 19 | on_success: always # options: [always|never|change] default: always 20 | on_failure: always # options: [always|never|change] default: always 21 | on_start: false # default: false 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Critical Webpack Plugin 2 | 3 | This is a webpack wrapper around [Addy Osmani's critical library](https://github.com/addyosmani/critical), which helps 4 | to inline minimum necessary CSS in HTML documents to prevent stylesheet loading from blocking the [Critical Rendering Path](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/). 5 | 6 | ## Install 7 | 8 | ``` 9 | $ npm install webpack-plugin-critical 10 | ``` 11 | 12 | ## Usage 13 | 14 | The following example shows how the Critical Webpack Plugin can be used to modify 15 | the project's `index.html` file to inline only the (minified) CSS needed for the index page, 16 | and asynchronously load the remaining CSS. 17 | 18 | **webpack.config.js** 19 | 20 | ```js 21 | const CriticalPlugin = require('webpack-plugin-critical').CriticalPlugin; 22 | ... 23 | plugins: [ 24 | new CriticalPlugin({ 25 | src: 'index.html', 26 | inline: true, 27 | minify: true, 28 | dest: 'index.html' 29 | }) 30 | ] 31 | ... 32 | ``` 33 | 34 | The only required option is `dest` and either `src` or `html`, since without dest, the output would 35 | be lost. When using Critical directly (instead of using this plugin), `dest` isn't required because the 36 | callback can accept the HTML or CSS output as a parameter. 37 | 38 | Other than `dest`, all options are the same as Critical, so please see the 39 | [Critical options](https://github.com/addyosmani/critical#options). 40 | 41 | To see a fully working example, check out the [integration spec](./integration). 42 | 43 | ## Why? 44 | 45 | When the browser sees this in a page: 46 | 47 | ```html 48 | 49 | ``` 50 | 51 | The browser stops, loads the stylesheet and its dependencies, and cannot continue 52 | rendering the page until the stylesheet is loaded and parsed. 53 | So the user sees an empty screen while they wait for every stylesheet and script to 54 | load. 55 | The critical library solves this problem by figuring out what CSS is actually needed 56 | for a given page, inlining the CSS into a ` 62 | 63 | ``` 64 | 65 | By loading the stylesheet using `preload` instead of `stylesheet`, the browser 66 | can begin downloading the stylesheet in the background, which comes in handy 67 | in single page applications where additional views may be loaded that depend 68 | on rules from the full stylesheet. 69 | 70 | ## TypeScript Support 71 | 72 | This plugin is written in TypeScript and includes TypeScript typings, 73 | which should automatically work if using TypeScript 2.x+. 74 | 75 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './dist/critical'; 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function __export(m) { 3 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; 4 | } 5 | __export(require('./dist/critical')); 6 | -------------------------------------------------------------------------------- /integration.sh: -------------------------------------------------------------------------------- 1 | rm -rf integration/dist 2 | npm pack . 3 | 4 | PACKAGE=`find . -name webpack-plugin-critical-*` 5 | 6 | cd integration 7 | 8 | npm install 9 | npm install ../$PACKAGE 10 | rm ../$PACKAGE 11 | 12 | ./node_modules/.bin/webpack 13 | node check-gen-html.js 14 | 15 | cd ../ 16 | -------------------------------------------------------------------------------- /integration/check-gen-html.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const parse5 = require('parse5'); 3 | 4 | const doc = fs.readFileSync('./dist/index.html', 'utf-8'); 5 | const parsed = parse5.parse(doc, {treeAdapter: parse5.treeAdapters.htmlparser2}); 6 | const head = parsed.firstChild.firstChild; 7 | const [style] = head.children.filter(n => n.name === 'style'); 8 | const [link] = head.children.filter(n => n.name === 'link'); 9 | const jasmine = require('jasmine'); 10 | 11 | if (style.firstChild.data !== ` 12 | .styleme{color:red} 13 | `) { 14 | throw new Error('Style is not correct:', style.firstChild.data); 15 | } else { 16 | console.log('