Skip to content

Commit a68911a

Browse files
committed
feat(cli): create a vite server to develop satori
1 parent fbd618c commit a68911a

20 files changed

+1194
-412
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<h1 align="center">x-satori</h1>
22

33
<p align="center">
4+
Use <b>Vue files to generate SVG images</b> by <a href="https://github.com/vercel/satori">Satori</a>.<br>
5+
The generated images can be coded using scripts or used in CLI.<br><br>
46
<a href="https://www.npmjs.com/package/x-satori">
57
<img alt="version" src="https://img.shields.io/npm/v/x-satori?color=212121&label=">
68
</a>

build.config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ export default defineBuildConfig({
1919
},
2020
externals: [
2121
'vue',
22+
'vite',
2223
],
2324
})

examples/vue/to-png.mts

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,6 @@ import { dirname, resolve } from 'path'
5252
return await writeFile(_OUTPUT, render.asPng())
5353

5454
}()).catch((err: Error) => {
55-
console.error(err)
56-
process.exit(1)
55+
console.error(err)
56+
process.exit(1)
5757
})

examples/vue/to-svg.mts

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ import { dirname, resolve } from 'path'
4545
await writeFile(_OUTPUT, strSVG)
4646

4747
}()).catch((err: Error) => {
48-
console.error(err)
49-
process.exit(1)
48+
console.error(err)
49+
process.exit(1)
5050
})

package.json

+17-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "x-satori",
33
"type": "module",
44
"version": "0.0.3",
5-
"description": "use Vue file to generate Open Graph SVG or PNG by satori",
5+
"description": "use Vue files to generate SVG images using Satori",
66
"author": "Q.Ben Zheng <[email protected]> (https://github.com/Zhengqbbb/)",
77
"license": "MIT",
88
"homepage": "https://github.com/Zhengqbbb/x-satori#readme",
@@ -12,6 +12,9 @@
1212
},
1313
"bugs": "https://github.com/Zhengqbbb/x-satori/issues",
1414
"keywords": [
15+
"satori",
16+
"vue-satori",
17+
"v-satori",
1518
"cli"
1619
],
1720
"exports": {
@@ -47,9 +50,9 @@
4750
"node": ">=14"
4851
},
4952
"scripts": {
53+
"x": "x-satori",
5054
"dev": "unbuild --stub",
51-
"build": "unbuild && cpx src/yoga.wasm dist/shared",
52-
"start": "x-satori",
55+
"build": "unbuild && cpx src/yoga.wasm dist",
5356
"cz": "czg",
5457
"lint": "eslint .",
5558
"prepare": "simple-git-hooks && cpx node_modules/yoga-wasm-web/dist/yoga.wasm src",
@@ -61,13 +64,20 @@
6164
"demo:vue:png": "pnpm -C examples/vue to:png"
6265
},
6366
"dependencies": {
64-
"satori": "^0.4.2",
67+
"@esbuild-kit/cjs-loader": "^2.4.2",
68+
"@esbuild-kit/esm-loader": "^2.5.5",
69+
"express": "^4.18.2",
70+
"minimist": "^1.2.8",
71+
"satori": "^0.4.3",
6572
"satori-html": "^0.3.2",
6673
"yoga-wasm-web": "^0.3.3"
6774
},
6875
"devDependencies": {
6976
"@antfu/eslint-config": "^0.35.3",
7077
"@rollup/plugin-replace": "^5.0.2",
78+
"@types/express": "^4.17.17",
79+
"@types/express-serve-static-core": "^4.17.17",
80+
"@types/minimist": "^1.2.2",
7181
"@types/node": "^18.15.3",
7282
"bumpp": "^9.0.0",
7383
"cpx2": "^4.2.2",
@@ -76,12 +86,12 @@
7686
"lint-staged": "^13.2.0",
7787
"npm-run-all": "^4.1.5",
7888
"pathe": "^1.1.0",
79-
"pnpm": "^7.29.1",
89+
"pnpm": "^7.29.3",
8090
"simple-git-hooks": "^2.8.1",
8191
"tsx": "^3.12.5",
82-
"typescript": "^4.9.5",
92+
"typescript": "^5.0.2",
8393
"unbuild": "^1.1.2",
84-
"vite": "^4.1.4",
94+
"vite": "^4.2.0",
8595
"vue": "^3.2.47",
8696
"x-satori": "workspace:*"
8797
},

