Critical CSS plugin

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.

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 ?

Nevermind, I finally got it working, using the html-critical-webpack-plugin@1.1.0 (version is important because plugin’s latest versions don’t work with webpack3).

$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>';
        }
      });
4 Likes

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.

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.

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.

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({
       ...
    })
  ],
};

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

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.

1 Like

I have error with this

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

How can I fix it ?

What have you tried?

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({

})
],
};

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?

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

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.

1 Like

I did notice several issues resulting from using the setup outline in 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.

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.

@ 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 (build fails), myproddomain.com (build fails).

Any help appreciated!

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

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);

Hey all, I’m struggling a little bit with the guide 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

They are set here: 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

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) and services (i.e. criticalcss.com that can handle this process for you.

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.