很多时候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", ""), } ); }
javascript
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', } ]
javascript