-
Notifications
You must be signed in to change notification settings - Fork 80
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
Use build-time og images #293
base: main
Are you sure you want to change the base?
Conversation
imgSrc: string; | ||
} | ||
|
||
export async function openGraphImage() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like an extremely Remix way of doing this. Looking forward to hearing your thoughts on this.
DeploymentA single requirement this plugin has is for your build to run a Puppeteer binary. You seem to be using Fly, which I believe is pretty flexible in terms of Docker images you use to deploy your app. Can someone please double-check if you have Chromium installed already? If not, we should add that to the image to skip downloading it on every build. cc @brookslybrand
|
I think with this linting rule, you may want to enable
|
This is neat! The problem with this approach is that it requires a rebuild of the whole site when new posts are published or a change is made to the og images. Additionally, the build times increases linearly with the number of pages which can aggravate the rebuild issues. Taking this to the logical conclusion is why Gatsby and Next.js came up with Deferred Static Generation (DSG) and Incremental Static Regeneration (ISR). Having things be generated at runtime is a desirable feature for these reasons. |
Thanks for the feedback, @kentcdodds! Those are valid concerns, allow me to address some and share my opinion on others. Changes require a rebuildThis will be my most controversial opinion, perhaps, but I truly believe that runtime content rendering, while it has a place to be, is a bad idea for most people. In practice, blogs, portfolios, and personal websites are static by nature. Pushing the content rendering to runtime adds unnecessary complexity and fragility (what if my runtime function pulls from a malformatted MDX? The site is down). I understand that may be desired in the case of highly-dynamic website, like yours. Realistically, very few people build or even need that level of detail. In fact, when I created a site for my wife using Remix, I quickly learned that it was a mistake to use it for a de-facto static website (it's still one of my painpoints with the framework). It introduces a degree more issues compared to the value it provides (I have to use verbose runtime MDX rendering, Remix doesn't support relative assets like images so I need to create explicit resource routes for those, etc).
That being said, the point itself is valid. Having to wait for an entire build to finish just to see an update to an OG image is likely too much. I think the solution here is asset caching during the build. Linear build time increaseI agree on this one too. I mean, it's x10 build time increase as of now, that's not nice! I have at least four things to try to improve the plugin's performance:
I believe implementing these will yield to a decrease in build time. It's worth mentioning that build-time generation will take time by design. As long as that time is appropriate, I'd argue it's a fantastic price to pay for all the benefits that the build-time generation provides, proper rendering and easier setup being just a few. If you consider how much compute this solves for your app in the long run, it's more than worth it.
DSG and ISRBoth are fantastic techniques that solve real problems. At the same time, I must admit, I've never faced any of those problems building websites and publishing content for almost a decade now. I can safely say most people haven't either. The majority of folks don't have millions of pages. Not even hundreds. It's good if they have a dozen! Transforming MDX is really fast (that's one of the reasons you can put it on runtime, to begin with). I can pay that price for 10 of my articles once, instead of asking every reader to pay it whenever they open my article for the first time. There is an important exception. If your content is dynamic, as in something on the OG image changes independently from your post (like GitHub's PR title on the PR OG image preview), then this plugin is not for you. Then, the runtime generation is indeed a solution to a problem here. But it's not in all the other cases, which I believe is the majority (like this website!). Your feedback comes down to performance and optimization, and I'm happy about that! The plugin is extremely raw, and trying it out on the Remix's site gave me a lot of hopes in its future. The fact that I was able to re-create your setup being entirely unfamiliar with the code base and the previous setup in under an hour is incredible. I spent an hour tweaking Satori just to understand it forces me to load a TTF version of my font that is x3 larger just so I could generate an image. That doesn't sound like a good design to me.
So, I will keep working on the plugin's performance and let's see where it goes! |
When I was building out my blog, which ran on Cloudflare Workers, I decided that I wanted my MDX content to be compiled at "build" time. My content was static files committed to the repo, so I had a script using GitHub Actions that compiled the MDX and pushed the results to the Worker KV store. This way, there was no runtime cost. It even included Etags, so I didn't even need to send the result if it was already cached. For local development, I created a content watcher that would compile and store in local KV whenever I saved the MDX file. This resulted in a very nice workflow that optimized for reading as well as change. |
|
I am looking at the Fly Docker image to install Chromium, allowing this plugin to run (the default image doesn't have it installed). Will try to push the changes later next week.
|
UpdatesWith https://github.com/kettanaito/remix-og-image/releases/tag/v0.3.5 and preceding releases, I've shaved about 3s from each generated image. I've also added proper caching on CI, which should be supported in Fly as well. This should improve the build time and produce dramatically faster incremental builds. I've also added |
Changes
Why?
The plugin has a nice summary of its benefits. Also summarizing here:
style
, dealing with the limitations of runtime-based solutions./og/blog/:slug
in the browser to iterate on the image. Debuggable with your favorite tools.*.webp
for OG images as it yields to ~61% smaller file size with superior quality to JPEG.Examples
I tried to re-create what you have with Satori but using Tailwind. Sharing some of the generated OG images below.
Post with unique background
Post without background (default background)
Post with multiple authors
Post with a long title
Since the OG image generation happens on build time now, that obviously affects the build, well, time! Let's see how.
Although this generates the images for all 27 existing blog posts (<1s per image), that's a huge decrease! I will see what I can do on the plugin's side to make it faster. The plugin supports caching, and will not generate images for data that hasn't changed, but that cache won't survive the build on CI, I wager.
Roadmap
satori
and the previous SVG-based runtime OG generation setup (once the changes are confirmed as good, will remove that). Looking forward to that nice diff!