# Critical CSS plugin

**URL:** https://discourse.roots.io/t/critical-css-plugin/11855
**Category:** sage
**Tags:** webpack
**Created:** 2018-03-08T14:32:25Z
**Posts:** 31

## Post 1 by @chrisrhymes — 2018-03-08T14:32:25Z

I’m looking to use [webpack-plugin-critical](https://www.npmjs.com/package/webpack-plugin-critical) in the webpack.config.optimize.js file, but I have no idea what settings would be needed as the example gives index.html as the src and dest, but as its WordPress its not a single page application.

Does anyone have any experience with using this (or other working packages) with WordPress and would you be able to share a working example?

Thanks!

---

## Post 2 by @strarsis — 2018-03-08T16:46:21Z

What about using [pagespeed for nginx](https://discourse.roots.io/t/trellis-build-nginx-from-source-ngx-pagespeed-enjoy/6391/18)?  
[https://www.modpagespeed.com/doc/filter-prioritize-critical-css](https://www.modpagespeed.com/doc/filter-prioritize-critical-css)

And for static:  
[https://discourse.roots.io/t/removing-unused-css-with-purgecss-uncss/11586/2](https://discourse.roots.io/t/removing-unused-css-with-purgecss-uncss/11586/2)

---

## Post 3 by @Log1x — 2018-03-08T18:27:52Z

You’re overthinking it imo. Just import/compile all of your critical CSS to something like `critical.css` and inline it with something like:

```
namespace App;

/**
 * Inject critical assets
 */
add_action('wp_head', function () {
    $critical = @realpath(asset_path('styles/critical.css'));
    if (file_exists($critical)) {
        echo '<style>'.@file_get_contents($critical).'</style>';
    }
}, 10);
```

---

## Post 4 by @chrisrhymes — 2018-03-09T09:39:14Z

Thanks for this. Is there a webpack package you would you use to generate the critical.css file? I used to use penthouse with gulp but I don’t have much experience with webpack.

---

## Post 5 by @Log1x — 2018-03-09T12:37:23Z

I’m sure there’s something out there but depending on the project size I’d probably just resort to `@import`ing all of the above the fold / scaffolding CSS into `critical.css`. I have no suggestions past that though as I haven’t had to do much more. :frowning:

---

## Post 6 by @chrisrhymes — 2018-03-13T11:18:58Z

So I’ve managed to make some progress using [critical-webpack-plugin](https://github.com/iGitScor/critical-webpack-plugin). I’ve added the following to the webpack.config.optimize.js file to get it to generate a critical css file and then use the above code example to inject critical assets. (Replacing path/to/site with the url to your site).

```
const CriticalWebpackPlugin = require('critical-webpack-plugin');
module.exports = {
plugins: [
new ImageMinPlugin(...),
new CriticalWebpackPlugin({
      src: 'http://path/to/site',
      dest: 'critical.css',
      width: 480,
      height: 800,
      pathPrefix: '/styles',
      minify: true
    }),
]
}
```

---

## Post 7 by @jasonbaciulis — 2018-04-10T12:29:51Z

In production sage appends cache busting string to file names so this path wouldn’t work. Is there a way to load file with that cache string name?

---

## Post 8 by @strarsis — 2018-04-10T13:07:29Z

@jasonbaciulis: For production builds a list of plain file names and  
their production equivalents with hash can be found in  
`dist/assets.json`:

```
{
  "scripts/customizer.js": "scripts/customizer_9ecd05b4.js",
  "styles/main.css": "styles/main_9ecd05b4.css",
  "scripts/main.js": "scripts/main_9ecd05b4.js"
}
```

---

## Post 9 by @Log1x — 2018-04-10T18:38:04Z

Whoops. Yes, `asset_path()`.

I updated my code above.

---

## Post 10 by @jasonbaciulis — 2018-04-12T12:30:08Z

It works now but only without `if (file_exists($critical))` statement. `file_exists()` check doesn’t work for me in another place in the theme as well.  
Do you have an idea why it wouldn’t work even if a file does exist?

Also, I am not using `@realpath` like in your code, just an `asset_path`. Is this your own directive? Could you post the code for it?

Thanks.

---

## Post 11 by @LucasDemea — 2018-10-01T22:00:04Z

Hi,  
Did you manage to get this to work ?  
On my side the critical-webpack-plugin is outputing an empty critical.css file. I think it’s because the plugin is run before all files have been built, and is parsing the site without any present css.  
Didn’t you encounter this problem? How can I make sure the plugin runs after all files have been compiled ?

---

## Post 12 by @LucasDemea — 2018-10-01T22:53:11Z

Nevermind, I finally got it working, using the **[html-critical-webpack-plugin](https://github.com/anthonygore/html-critical-webpack-plugin)**@1.1.0 (version is important because plugin’s latest versions don’t work with webpack3).

> [@jasonbaciulis](#):
>
> It works now but only without `if (file_exists($critical))` statement. `file_exists()` check doesn’t work for me in another place in the theme as well.  
> Do you have an idea why it wouldn’t work even if a file does exist?

`$critical` is an url, and `file_exists` uses only physical paths.  
It will work if you use fopen instead :

```
add_action('wp_head', function(){
        $critical=asset_path('styles/critical.css');
        if (@fopen($critical, "r")){
          echo '<style>'.@file_get_contents($critical).'</style>';
        }
      });
```

---

## Post 13 by @jcklpe — 2018-10-27T19:38:15Z

Hey Lucas, just wanted to check in on how this ended up working. I was trying to get GoogleLab’s “Inline Critters Webpack” project working with my theme but it won’t work because it looks for html files and can’t search php.

Please correct me if I’m wrong but it sounds like this is what you got working:

- use html-critical-webpack-plugin to extract the critical path css from the php files
- then output that css to a file called /styles/critical.css
- use the php action listed above (in your functions.php file I imagine) to inject that critical css into the head of the page?

Is that correct? I’m also not using roots, just vanilla wordpress right now. Though it seems like a cool project.

---

## Post 14 by @LucasDemea — 2018-10-29T09:56:42Z

Hi jcklpe.

Yes, though the first point isn’t technically right : html-critical-webpack-plugin isn’t exactly extracting css from php files, but from local or remote urls.

---

## Post 15 by @jcklpe — 2018-10-29T15:47:05Z

Excellent. Would you happen to be able to share a snippet of your config file as reference or maybe a git repo where I could check out how you are doing things?

I hope that’s not asking a lot, I’m new to development and while I think I’ve got an idea of how I should set stuff up I thought I’d check for a reference.

**EDIT:** Also I’m already attempting to integrate it to the webpack on my own, which is bringing up a couple of additional questions.

Does this require HtmlWebpackPlugin to work?

I imagine that it does in order to have an html file to actually check right? That’s what you mean when you say it’s extracting it from local or remote urls right? So what I need to do is first configure HTMLwebpackplugin to render my php files into html files that HTMLCriticalWebpack can then reference to generate the critical.css that then can be loaded by the worpress php function right?

Also is the webpack config able to differentiate between different pages being loaded, or does it just generate critical path css for all the pages and bunldes those together in critical.css?

Again, I apologize if these are sort of dumb questions.

---

## Post 16 by @LucasDemea — 2018-10-30T15:48:06Z

There you go, but it uses some variables from sage, so it might differ a little from your cfg.

webpack.config.optimize.js:

```
module.exports = {
  plugins: [
    new ImageminPlugin({
     ...
    }),
    new HtmlCriticalWebpackPlugin({
      base: config.paths.dist,
      src: config.devUrl,
      dest: 'styles/critical-home.css',
      inline: false,
      minify: true,
      extract: false,
      width: 375,
      height: 565,
      penthouse: {
        blockJSRequests: false,
      }
    }),
    new UglifyJsPlugin({
       ...
    })
  ],
};
```

> [@jcklpe](#):
>
> Does this require HtmlWebpackPlugin to work?

No, php generates the HTML server-side and what the browser (and html-critical-webpack-plugin) get is already HTML.

> [@jcklpe](#):
>
> Also is the webpack config able to differentiate between different pages being loaded, or does it just generate critical path css for all the pages and bunldes those together in critical.css?

In my case, the critical css is generated only for the homepage, but you can run the script on how many pages you want. You’ll just need to instantiate html-critical-webpack-plugin for each page.  
It may be possible to parse multiples pages at once and extract the critical css for all these pages, but I didn’t try it for now.

---

## Post 17 by @Prochor_Simon — 2018-12-04T22:03:39Z

I have error with this

> ```
> TypeError: Cannot read property 'afterEmit' of undefined
> at HtmlCriticalWebpackPlugin.apply
> ```

How can I fix it ?

---

## Post 18 by @MWDelaney — 2018-12-05T00:03:52Z

What have you tried?

---

## Post 19 by @Prochor_Simon — 2018-12-05T00:17:04Z

> [@LucasDemea](#):
>
> module.exports = { plugins: [new ImageminPlugin({ … }), new HtmlCriticalWebpackPlugin({ base: config.paths.dist, src: config.devUrl, dest: ‘styles/critical-home.css’, inline: false, minify: true, extract: false, width: 375, height: 565, penthouse: { blockJSRequests: false, } }), new UglifyJsPlugin({ … })], };

This

> module.exports = {  
> plugins: [  
> new ImageminPlugin({  
> …  
> }),  
> new HtmlCriticalWebpackPlugin({  
> base: config.paths.dist,  
> src: config.devUrl,  
> dest: ‘styles/critical-home.css’,  
> inline: false,  
> minify: true,  
> extract: false,  
> width: 375,  
> height: 565,  
> penthouse: {  
> blockJSRequests: false,  
> }  
> }),  
> new UglifyJsPlugin({  
> …  
> })  
> ],  
> };

---

## Post 20 by @MWDelaney — 2018-12-05T00:54:14Z

Sorry, I mean what have you tried to fix it? We can try to help but we don’t want to go around in circles. Have you googled the issue? Tried to resolve it on your own? If so how?

---

## Post 21 by @Prochor_Simon — 2018-12-05T23:02:11Z

I have this [https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Falmet.com.ua%2F](https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Falmet.com.ua%2F) Yes I tried to resolve by my self

---

## Post 22 by @narrato — 2019-02-19T14:01:21Z

I seem to have found a solution to this error: I had html-critical-webpack-plugin version 2.x installed, installing version 1.1.0 fixed this error.

---

## Post 24 by @dhaynes1206 — 2019-09-19T15:07:15Z

I did notice several issues resulting from using the setup outline in [https://roots.io/guides/asynchronous-css-loading-in-sage/](https://roots.io/guides/asynchronous-css-loading-in-sage/)

If you are using soil and soil-clean-up, the filter referenced to set the media attribute to print for async loading will fail because all handles are removed.

also, if that same filter runs before the action used to inline your critical styles, your yarn build will fail because webpack will not see any usable stylesheets in the source.

I am going to try to tackle this today and report back, just thought I would add that info because the referenced article has a link that points here.

---

## Post 25 by @dhaynes1206 — 2019-09-19T15:28:45Z

actually the yarn build fails because of the async load, has nothing to do with the action to inline critical styles. this obviously will not matter on production, but if you are testing/running on development/staging it will create an issue.

---

## Post 26 by @Alfalfa — 2019-10-09T08:10:33Z

@ [dhaynes1206](https://discourse.roots.io/u/dhaynes1206) DId you find a workaround for that? I guess it’s what happens to me now. Locally it’s creating the critical CSS file, but it’s not in production, hence I see the page with no styles for half a second before the styles are loaded.

yarn build:production fails if I change my devUrl though, what URL should I use there? I tried with localhost:8000 (creates the file in localhost and works fine, not in dev), [mydevdomain.com](http://mydevdomain.com) (build fails), [myproddomain.com](http://myproddomain.com) (build fails).

Any help appreciated!

Edit: Forgot to say that I’m running Sage in a docker container.

---

## Post 28 by @djmtype — 2019-12-23T16:55:49Z

This only seems to work after running `yarn build`. This does not work when running `yarn start`:

```
$critical = asset_path('styles/critical.css');
if (@fopen($critical, 'r')){
echo '<style>'.@file_get_contents($critical).'</style>';
}
}, 1);
```

---

## Post 29 by @duffner — 2020-08-05T22:03:10Z

Hey all, I’m struggling a little bit with the guide [https://roots.io/guides/asynchronous-css-loading-in-sage/](https://roots.io/guides/asynchronous-css-loading-in-sage/), I was able to install all the packages, update all the files etc. However, I’m getting the following error when running yarn build:production:  
`95% emittingError: No usable stylesheets found in html source. Try to specify the stylesheets manually.`

I feel as if the variables here are the culprits, as I’m not familiar enough with Sage, I’m not sure where they are set /resources/assets/build/webpack.config.optimize.js

```
base: config.paths.dist,
  src: config.devUrl,
```

I’m thinking that the config.devUrl isn’t grabbing any data, or maybe that I don’t have it set as I don’t use Trellis, just Bedrock & Sage

---

## Post 30 by @alwaysblank — 2020-08-06T19:13:05Z

> [@duffner](#):
>
> I feel as if the variables here are the culprits, as I’m not familiar enough with Sage, I’m not sure where they are set

They are set here: [https://github.com/roots/sage/blob/9.0.9/resources/assets/config.json](https://github.com/roots/sage/blob/9.0.9/resources/assets/config.json)  
and here: [https://github.com/roots/sage/blob/9.0.9/resources/assets/build/config.js](https://github.com/roots/sage/blob/9.0.9/resources/assets/build/config.js)

I’m not personally familiar w/ this process because, but I’m assuming that it requires your VM to be up and running (i.e. there will need to be something at `devUrl` for the headless browser to visit), which may be a problem?

There are also plugins (i.e. [WP Rocket](https://docs.wp-rocket.me/article/1266-optimize-css-delivery)) and services (i.e. [criticalcss.com](https://criticalcss.com/) that can handle this process for you.

---

## Post 31 by @allan.crabtree — 2021-11-25T18:17:58Z

I had a weird issue which was getting the same error because my `src` URL in `webpack.config.optimize.js` was a wordpress-password protected post/page. As soon as I removed the password protection the yarn build was sucessful.
