UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

98 lines (84 loc) 2.88 kB
import fs from 'fs/promises' import path from 'path' import {type Plugin} from 'vite' import {generateWebManifest} from '../webManifest' const mimeTypes: Record<string, string | undefined> = { '.ico': 'image/x-icon', '.svg': 'image/svg+xml', '.png': 'image/png', } /** * Fallback favicons plugin for Sanity. * * If a favicon is not found in the static folder, this plugin will serve the default * Sanity favicons from the npm bundle. If a custom `favicon.ico` is found in the static * folder, it will also be served for a root `/favicon.ico` request. * * @param options - Options for the plugin * @returns A Vite plugin * @internal */ export function sanityFaviconsPlugin({ defaultFaviconsPath, customFaviconsPath, staticUrlPath, }: { defaultFaviconsPath: string customFaviconsPath: string staticUrlPath: string }): Plugin { const cache: {favicons?: string[]} = {} async function getFavicons(): Promise<string[]> { if (cache.favicons) { return cache.favicons } cache.favicons = await fs.readdir(defaultFaviconsPath) return cache.favicons } async function hasCustomFavicon(): Promise<boolean> { try { await fs.access(path.join(customFaviconsPath, 'favicon.ico')) return true } catch (err) { return false } } return { name: 'sanity/server/sanity-favicons', apply: 'serve', configureServer(viteDevServer) { const webManifest = JSON.stringify(generateWebManifest(staticUrlPath), null, 2) const webManifestPath = `${staticUrlPath}/manifest.webmanifest` return () => { viteDevServer.middlewares.use(async (req, res, next) => { if (req.url?.endsWith(webManifestPath)) { res.writeHead(200, 'OK', {'content-type': 'application/manifest+json'}) res.write(webManifest) res.end() return } const parsedUrl = ((req as any)._parsedUrl as URL) || new URL(req.url || '/', 'http://localhost:3333') const pathName = parsedUrl.pathname || '' const fileName = path.basename(pathName || '') const icons = await getFavicons() const isIconRequest = pathName.startsWith('/favicon.ico') || (icons.includes(fileName) && pathName.includes(staticUrlPath)) if (!isIconRequest) { next() return } const faviconPath = fileName === 'favicon.ico' && (await hasCustomFavicon()) ? path.join(customFaviconsPath, 'favicon.ico') : path.join(defaultFaviconsPath, fileName) const mimeType = mimeTypes[path.extname(fileName)] || 'application/octet-stream' res.writeHead(200, 'OK', {'content-type': mimeType}) res.write(await fs.readFile(faviconPath)) res.end() }) } }, } }