Skip to content

Zhengqbbb/x-satori

Repository files navigation

x-satori

version

Use Vue files to generate SVG images by Satori.
The image can be generated by running ESM script or CLI.

Open in StackBlitz

youtube guide demo

Twitter: post & demo


Local running example demo

npx degit Zhengqbbb/x-satori/playground <file_name>

cd <file_name>
pnpm install

# Development Model
pnpm dev

# [Generate] SVG
pnpm build
# or `pnpm gen:svg`

# [Generate] PNG
pnpm gen:png

Usage

npm install -D x-satori
Using CLI
  • Dependency: Vue | Vite
$ npx x-satori --help

SYNOPSIS:
    x-satori --template <vue_file_path> --config <satori_config_path> [ --output <path> | --dev ]

OPTIONS:
    -d|--dev                   Turn on Dev mode
    -t|--template <path>       The Vue template file path
    -c|--config   <path>       The export satori configure file path
    -o|--output   <path>       Target output SVG path

EXAMPLES:
    x-satori --config "./satori.js" --template "./Template.vue" --dev
    x-satori --config "./satori.js" --template "./Template.vue"
    x-satori --config "./satori.js" --template "./Template.vue" -o image.svg

Configure

  • Extends Satori options and add Vue file props option
import { defineSatoriConfig } from 'x-satori/vue'

export default defineSatoriConfig({
    // ... Satori options
    props: {
        // ...Vue SFC props options
        // title: "Hello world"
    },
})

Vue template file

<script setup lang="ts">
const props = defineProps({
  title: String,
})
</script>
<template>
  <div class="w-full h-full flex text-white bg-blue-500 items-center justify-center">
    <h1 :style="{ fontSize: '70px' }">
      {{ title }} πŸ‘‹
    </h1>
  </div>
</template>

Example: playground/


Using ESM script
  • Dependency: Vue
import { defineSatoriConfig, satoriVue } from 'x-satori/vue'

function main() {
    const _DIRNAME = typeof __dirname !== 'undefined'
        ? __dirname
        : dirname(fileURLToPath(import.meta.url))
    const _OUTPUT = resolve(_DIRNAME, './image/og.png')

    const templateStr = await readFile(resolve(_DIRNAME, './Template.vue'), 'utf8')
    const opt = defineSatoriConfig({
    // ... Satori options
        props: {
        // ...Vue SFC props options
        // title: "Hello world"
        },
    })
    const strSVG = await satoriVue(opt, templateStr)
    console.log(strSVG)
}
main()

Example: examples/run-esm-script

npm run gen:svg
npm run gen:png

How it works

  1. β–² Satori is an amazing library for generating SVG strings from pure HTML and CSS.
  2. Unfortunately, it is built on top of React's JSX and expects "React-elements-like objects".
  3. Thank an other library natemoo-re/satori-html can to generate the necessary VDOM object from a string of HTML.
  4. So the key is to convert the Vue SFC file to an HTML string, and here I used transform so that I could generate it via script (Only the template syntax is used)
    • @vue/compiler-sfc: to parse Vue SFC file
    • vue - createSSRApp and vue/server-renderer: transform HTML string

Why developed

My Weekend Pilot Project

  1. This processing logic, initially used in my Vite-SSG person website qbb.sh, I prefer to run the script to generate e.g tsx gen-og.mts at my build time rather than the edge Fn
  2. And personally, I think Vue SFC File would be better in expressing this SVG structure, but I only use the template syntax and props, and the css would use tailwindcss.
  3. I did a experiment this weekend, using Vite HRM to improve DX, and developed a CLI so that I could run command and generated the SVG directly.

I'm happy that I finally finished this series of experiments and results this weekend.

demo-img-1 demo-img-2
demo-img-3 demo-img-4
ESM script source: qbb.sh /node/og/main.mts

Related Links

FAQ

CJS support ?

Not supported, waiting for upstream library natemoo-re/ultrahtml

I did it step by step according to the documentation of Vue and Vite, if you are interested, PR welcome πŸ€—

LICENSE

MIT Copyright (c) 2023 Q.Ben Zheng