Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to headless Chrome? #229

Closed
addyosmani opened this issue Aug 4, 2017 · 37 comments
Closed

Migrate to headless Chrome? #229

addyosmani opened this issue Aug 4, 2017 · 37 comments
Labels

Comments

@addyosmani
Copy link
Owner

Now that headless Chrome is a thing and the DevTools support extracting unused CSS via the CSS/JS Code Coverage tool, it may be worth considering if critical would like to switch away from using PhantomJS over to this as part of a rewrite.

CSS Code Coverage is available via the remote debugging protocol and my understanding is that we could programmatically use this to extract out CSS in a more accurate manner while maintaining a similar workflow to what critical supports today.

Something that could be of value to consider is would this change be worth the effort? Would switching away from Phantom under the hood and over to the coverage model improve how close to ideal we're able to extract critical styles? or is the time we could spend doing this better spent addressing the existing edge-cases that come up in issues and smoothing those over instead?

@prateekbh
Copy link

idea of having css extracted with the help of coverage tool is really good as I guess that is what lighthouse uses. Also users rely on it as well. Although what happens to dynamic classnames?
ripple classes, hidden dialog classes etc.. With coverage tool I record the activity and run tasks the most necessary actions on page and then see the results, not sure how we deal with this in the most generic way

@addyosmani
Copy link
Owner Author

To be honest, I'm still somewhat skeptical of the value of code coverage tooling that doesn't include some form of UI hit-testing. That said, even today tools like critical need to work around this by allowing authors to specify their dynamic styles separately or come up with a whitelist of dynamic styles that aren't going to be removed. I could see us using headless + coverage while still having to expose these workarounds for the end user.

@bezoerb
Copy link
Collaborator

bezoerb commented Aug 4, 2017

I think it's worth a try. We should give it a shot on a separate branch to see how far we get.

@kurtextrem
Copy link

Don't we have snippets that generate critical css? If I'm not mistaken Chrome headless is able to inject scripts into pages - what if we combine the coverage report with those snippets?

@pocketjoso
Copy link
Contributor

Just FYI I'm now looking to migrate Penthouse to headless chrome, so if you wait another ~ 2 weeks you can get this migration without any changes to critical, aside from a Penthouse version bump. 👊

@addyosmani
Copy link
Owner Author

@pocketjoso Wow. That's...pretty incredible :) Thanks for keeping an eye on the repo and for letting us know! That'll save a whole lot of time! We really appreciate you working on that migration 🎉 🍰

@pocketjoso
Copy link
Contributor

pocketjoso commented Aug 20, 2017

I have a headless chrome version of Penthouse with feature parity now, just fiddling with support for Linux etc - if you want to play with it it's available on the next tag (penthouse@next), currently as penthouse@rc-4. I will take some time before shipping this as latest.
(penthouse) pr is here: pocketjoso/penthouse#174

@bezoerb
Copy link
Collaborator

bezoerb commented Aug 20, 2017

@pocketjoso: Thats awesome! Thanks for pushing things forward :)

@reznord
Copy link

reznord commented Sep 5, 2017

@pocketjoso: That's super cool. Will try it on a different branch and test it.

@reznord
Copy link

reznord commented Sep 5, 2017

I will be working on it in a separate branch in my fork.

@phaistonian
Copy link
Contributor

So let me get it.

Is there a way we can use Critical with headless chrome now?

ps: I am using headless Chrome any chance I get - it feels NOT dirty, fast and overall awesome.

@pocketjoso
Copy link
Contributor

@phaistonian maybe you can just manually replace the penthouse lib in your node_modules with the one from penthouse@next - if you can get critical to run with it it will work out of the box, as I made the API backwards compatible.

@pocketjoso
Copy link
Contributor

pocketjoso commented Sep 13, 2017

@bezoerb @addyosmani and others:

I will release Penthouse 1.0 this week (using chrome headless via Puppeteer); I've just been writing up a release blog post, and waiting for the Puppeteer team to close a few important bugs.

1.0 will be backwards compatible (except for that Puppeteer requires Node>=6.4.0), so this means you can upgrade without changing a thing! (the reason for the major version bump is more to mark Penthouse as stable tech).