playground/Template.vue

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<script setup lang="ts">
2+
defineProps<{ title: string; desc: string; site: string }>()
3+
</script>
4+
5+
<template>
6+
<div
7+
style="background-image: linear-gradient(120deg, rgb(27, 26, 28), rgb(6, 6, 7) 30%, rgb(25, 95, 60) 70%, rgb(16, 15, 16));color: #ffffff;"
8+
tw="w-full h-full text-1.4rem flex flex-col items-center justify-between px-2rem py-2rem"
9+
>
10+
<div tw="flex w-full">
11+
<svg height="72" viewBox="0 0 24 24">
12+
<defs><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="19.78" x2="10.749" y1="11.04" y2="20.16"><stop offset="0" stop-color="#fff" /><stop offset="1" stop-color="#ababab" /></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="13.669" x2="7.911" y1="2.441" y2="19.191"><stop offset="0" stop-color="#fff" /><stop offset="1" stop-color="#ababab" /></linearGradient><clipPath id="a"><path d="M6.621 6.548h16.145v19H6.621z" /></clipPath><clipPath id="c"><path d="M0-4.236h15.108v30H0z" /></clipPath></defs><path clip-path="url(#a)" d="M15.105 12.55c.019.115.04.266.065.453.024.188.036.382.036.583 0 .442-.063.867-.188 1.275a3.145 3.145 0 0 1-.568 1.08c-.255.312-.57.56-.944.742-.374.182-.81.273-1.31.273-.365 0-.691-.06-.98-.18a2.018 2.018 0 0 1-.726-.504 2.242 2.242 0 0 1-.454-.77 2.909 2.909 0 0 1-.158-.98c0-.527.11-1.027.33-1.497.222-.47.52-.902.894-1.296a7.225 7.225 0 0 1 1.303-1.073 9.111 9.111 0 0 1 1.562-.814 9.933 9.933 0 0 1 1.678-.51 7.955 7.955 0 0 1 1.634-.18 8.9 8.9 0 0 1 1.8.172 9.242 9.242 0 0 1 1.642.504c.374-.163.756-.312 1.145-.446.388-.135.79-.211 1.202-.23l.029.086c-.135 0-.298.024-.49.072a5.368 5.368 0 0 0-1.138.44c-.172.09-.302.179-.388.265.365.211.657.483.878.814.221.331.331.713.331 1.145 0 .412-.103.765-.31 1.058a2.706 2.706 0 0 1-.777.735 4.13 4.13 0 0 1-1.022.46 9.04 9.04 0 0 1-1.059.252l-.014.03c.298.037.588.083.871.136.283.053.538.142.763.266.226.125.406.3.54.526.135.226.202.526.202.9a3.02 3.02 0 0 1-.338 1.433c-.226.427-.526.79-.9 1.087a4.143 4.143 0 0 1-1.268.684c-.47.158-.95.238-1.44.238a2.54 2.54 0 0 1-.619-.08 1.949 1.949 0 0 1-.569-.237 1.394 1.394 0 0 1-.417-.404 1.003 1.003 0 0 1-.166-.575.91.91 0 0 1 .26-.649.84.84 0 0 1 .633-.273c.288 0 .542.096.763.288a1.11 1.11 0 0 0-.425.432 1.215 1.215 0 0 0-.136.576c0 .25.067.437.201.562.135.124.327.187.576.187a1.8 1.8 0 0 0 1.023-.31c.307-.206.566-.465.777-.777.211-.313.375-.656.49-1.03.115-.375.173-.73.173-1.066 0-.633-.166-1.096-.497-1.39-.331-.292-.843-.438-1.534-.438l.015-.116a4.18 4.18 0 0 0 1.05-.194 3.09 3.09 0 0 0 .93-.475c.273-.207.496-.466.67-.778.172-.312.258-.684.258-1.116 0-.269-.048-.526-.144-.77a1.622 1.622 0 0 0-.46-.641 5.97 5.97 0 0 0-1.296 1.483c-.384.605-.766 1.25-1.145 1.937-.38.686-.775 1.377-1.188 2.073a10.54 10.54 0 0 1-1.419 1.887 6.595 6.595 0 0 1-1.85 1.368c-.7.35-1.526.526-2.477.526-.307 0-.607-.041-.9-.123a2.61 2.61 0 0 1-.785-.36 1.969 1.969 0 0 1-.561-.583 1.463 1.463 0 0 1-.216-.792c0-.279.074-.518.223-.72.149-.202.377-.303.684-.303.22 0 .396.068.526.202s.194.302.194.504a.654.654 0 0 1-.173.46c-.115.126-.23.198-.345.217a.768.768 0 0 0-.015.173c0 .393.127.684.382.87.254.188.626.282 1.116.282.653 0 1.226-.178 1.72-.533a6.052 6.052 0 0 0 1.361-1.39c.413-.57.812-1.21 1.196-1.915.384-.706.794-1.406 1.23-2.102.438-.696.925-1.354 1.462-1.973a6.578 6.578 0 0 1 1.887-1.505 3.807 3.807 0 0 0-1.325-.655c-.5-.14-.994-.209-1.483-.209a6.76 6.76 0 0 0-2.117.36c-.73.24-1.394.588-1.994 1.044a5.73 5.73 0 0 0-1.476 1.656c-.384.648-.576 1.38-.576 2.196 0 .23.03.47.093.72s.161.478.295.684c.135.207.303.377.504.511.202.135.437.202.706.202a1.97 1.97 0 0 0 1-.252c.294-.168.546-.394.757-.677a3.11 3.11 0 0 0 .482-.98c.11-.369.166-.75.166-1.144 0-.23-.01-.43-.029-.598a46.06 46.06 0 0 0-.058-.482l.159-.014Z" fill="url(#b)" /><path clip-path="url(#c)" d="M15.108 12.625c-.154.252-.333.518-.536.798-.202.28-.43.532-.682.756-.252.224-.522.41-.809.557-.287.147-.591.22-.913.22-.35 0-.707-.105-1.071-.315-.252-.14-.48-.35-.682-.63a7.12 7.12 0 0 1-.546-.882 17.7 17.7 0 0 1-.441-.903 7.872 7.872 0 0 0-.347-.693c-.322.112-.64.196-.955.252a5.448 5.448 0 0 1-.956.084c-.462 0-.928-.056-1.396-.168a2.576 2.576 0 0 1-1.208-.65 5.65 5.65 0 0 0-.798.671 7.048 7.048 0 0 0-.693.798c-.07 0-.105-.049-.105-.147.238-.28.48-.539.724-.777a7.4 7.4 0 0 1 .767-.65c-.448-.49-.672-1.1-.672-1.828 0-.448.087-.913.262-1.396.175-.483.4-.956.672-1.418.274-.462.571-.9.893-1.312.322-.413.637-.767.945-1.06a5.3 5.3 0 0 1 3.675-1.513c.07 0 .115.014.136.042a.14.14 0 0 1 .032.084c0 .042-.014.063-.042.063a.973.973 0 0 0-.189-.02h-.147c-.336 0-.672.08-1.008.24a4.53 4.53 0 0 0-.945.61c-.294.245-.56.504-.798.777s-.441.514-.609.724c-.196.266-.403.574-.62.924-.216.35-.416.718-.598 1.103a7.648 7.648 0 0 0-.452 1.218 4.79 4.79 0 0 0-.178 1.291c0 .364.07.721.21 1.071.476-.322.931-.535 1.365-.64.434-.105.791-.158 1.071-.158.154 0 .318.01.493.032.176.02.361.073.557.157.196.084.399.214.609.389.21.175.42.416.63.724a4.999 4.999 0 0 0 1.386-1.04 7.732 7.732 0 0 0 1.785-3.076c.168-.56.252-1.085.252-1.575 0-.448-.053-.864-.158-1.25a2.497 2.497 0 0 0-.472-.955 1.746 1.746 0 0 0-.388-.325 1.35 1.35 0 0 0-.41-.179c-.07-.028-.105-.049-.105-.063 0-.028.035-.042.105-.042.112 0 .245.004.399.01.154.008.294.011.42.011.084 0 .178.01.284.032a.63.63 0 0 1 .283.136c.21.168.413.417.609.746s.294.794.294 1.396c0 .42-.077.914-.231 1.48a7.43 7.43 0 0 1-.735 1.733A8.669 8.669 0 0 1 11.78 9.79a6.94 6.94 0 0 1-1.922 1.386c.084.126.182.29.294.494.112.203.238.42.378.65.14.232.294.466.462.704.168.238.343.462.525.672.406.462.826.693 1.26.693.084 0 .203-.014.357-.042.154-.028.325-.101.514-.22.19-.12.396-.305.62-.557.224-.252.448-.602.672-1.05.028-.042.063-.049.105-.02.042.027.063.07.063.125Zm-6.111-1.239-.304-.472a2.253 2.253 0 0 0-.378-.441 1.8 1.8 0 0 0-.525-.326 1.952 1.952 0 0 0-.746-.126c-.35 0-.686.06-1.008.179a4.965 4.965 0 0 0-.945.472c.238.392.574.658 1.008.798.434.14.861.21 1.281.21.532 0 1.071-.098 1.617-.294Z" fill="url(#d)" />
13+
</svg>
14+
</div>
15+
<div tw="w-full flex relative mt--20 px-30 flex-col justify-center items-center">
16+
<div tw="text-4rem font-bold" style="white-space: pre-wrap;" v-html="title" />
17+
<div tw="text-2.4rem text-neutral-200" style="white-space: pre-wrap;">
18+
This is a example
19+
</div>
20+
</div>
21+
<div tw="w-full flex items-center justify-end">
22+
<div tw="flex items-center text-zinc-500 text-1rem">
23+
<span tw="text-neutral-500 ml-1">
24+
By Q.Ben Zheng
25+
</span>
26+
<span tw="text-neutral-500 border-b border-neutral-400 ml-2" v-html="site" />
27+
</div>
28+
</div>
29+
</div>
30+
</template>

