Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhanced transform functionality to include compression #135

Closed
wants to merge 11 commits into from
Closed
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
2 changes: 2 additions & 0 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ export type TransformOptionObject =
| {
encoding: Exclude<BufferEncoding, 'binary'>
handler: TransformFunc<string>
compress?: 'gzip' | 'brotliCompress' | 'deflate'
}
| {
encoding: 'buffer'
handler: TransformFunc<Buffer>
compress?: 'gzip' | 'brotliCompress' | 'deflate'
}

export type TransformOption = TransformFunc<string> | TransformOptionObject
Expand Down
57 changes: 53 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<Buffer>((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
Expand Down Expand Up @@ -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 }
}

Expand Down
Loading