I recommend taking advantage of some changes though:

  • Use cssString instead of css (filepath), to avoid unnecessary i/o.
  • Parallel execution now works, so you might want to utilise this better. Now concurrent penthouse calls get run in different tabs in chromium, rather than as separate browser instances, as was previously the case. This does not only make execution much faster, but also avoid cases where PhantomJS would occasionally just crash, even without hitting resource limits. Note that in the default settings the shared browser instance will get closed as soon as there is no pending call.
  • optional; perhaps not relevant for you - Penthouse 1.0 supports generating before/after screenshots (with/without critical css - in both cases the page rendered without JS), these can be used to increase confidence that the critical css is correct.
  • get rid of const penthouseAsync = Bluebird.promisify(penthouse), as Penthouse has been returning promises since 0.11.0
  • test using file:/// protocol for local files via Chrome headless - which hopefully works across platforms and hence can remove the need for critical to be [starting local servers for the generation])https://github.com/addyosmani/critical/blame/master/lib/core.js#L207)

You can check the readme from the chrome headless Penthouse PR; it is mostly up to date and I will fix the remaining this week.

As I've said before you can test this version on penthouse@next, but at this stage I've run it in production for more than a week and generated over 100,000 critical css files - it's definitely in better shape in every way than the previous version of penthouse.

@phaistonian
Copy link
Contributor

@pocketjoso Worked like charm!

One little thing:

I get this

 UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: Protocol error (Target.closeTarget): Target closed.

all the time. It doe not affect the result, but it's a bit annoying.

@reznord
Copy link

reznord commented Sep 14, 2017

@phaistonian When I test the same in my local, two tests are failing for me. Here is the error log.

@pocketjoso
Copy link
Contributor

So this is when running a lot of invocations in sequence, am I right? not in parallel? I'll look into it - thanks for testing both of you!

@reznord
Copy link

reznord commented Sep 14, 2017

Yup.

@phaistonian
Copy link
Contributor

Having used the lighthouse/chrome-launcher/chrome-launcher (not Puppeteer) to perform some related tasks, I think the issue has to do with the fact that there's a new task launched before the previous Target (Protocol) is closed.

Perhaps an "await" would do the trick :)

@pocketjoso
Copy link
Contributor

@phaistonian Well the intention is to keep the browser instance running, to save some time and resources, but it currently closes as soon as the puppeteer task finishes - so before the next call happens when you run them in sequence. Sounds like there's some timing issue when the two calls happen close after each other (but not in parallel).

@addyosmani
Copy link
Owner Author

I will release Penthouse 1.0 this week (using chrome headless via Puppeteer); I've just been writing up a release blog post, and waiting for the Puppeteer team to close a few important bugs.

\o/ This is amazing work, @pocketjoso. I can't thank you enough for the tireless work in getting Penthouse updated to use headless Chrome. I sit across from the Puppeteer team and if you find yourself blocked on anything at all, please feel free to ping and I'll have a chat with them.

1.0 will be backwards compatible (except for that Puppeteer requires Node>=6.4.0), so this means you can upgrade without changing a thing! (the reason for the major version bump is more to mark Penthouse as stable tech).

I had been very curious to what extent backward compat would be maintained, but this sounds great.

@phaistonian When I test the same in my local, two tests are failing for me. Here is the error log.

Same here. This appears to occur during sequential invocations rather than running in parallel.

As I've said before you can test this version on penthouse@next, but at this stage I've run it in production for more than a week and generated over 100,000 critical css files - it's definitely in better shape in every way than the previous version of penthouse.

This is a good confidence booster. I believe @reznord is interested in working on @next support for critical and might put together a PR for us to switch over as a next step.

optional; perhaps not relevant for you - Penthouse 1.0 supports generating before/after screenshots (with/without critical css - in both cases the page rendered without JS), these can be used to increase confidence that the critical css is correct.

Whoa whoa whoa. That's actually very interesting. A part of my workflow when using critical has always been to do the comparison of the before and after. I'd been wondering if it made sense for a mode that would generate before/after screenshots and do an image diff or visual similarity diff (using SSIM) to inform the user whether the output was 100% as expected. Your work here sounds like it would provide at least the first part of this and I'd love to make sure our readme reflects how to use it with critical via Penthouse.

@pocketjoso
Copy link
Contributor

pocketjoso commented Sep 14, 2017