playground/a.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { fileURLToPath } from 'node:url'
2+
import { readFile } from 'node:fs/promises'
3+
import { dirname, resolve } from 'path'
4+
import { satoriVue } from 'x-satori/vue'
5+
6+
export async function gen() {
7+
const _DIRNAME = typeof __dirname !== 'undefined'
8+
? __dirname
9+
: dirname(fileURLToPath(import.meta.url))
10+
11+
const templateStr = await readFile(resolve(_DIRNAME, './Template.vue'), 'utf8')
12+
const opt = {
13+
height: 628,
14+
width: 1200,
15+
fonts: [
16+
{
17+
name: 'Inter',
18+
data: await readFile(resolve(_DIRNAME, './fonts/Inter-Medium.woff')),
19+
weight: 400,
20+
style: 'normal',
21+
},
22+
{
23+
name: 'Inter',
24+
data: await readFile(resolve(_DIRNAME, './fonts/Inter-Bold.woff')),
25+
weight: 700,
26+
style: 'normal',
27+
},
28+
{
29+
name: 'Noto Sans Symbols',
30+
data: await readFile(resolve(_DIRNAME, './fonts/NotoSansSymbols2-Regular.ttf')),
31+
weight: 700,
32+
style: 'normal',
33+
},
34+
],
35+
props: {
36+
title: 'hello nice',
37+
desc: 'example',
38+
site: 'https://qbb.sh',
39+
},
40+
}
41+
const strSVG = await satoriVue(opt, templateStr)
42+
return strSVG
43+
}

playground/config.mjs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { readFileSync } from 'node:fs'
2+
import { fileURLToPath } from 'node:url'
3+
import { dirname, resolve } from 'path'
4+
import { defineSatoriConfig } from 'x-satori/vue'
5+
6+
const _DIRNAME = typeof __dirname !== 'undefined'
7+
? __dirname
8+
: dirname(fileURLToPath(import.meta.url))
9+
10+
export default defineSatoriConfig({
11+
height: 628,
12+
width: 1200,
13+
fonts: [
14+
{
15+
name: 'Inter',
16+
data: readFileSync(resolve(_DIRNAME, './fonts/Inter-Medium.woff')),
17+
weight: 400,
18+
style: 'normal',
19+
},
20+
{
21+
name: 'Inter',
22+
data: readFileSync(resolve(_DIRNAME, './fonts/Inter-Bold.woff')),
23+
weight: 700,
24+
style: 'normal',
25+
},
26+
{
27+
name: 'Noto Sans Symbols',
28+
data: readFileSync(resolve(_DIRNAME, './fonts/NotoSansSymbols2-Regular.ttf')),
29+
weight: 700,
30+
style: 'normal',
31+
},
32+
],
33+
props: {
34+
title: 'hello world',
35+
desc: 'example',
36+
site: 'https://qbb.sh',
37+
},
38+
})

playground/config.mts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { readFileSync } from 'node:fs'
2+
import { fileURLToPath } from 'node:url'
3+
import { dirname, resolve } from 'path'
4+
import { defineSatoriConfig } from 'x-satori/vue'
5+
6+
const _DIRNAME = typeof __dirname !== 'undefined'
7+
? __dirname
8+
: dirname(fileURLToPath(import.meta.url))
9+
10+
export default defineSatoriConfig({
11+
height: 628,
12+
width: 1200,
13+
fonts: [
14+
{
15+
name: 'Inter',
16+
data: readFileSync(resolve(_DIRNAME, './fonts/Inter-Medium.woff')),
17+
weight: 400,
18+
style: 'normal',
19+
},
20+
{
21+
name: 'Inter',
22+
data: readFileSync(resolve(_DIRNAME, './fonts/Inter-Bold.woff')),
23+
weight: 700,
24+
style: 'normal',
25+
},
26+
{
27+
name: 'Noto Sans Symbols',
28+
data: readFileSync(resolve(_DIRNAME, './fonts/NotoSansSymbols2-Regular.ttf')),
29+
weight: 700,
30+
style: 'normal',
31+
},
32+
],
33+
props: {
34+
title: 'hello world',
35+
desc: 'example',
36+
site: 'https://qbb.sh',
37+
},
38+
})

playground/config.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { readFileSync } from 'node:fs'
2+
import { fileURLToPath } from 'node:url'
3+
import { dirname, resolve } from 'path'
4+
import { defineSatoriConfig } from 'x-satori/vue'
5+
6+
const _DIRNAME = typeof __dirname !== 'undefined'
7+
? __dirname
8+
: dirname(fileURLToPath(import.meta.url))
9+
10+
export default defineSatoriConfig({
11+
height: 628,
12+
width: 1200,
13+
fonts: [
14+
{
15+
name: 'Inter',
16+
data: readFileSync(resolve(_DIRNAME, './fonts/Inter-Medium.woff')),
17+
weight: 400,
18+
style: 'normal',
19+
},
20+
{
21+
name: 'Inter',
22+
data: readFileSync(resolve(_DIRNAME, './fonts/Inter-Bold.woff')),
23+
weight: 700,
24+
style: 'normal',
25+
},
26+
{
27+
name: 'Noto Sans Symbols',
28+
data: readFileSync(resolve(_DIRNAME, './fonts/NotoSansSymbols2-Regular.ttf')),
29+
weight: 700,
30+
style: 'normal',
31+
},
32+
],
33+
props: {
34+
title: 'hello nice',
35+
desc: 'example',
36+
site: 'https://qbb.sh',
37+
},
38+
})

0 commit comments

Comments
 (0)