很多时候manifest.json
等文件会要求我们给它一系列尺寸的 icon 图片,
虽然生成起来也不算太麻烦,例如有像PWABuilder这样的工具,
但若是经常变动 icon 的话还是觉得有点麻烦,于是想能不能用 nextjs 来动态生成这些图片。
ImageResponse
ImageResponse
是 nextjs 13.4 引入的一个新特性,可以用来动态生成react组件的图片,
加上个img标签,再调一下画布大小,就非常适合用来生成 icon 图片。
使用
下面是一个我现在正在用的例子,只需要更改 iconPath 的定义,并创建个app/icon.js
即可使用
import { ImageResponse } from "next/og";
const iconPath =
"https://ravelloh.top/assets/images/android-chrome-512x512.png";
export function generateImageMetadata() {
return [
{
contentType: "image/png",
size: { width: 16, height: 16 },
id: "16x",
},
{
contentType: "image/png",
size: { width: 32, height: 32 },
id: "32x",
},
{
contentType: "image/png",
size: { width: 36, height: 36 },
id: "36x",
},
{
contentType: "image/png",
size: { width: 48, height: 48 },
id: "48x",
},
{
contentType: "image/png",
size: { width: 72, height: 72 },
id: "72x",
},
{
contentType: "image/png",
size: { width: 96, height: 96 },
id: "96x",
},
{
contentType: "image/png",
size: { width: 128, height: 128 },
id: "128x",
},
{
contentType: "image/png",
size: { width: 144, height: 144 },
id: "144x",
},
{
contentType: "image/png",
size: { width: 192, height: 192 },
id: "192x",
},
{
contentType: "image/png",
size: { width: 256, height: 256 },
id: "256x",
},
{
contentType: "image/png",
size: { width: 384, height: 384 },
id: "384x",
},
{
contentType: "image/png",
size: { width: 512, height: 512 },
id: "512x",
},
{
contentType: "image/png",
size: { width: 1024, height: 1024 },
id: "1024x",
},
];
}
export default async function Icon({ id }) {
return new ImageResponse(
(
// eslint-disable-next-line @next/next/no-img-element
<img src={iconPath} width="100%" height="100%" alt="Icon" />
),
{
width: id.replace("x", ""),
height: id.replace("x", ""),
}
);
}
Nextjs 默认会自动在 build 时 SSR 这些 icon,即每次部署后会自动更新。
请求起来也很简单,例如要是要 144x144 的 icon,只需要访问/icon/144x
即可。
对应的 manifest.js 中的 icon 配置如下:
icons: [
{
src: '/icon/16x/',
sizes: '16x16',
type: 'image/png',
},
{
src: '/icon/32x/',
sizes: '32x32',
type: 'image/png',
},
{
src: '/icon/36x/',
sizes: '36x36',
type: 'image/png',
},
{
src: '/icon/48x/',
sizes: '48x48',
type: 'image/png',
},
{
src: '/icon/72x/',
sizes: '72x72',
type: 'image/png',
},
{
src: '/icon/96x/',
sizes: '96x96',
type: 'image/png',
},
{
src: '/icon/128x/',
sizes: '128x128',
type: 'image/png',
},
{
src: '/icon/144x/',
sizes: '144x144',
type: 'image/png',
},
{
src: '/icon/192x/',
sizes: '192x192',
type: 'image/png',
},
{
src: '/icon/512x/',
sizes: '512x512',
type: 'image/png',
},
{
src: '/icon/1024x/',
sizes: '1024x1024',
type: 'image/png',
}
]