So for full transparency @addyosmani, as I will disclose in the release post for Penthouse 1.0 (perhaps you know this already) - all my work on Penthouse is pretty much "funded" via the premium SASS service I built on top (https://criticalcss.com), which has been using image diffing since the start. It's also from where I've found most of the issues in Penthouse, and got the confidence that Penthouse works well, since it's used really heavily there. Will post another blog post about criticalcss.com too soon and my story about a successful open source revenue model for a "side project". :)

@pocketjoso
Copy link
Contributor

pocketjoso commented Sep 14, 2017

And @addyosmani re sitting next to the Puppeteer team - that's awesome! You already found the most critical issue on my list (puppeteer/puppeteer#662).

I have nothing else critical that I've already opened issues for, but other things on my mind are:
- problems with thrown errors such as the ones making critical's tests fail - but I need to take a closer look my self on this first to see whether it's something I can fix in Penthouse. There are fewer such thrown errors since the commits after 0.10.2 (specifically since puppeteer/puppeteer@e5c17ee), but...

.. it also seems to me that there's been some performance regressions in Puppeteer since 0.10.2, at least how I use it (with JS disabled). On average my puppeteer execution now seems at least about 1s slower (from about 10s to 12s) - but I have not isolated the cause (exact commit) for this yet hence why I haven't raised an issue in Puppeteer yet. It is possible, but unlikely, that the regression did not come from a change in Puppeteer.

Update: after debugging this today I found and resolved these regressions on my end - they were not coming from Puppeteer. 👍


I also understand that Puppeteer have other priorities than making execution as fast as possible with JS disabled, so hey perhaps this is known and intentional. All in all Chrome headless is lightyears faster than PhantomJS anyway. :)

@pocketjoso
Copy link
Contributor

Finally @addyosmani I have been thinking about backwards compatibility, and the return value of Penthouse, per the discussion we had in London a while ago. I considered breaking the api to return an object with both the critical css and debug/error info as you asked for back then, but for this release I'm almost sold on going for compatibility, so I can get maximum adaptation as the release is just so much better than the current version.

@pocketjoso
Copy link
Contributor

Update: Just published penthouse@1.0.0-rc14 which fixes the bug with target closed errors as reported by @phaistonian in #229 (comment).

Doing final sanity testings, preparing to merge this into the Penthouse master branch for 1.0 version. However in addition to the release post I'm writing I also need to make sure Penthouse's README is up to date - so not sure I will manage to finish this tonight, let's see.

@addyosmani and @bezoerb - I added 2 more points re changes critical should take up when adopting this new penthouse version (no need to promisify, and should be able to skip starting local servers for local files): #229 (comment)

@reznord
Copy link

reznord commented Sep 17, 2017

@pocketjoso everything works super awesome, except for this:

(node:5200) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error: Penthouse timed out after 0.001s.
(node:5200) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

@pocketjoso
Copy link
Contributor

pocketjoso commented Sep 17, 2017

@reznord pushed one more commit that prevents rejecting the returned promise when Penthouse is called in callback mode - have not pushed this to npm though as I'm hoping to merge to master (next) instead :).

And in the bigger picture would be great for critical to start using the Promise based api instead.

@bezoerb
Copy link
Collaborator

bezoerb commented Sep 17, 2017

@pocketjoso That's super awesome! Thanks for putting so much effort in this! I'm looking forward to make the suggested changes to critical this week.

@pocketjoso
Copy link
Contributor

pocketjoso commented Sep 17, 2017

🎉 Penthouse 1.0 is here🎉:
https://medium.com/@pocketjoso/penthouse-1-0-official-release-ece995b0d29e

@bezoerb
Copy link
Collaborator

bezoerb commented Sep 21, 2017

@pocketjoso Tests are currently failing for node 6.
appveyor,
travis

Seems like the current master of puppeteer needs an additional build step for node6 https://github.com/GoogleChrome/puppeteer/blob/master/package.json#L20
/cc @addyosmani

@pocketjoso
Copy link
Contributor

@bezoerb yeah commented in Penthouse repo.

@phaistonian
Copy link
Contributor

So? Almost there?:)

@bezoerb
Copy link
Collaborator

bezoerb commented Sep 26, 2017

@phaistonian: Yes :) we only need to fix node6 support

@stereobooster
Copy link

Is there a PR to fix node6 tests?

@bezoerb
Copy link
Collaborator

bezoerb commented Oct 7, 2017

one step forward in #246

@Grawl
Copy link

Grawl commented Oct 8, 2017

I found this Chrome extension: Critical CSS extractor

Works good for my sites.

bezoerb added a commit that referenced this issue Oct 21, 2017
* Bumped penthouse [#229]

* adds puppeteer as dependency

* Travis tweaks

* Travis tweaks
@phaistonian
Copy link
Contributor

How about a next tag until this is done?

i.e yarn add critical@next

@bezoerb
Copy link
Collaborator

bezoerb commented Nov 6, 2017

v1.0.0 Released :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants