Skip to main content

2 posts tagged with "react"

View All Tags

Creating an OG image using React and Netlify Edge Functions

· 4 min read
Nick Taylor
AI Engineer

Open Graph (OG) images are a must if you're sharing content on the Internet. From sites like X/Twitter, to Slack or Discord, a great OG image makes your link share pop.

Examples

I recently built out a couple of OG images for Open Sauced for a couple of features we've rolled out over the past couple of months, Workspaces and Repository pages. They're great features that I encourage you to check out, and I encourage you to share them on socials so our beautiful OG images pop.

For example, here's an OG image for a workspace for jsr. JSR is the new JavaScript registry from the folks from Deno.

OG image for the OpenSauced workspace for jsr

And here's the OG image for a repository page for huggingface/transformers.

OG image for the huggingface/transformers repository

Looking at the image for the jsr workspace, there is a template for the image, but there are several dynamic portions to the image.

All the sections denoted by green outlined squares are dynamic.

OG image for the OpenSauced workspace for jsr with sections outline in green squares denoting dynamic portions of the image

This dynamic info gets pulled in for the most part from the OpenSauced API.

Other parts are pulled in from the URL, like 30 for the day range, and the description comes from the query string in the OG image URL.

browser dev tools view of the metadata section of the head with OG image URLs outlined by green squares

React to generate an image

So, how do we use React to generate an image?

We're using og_edge from my old co-worker Matt Kane (@ascorbic), but og_edge is a direct port of @vercel/og that works on Deno and Netlify Edge Functions which run on Deno.

https://github.com/ascorbic/og-edge

Under the hood, og_edge and @vercel/og use the Satori library.

Satori: Enlightened library to convert HTML and CSS to SVG.

https://github.com/vercel/satori

The API for the og_edge module is pretty straightforward. It exposes an ImageResponse constructor with the following options and that's it.

{% raw %}
new ImageResponse(
element: ReactElement,
options: {
width?: number = 1200
height?: number = 630
emoji?: 'twemoji' | 'blobmoji' | 'noto' | 'openmoji' | 'fluent' | 'fluentFlat' = 'twemoji',
fonts?: {
name: string,
data: ArrayBuffer,
weight: number,
style: 'normal' | 'italic'
}[]
debug?: boolean = false

// Options that will be passed to the HTTP response
status?: number = 200
statusText?: string
headers?: Record<string, string>
},
)
{% endraw %}

Code snippet above care of the official og_edge API reference.

To build out these OG images, we have a background image, some icons, like a star and fork icon, and we also pull in the repository organization or user's avatar. With a bit of vanilla CSS, we can position things just right. We also pull in the Inter font as that's what we use at OpenSauced.

As far as I know, og_edge does not support Tailwind like @vercel/og does. Not a dealbreaker at all, but just something to be mindful of.

One other thing we do is set cache headers as these are dynamic images where the data changes over time. Having said that, some social networks cache OG images very aggressively.

{% raw %}
headers: {
// cache for 2 hours
"cache-control": "public, s-maxage=7200",
"content-type": "image/png",
},
{% endraw %}

Show me the code

Here's the pull requests for the initial work on these two OG images.

https://github.com/open-sauced/app/pull/2939 https://github.com/open-sauced/app/pull/3117

Wrapping up

Beautiful and dynamic OG images are a must if you're looking to stand out when sharing links on socials, and og_edge and @vercel/og are great options if you also want to leverage your existing React skill set.

Now go out and build your own OG images! 🖼️

Stay saucy peeps!

If you would like to know more about my work in open source, follow me on OpenSauced.

Migrating from Jest to Vitest for your React Application

· 5 min read
Nick Taylor
AI Engineer

Are you looking to migrate from Jest to Vitest for your React application? Look no further.

I recently migrated the OpenSauced app repository to Vitest. Here's the pull request if you're interested.

https://github.com/open-sauced/app/pull/2296

Why move from Jest to Vitest?

Both Jest and Vitest are great testing frameworks, so why bother switching?

Vitest supports ECMAScript modules (ESM), TypeScript out of the box.

Jest requires additional setup for both, although there is experimental support for ESM.

