vite-plugin-lqip
Version:
Low-quality image placeholder (LQIP) plugin for Vite.
67 lines (61 loc) • 1.47 kB
text/typescript
import mime from 'mime';
import path from 'node:path';
import sharp from 'sharp';
import type { Plugin } from 'vite';
export interface LQIPPluginOptions {
sharp?: {
/**
* (optional) Provide options to sharp.resize
* @default { width: 32, height: 32, fit: 'inside', kernel: sharp.kernel.cubic }
*/
resize?: sharp.ResizeOptions;
/** (optional) provide options to sharp.webp */
webp?: sharp.WebpOptions;
/**
* (optional) provide blur factor
* @default 1.5
*/
blur?: number;
};
}
export default function vitePluginLqip(options?: LQIPPluginOptions): Plugin {
return {
name: 'vite-plugin-lqip',
enforce: 'pre',
async load(id) {
const [base, search] = id.split('?');
if (!search) {
return null;
}
const s = new URLSearchParams(search);
if (!s.has('lqip')) {
return null;
}
const img = sharp(base);
const metadata = await img.metadata();
const output = await img
.toFormat('webp', {
smartSubsample: true,
...options?.sharp?.webp,
})
.blur(1.25)
.resize({
width: 32,
height: 32,
fit: 'inside',
kernel: sharp.kernel.cubic,
...options?.sharp?.resize,
})
.toBuffer();
const lqip = `data:${mime.getType(path.extname(base!))};base64,${output.toString('base64')}`;
return `import src from '${base}?url';
export default {
lqip: \`${lqip}\`,
src,
width: ${metadata.width ?? -1},
height: ${metadata.height ?? -1},
};
`;
},
};
}