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

feat(gatsby-plugin-preload-fonts): preload used fonts #14608

Merged
merged 22 commits into from
Aug 23, 2019
Merged

feat(gatsby-plugin-preload-fonts): preload used fonts #14608

merged 22 commits into from
Aug 23, 2019

Conversation

superhawk610
Copy link
Contributor

@superhawk610 superhawk610 commented Jun 7, 2019

Description

Fonts don't start downloading until the browser knows they're needed. Which means that the browser has to download/parse the HTML & CSS and start rendering a section of the page before it knows to start downloading the font.

This can cause significant delays in loading fonts.

A common suggestion is to add a to the page for each font that's used on the page so the browser knows to start downloading the font files immediately.

This plugin enables a two-step process for embedding <link preload> tags into each statically rendered page in your build output:

  1. Run the included puppeteer script to scrape every route in your application and generate a mapping from routes to fonts.
  2. Add the plugin to your gatsby-config.js and these tags will be automagically embedded into each page at build time.

TODO

  • list all application routes
  • determine what fonts are required on each route
  • cache resource mapping between builds to prevent unnecessarily scrapes
  • inject tags at build time
  • configuration
  • docs
  • tests

Related Issues

Closes #14281.

@superhawk610 superhawk610 self-assigned this Jun 7, 2019
@superhawk610 superhawk610 marked this pull request as ready for review June 8, 2019 04:39
@superhawk610 superhawk610 requested a review from a team as a code owner June 8, 2019 04:39
@superhawk610
Copy link
Contributor Author

I'm currently working on unit tests but I figured I could go ahead and get some feedback on the plugin layout/implementation - in particular, I'm curious how my approach to the following tasks fit the Gatsby ecosystem:

  • cache directory
  • logging
  • route fetching

@ghost
Copy link

ghost commented Jun 13, 2019

Subscribed to this! Thanks for taking this on @superhawk610

@wardpeet wardpeet self-assigned this Jun 14, 2019
Copy link
Contributor

@wardpeet wardpeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking this one on! Looks pretty good.

I wonder if we can implement this as a real gatsby plugin instead of a seperate script. This gives us the opportunity to use the gatsby-cli reporter & gatsby cache.

We could look into https://www.gatsbyjs.org/docs/node-apis/#onCreateDevServer to run puppeteer when the dev server is running.

What do you think?

packages/gatsby-plugin-preload-fonts/README.md Outdated Show resolved Hide resolved
packages/gatsby-plugin-preload-fonts/src/prepare/utils.js Outdated Show resolved Hide resolved
packages/gatsby-plugin-preload-fonts/src/prepare/index.js Outdated Show resolved Hide resolved
@superhawk610
Copy link
Contributor Author

@wardpeet I went with a separate script to follow the idea proposed in the original linked issue; I'm cool with either integrating with the dev server directly or having that as an option, my only concern is that this is a costly operation (minutes on smaller projects and potentially hours on larger projects). I added some basic route caching to prevent crawling if the list of routes hasn't changed, perhaps I should make that more granular and only crawl new routes by default?

cc @KyleAMathews: what are your thoughts on having the font-scraping script run onCreateDevServer vs manually via a package script?

@KyleAMathews
Copy link
Contributor

Yeah — my guess that this would be a really costly operation so best done in a periodic cron job — it looks like your testing has confirmed that so let's keep it a separate script.

Copy link
Contributor

@KyleAMathews KyleAMathews left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good!

Could you include a screenshot of what a run of the script looks like?

@superhawk610
Copy link
Contributor Author

Here's a couple screen recordings of the preload script:

Initial Run

first-run

Subsequent Run(s)

subsequent-run

Copy link
Contributor

@wardpeet wardpeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really good! I added a few comments/questions but this is ready to go! Well done! 👏

@wardpeet wardpeet changed the title feat(gatsby-plugin-preload-fonts): create plugin feat(gatsby-plugin-preload-fonts): fetch loaded fonts Jul 15, 2019
@wardpeet wardpeet changed the title feat(gatsby-plugin-preload-fonts): fetch loaded fonts feat(gatsby-plugin-preload-fonts): preload used fonts Jul 15, 2019
@superhawk610 superhawk610 requested a review from a team as a code owner July 15, 2019 07:15
@wardpeet wardpeet added the status: awaiting author response Additional information has been requested from the author label Jul 29, 2019
@superhawk610
Copy link
Contributor Author

superhawk610 commented Jul 29, 2019

Hey, sorry about the delay, I put this on the backburner until #15475 was addressed but it never was. I'll try and get a commit addressing @wardpeet's most recent feedback this week, hopefully the versioning thing will have sorted itself out.

