Skip to content

Commit

Permalink
feat: Experimental support for custom Tailwind configurations (#340)
Browse files Browse the repository at this point in the history
This PR adds a `tailwindConfig` option to pass a custom configuration
down to `twrnc`, which allows sharing tokens between front-end and OG
images in a single codebase already using Tailwind.

<img width="1728" alt="Custom Tailwind classes used in Satori's
playground"
src="https://user-images.githubusercontent.com/6959425/208383229-03e9329c-a50f-47b3-9edb-7b8dc9c56b9c.png">

#### Tests

I wasn't sure if I should add tests given that Tailwind support is
labeled `experimental` and that there are no Tailwind-related tests
currently.

#### `@vercel/og`

What's the process like to surface new `satori` features up to
`@vercel/og`? (e.g. adding a `tailwindConfig` option there too)

---------

Co-authored-by: Shu Ding <[email protected]>
  • Loading branch information
marcbouchenoire and shuding authored Feb 1, 2023
1 parent 45c77a1 commit bc615fa
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 38 deletions.
80 changes: 44 additions & 36 deletions src/handler/tailwind.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,64 @@
import type { TwConfig } from 'twrnc'

import * as twrnc from 'twrnc/create'

const config = {
plugins: [
{
handler: ({ addUtilities }) => {
const presets = {
'shadow-sm': { boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)' },
shadow: {
boxShadow:
'0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
},
'shadow-md': {
boxShadow:
'0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
},
'shadow-lg': {
boxShadow:
'0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
},
'shadow-xl': {
boxShadow:
'0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
},
'shadow-2xl': {
boxShadow: '0 25px 50px -12px rgb(0 0 0 / 0.25)',
},
'shadow-inner': {
boxShadow: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
},
'shadow-none': { boxShadow: '0 0 #0000' },
}
type TwPlugin = TwConfig['plugins'][number]

addUtilities(presets)
const defaultShadows: TwPlugin = {
handler: ({ addUtilities }) => {
const presets = {
'shadow-sm': { boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)' },
shadow: {
boxShadow:
'0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
},
},
],
'shadow-md': {
boxShadow:
'0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
},
'shadow-lg': {
boxShadow:
'0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
},
'shadow-xl': {
boxShadow:
'0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
},
'shadow-2xl': {
boxShadow: '0 25px 50px -12px rgb(0 0 0 / 0.25)',
},
'shadow-inner': {
boxShadow: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
},
'shadow-none': { boxShadow: '0 0 #0000' },
}

addUtilities(presets)
},
}

function createTw() {
return twrnc.create(config, 'web')
function createTw(config?: TwConfig) {
return twrnc.create(
{
...config,
plugins: [...(config?.plugins ?? []), defaultShadows],
},
'web'
)
}

let tw
export default function getTw({
width,
height,
config,
}: {
width: number
height: number
config?: TwConfig
}) {
if (!tw) {
tw = createTw()
tw = createTw(config)
}
tw.setWindowDimensions({ width: +width, height: +height })
return tw
Expand Down
3 changes: 3 additions & 0 deletions src/satori.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ReactNode } from 'react'
import type { TwConfig } from 'twrnc'

import getYoga, { init } from './yoga'
import layout from './layout'
Expand Down Expand Up @@ -31,6 +32,7 @@ export type SatoriOptions = (
languageCode: string,
segment: string
) => Promise<FontOptions | string | undefined>
tailwindConfig?: TwConfig
}

export { init }
Expand Down Expand Up @@ -109,6 +111,7 @@ export default async function satori(
const twToStyles = getTw({
width: definedWidth,
height: definedHeight,
config: options.tailwindConfig,
})
const twStyles = { ...twToStyles([tw] as any) }
if (typeof twStyles.lineHeight === 'number') {
Expand Down
6 changes: 4 additions & 2 deletions tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ export default defineConfig({
entry: ['src/index.ts'],
splitting: false,
sourcemap: true,
dts: process.env.NODE_ENV !== 'development',
dts: process.env.NODE_ENV !== 'development' && {
resolve: ['twrnc', './tw-config', './types'],
},
minify: process.env.NODE_ENV !== 'development',
format: ['esm', 'cjs'],
noExternal: ['twrnc'],
esbuildOptions(options) {
if (process.env.WASM) {
options.outExtension = {
'.js': `.wasm.${options.format === "cjs" ? 'cjs' : 'js'}`,
'.js': `.wasm.${options.format === 'cjs' ? 'cjs' : 'js'}`,
}
}
options.tsconfig = process.env.WASM ? 'tsconfig.wasm.json' : 'tsconfig.json'
Expand Down

1 comment on commit bc615fa

@vercel
Copy link

@vercel vercel bot commented on bc615fa Feb 1, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.