diff --git a/README.md b/README.md index 1b6d73c..b9f007f 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,29 @@ So the file will be copied to `dist/wasm-files/example.wasm`. > > See [`fast-glob` documentation about this](https://github.com/mrmlnc/fast-glob#how-to-write-patterns-on-windows) for more details. +## Usage (Compressing Content) + +Add `viteStaticCopy` plugin to `vite.config.js` / `vite.config.ts`. Destination files will now be compressed with selected algorithm (gzip, brotli, deflate) and have corresponding extension. + +```js +// vite.config.js / vite.config.ts +import { viteStaticCopy } from 'vite-plugin-static-copy' + +export default { + plugins: [ + viteStaticCopy({ + targets: [ + { + src: 'images/*.svg', + dest: 'assets', + transform: { compress: 'gzip' } + } + ] + }) + ] +} +``` + ### Options See [options.ts](https://github.com/sapphi-red/vite-plugin-static-copy/blob/main/src/options.ts). diff --git a/src/options.ts b/src/options.ts index 22e3233..8043144 100644 --- a/src/options.ts +++ b/src/options.ts @@ -22,10 +22,12 @@ export type TransformOptionObject = | { encoding: Exclude handler: TransformFunc + compress?: 'gzip' | 'brotliCompress' | 'deflate' } | { encoding: 'buffer' handler: TransformFunc + compress?: 'gzip' | 'brotliCompress' | 'deflate' } export type TransformOption = TransformFunc | TransformOptionObject diff --git a/src/utils.ts b/src/utils.ts index b5d5dfc..b579a3a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -11,6 +11,7 @@ import type { import type { Logger } from 'vite' import type { FileMap } from './serve' import { createHash } from 'node:crypto' +import zlib from 'zlib' export type SimpleTarget = { src: string @@ -105,6 +106,45 @@ export const collectCopyTargets = async ( return copyTargets } +async function getCompressedContent( + file: string, + transform: TransformOptionObject +) { + let destExt + switch (transform.compress) { + case 'brotliCompress': + destExt = '.br' + break + case 'deflate': + destExt = '.zz' + break + case 'gzip': + destExt = '.gz' + break + default: + destExt = '' + break + } + //unknown encoding, return empty compressed + if (destExt == '') { + return { destExt, compressedData: null } + } + + const content = await fs.readFile(file) + + const compressedData = await new Promise((resolve, reject) => { + zlib[transform.compress || 'gzip']( + content, + (err: Error | null, result: Buffer) => { + if (err) reject(err) + else resolve(result) + } + ) + }) + + return { destExt, compressedData } +} + export async function getTransformedContent( file: string, transform: TransformOptionObject @@ -137,11 +177,20 @@ async function transformCopy( } } - const transformedContent = await getTransformedContent(src, transform) - if (transformedContent === null) { - return { copied: false } + const { destExt, compressedData } = await getCompressedContent(src, transform) + // if this worked, adjust dest and use, else retry with getTransformedContent() + if (destExt) { + if (compressedData === null) { + return { copied: false } + } + await fs.outputFile(dest + destExt, compressedData) + } else { + const transformedContent = await getTransformedContent(src, transform) + if (transformedContent === null) { + return { copied: false } + } + await fs.outputFile(dest, transformedContent) } - await fs.outputFile(dest, transformedContent) return { copied: true } }