Vitest is also fast. Yes, it depends, but in general, it's faster. (See the Vitest comparison with other test runners)

Neo fighting an agent in the Matrix movie with one hand

If you're already using Vite in your project or the meta-framework you're using is based on Vite, using Vitest is a no-brainer as you're already in the Vite ecosystem.

If your project isn't using Vite, e.g. Next.js, it's still a great move.

Vitest makes it effortless to migrate from Jest. It supports the same Jasmine like API.

TLDR; You don't need to update existing tests, as it’s mostly a drop-in replacement for Jest.

Some other niceties are a default watch mode care of Vite instant Hot Module Reload (HMR).

Install Vitest

The first thing you want to do is install Vitest.

https://github.com/vitest-dev/vitest

Run npm install vitest -D in the terminal to install Vitest as a dev dependency.

Next up, create a vitest.config.ts file in the root of your project. Even if you're not using TypeScript, name it vitest.config.ts.

In that file, add the following code and save it.

{% raw %}
import { defineConfig } from "vite";

// https://vitejs.dev/config/
export default defineConfig({
test: {
// some paths to the files that are test files
include: ["./**/*.test.ts", "./**/*.test.tsx"],
},
});
{% endraw %}

You can explicitly import describe, it/test, expect or you can have it work like in Jest where they're all globals. All you need to do is set globals to true in the Vitest configuration.

{% raw %}
import { defineConfig } from "vite";

// https://vitejs.dev/config/
export default defineConfig({
test: {
include: ["./**/*.test.ts", "./**/*.test.tsx"],
+ globals: true,
},
});
{% endraw %}

Using Vitest with React

At OpenSauced, we're using Next.js to build out the main application.

Vitest is based off Vite which supports React via their plugin ecosystem, so you'll need to install the Vite React plugin to get React support.

Run npm install @vitejs/plugin-react -D to install the plugin as a dev dependency.

Update the Vitest configuration to add the React plugin.

{% raw %}
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
+ plugins: [react()],
test: {
include: ["./**/*.test.ts", "./**/*.test.tsx"],
globals: true,
},
});
{% endraw %}

React Testing Library

If you happen to be using React Testing Library in your project, you'll need to keep the jsdom dev dependency installed.

Next, add jsdom to your Vitest configuration.

{% raw %}
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
test: {
include: ["./**/*.test.ts", "./**/*.test.tsx"],
globals: true,
+ environment: "jsdom",
},
});
{% endraw %}

Aliases

Your project might be using aliases for paths. For example, in the OpenSauced app repository, components, lib, and img are aliases to folders.

If you need to support aliases, Vitest has you covered.

Here's an example of supporting the above-mentioned aliases.

{% raw %}
export default defineConfig({
plugins: [react()],
+ resolve: {
+ alias: {
+ components: fileURLToPath(new URL("./components", import.meta.url)),
+ lib: fileURLToPath(new URL("./lib", import.meta.url)),
+ img: fileURLToPath(new URL("./img", import.meta.url)),
+ },
+ },
test: {
include: ["./**/*.test.ts", "./**/*.test.tsx"],
globals: true,
environment: "jsdom",
},
});
{% endraw %}

TypeScript Types

If you're using TypeScript, you can add the types for Vitest to the project.

In your tsconfig.json file, add the types in the compiler options section of the TypeScript configuration file.

{% raw %}
{
"compilerOptions": {
// . .. other compiler options in your project
+ "types": ["vitest/globals"]
}

// . .. other TypeScript configuration options in your project
}

{% endraw %}

Running Tests

To run tests using Vitest, you can run vitest. By default, it will go into watch mode. If you only want to run the test suite once, e.g. for the CI/CD pipeline, run vitest run.

Removing Jest

If your project is a TypeScript project, you probably have the types for Jest in your project. If you do, run the following to remove the Jest TypeScript types.

{% raw %}
npm uninstall -D @types/jest
{% endraw %}

Uninstall Jest itself.

{% raw %}
npm uninstall jest jest-environment-jsdom -D
{% endraw %}

And that's it! Happy testing!

Stay saucy peeps!

If you would like to know more about my work in open source, follow me on OpenSauced.