EDIT: I'm beginning a new job this week, so I haven't had any free time to work on this. I'll get final review changes up as soon as I get the time :)

@wardpeet
Copy link
Contributor

Oh yeah, it got fixed. I missed your issue. It would be awesome to get this one shipped 🤗.

@superhawk610
Copy link
Contributor Author

@wardpeet Should be g2g 🔥

@superhawk610 superhawk610 added status: awaiting reviewer response A pull request that is currently awaiting a reviewer's response and removed status: awaiting author response Additional information has been requested from the author labels Aug 23, 2019
@wardpeet
Copy link
Contributor

Awesome! 🔥 I'll fix tests and give this plugin one more try and i'll merge afterwards! Thanks for your hard work. This is going to be awesome!

Copy link
Contributor

@wardpeet wardpeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤞 I believe this one is going to be the one. Tests node 8 works so. Thanks @superhawk610 for this plugin. Like I said before, this is awesome!

@wardpeet wardpeet merged commit 5b2a76a into gatsbyjs:master Aug 23, 2019
@wardpeet
Copy link
Contributor

@superhawk610 we have published your plugin gatsby-plugin-preload-fonts@1.0.0

@universse
Copy link
Contributor

Is this recommended for self-hosted fonts?

@sidharthachatterjee
Copy link
Contributor

@universse Yeah, should be beneficial whether self hosted or not

@universse
Copy link
Contributor

universse commented Aug 24, 2019

Cause I was trying to run the script "preload-fonts": "gatsby-preload-fonts" and got error

err could not establish a connection with the dev server
     attempted connection to http://localhost:8000/___graphql

So I started dev server, and run the scripts, which gives me this output

// font-preload-cache.json
{
  ...
  "assets": {
    "/": {
      "http://localhost:8000/static/Spectral-ExtraBold-76dd69dbe4b4ddc4f3923bf08e883d43.woff2": true,
      ....
    },
  }
}

This works if fonts are loaded from external sources since you get absolute external urls. That's not the case for self-hosted ones with relative urls. So I guess there needs to be a way to configure the origin. Not sure if i'm missing anything though.

@wardpeet
Copy link
Contributor

@universse good catch, you could add a PR to actually check the url if it matches the dev server we strip out the domain.

@universse
Copy link
Contributor

I made a PR #17235

@chocobuckle
Copy link

Maybe I'm missing something simple, but just curious as to how one is meant to use this with continuous deployment? If I run gatsby develop and then gatsby build locally then all works as expected, but when I push a commit and Netlify starts building my site then it obviously errors with a "err could not establish a connection with the dev server" message. Please explain, as if to an idiot! :)

@superhawk610
Copy link
Contributor Author

You'll need to tweak your CD config to run the dev server in the background, then run gatsby-preload-fonts, then kill the dev server once that's complete. I'm not totally sure of the best way to accomplish this on Netlify, perhaps @masives can shed some light?

@nandorojo
Copy link
Contributor

@superhawk610 Similar question to @chocobuckle here. Any idea how to get this to work on Gatsby Cloud when I deploy?

@superhawk610
Copy link
Contributor Author

@nandorojo I'm not super familiar with Gatsby Cloud configuration, but from the docs it seems like the best way to accomplish this would be to add a postinstall script that does what I suggested above, something like

// package.json
"scripts": {
  "postinstall": "scripts/update-font-preloads.sh"
}

// scripts/update-font-preloads.sh
#!/bin/bash
export CI=1 # Gatsby Cloud may set this for you, in which case
            # it's unnecessary; just make sure it's set or the
            # crawler will hang indefiniely waiting for input

echo "spinning up dev server..."
./node_modules/.bin/gatsby develop &
SERVER_PID=$!

echo "crawling routes to check for font preloads..."
./node_modules/.bin/gatsby-preload-fonts &
CRAWLER_PID=$!

wait $CRAWLER_PID
echo "done!"

kill -9 $SERVER_PID

(I haven't tested this but that's the basic idea)

@botteu
Copy link

botteu commented Sep 18, 2020

I'm in the same boat as @chocobuckle . We're hosting on Netlify and the build script is run when we push to branch X, but since the font mapping needs gatsby develop to run, it doesn't work.

@masives
Copy link
Contributor

masives commented Sep 21, 2020

@botteu I think you'd need to write a node script that would

  1. Spawn a process with gatsby develop
  2. Wait for gatsby dev server to be available
  3. Run the font preloading script
  4. Kill the server

@botteu
Copy link

botteu commented Sep 21, 2020

@masives Yep. But I was hoping to avoid that 😉 But thanks anyways 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: awaiting reviewer response A pull request that is currently awaiting a reviewer's response
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Preload fonts used on pages
9 participants