A Vite plugin to copy files with optional transformation and wildcard support
npm install @kpsoftec/vite-copy-pluginA Vite plugin to copy files with optional transformation and wildcard support, similar to copy-webpack-plugin.
- ✅ Copy files with wildcard patterns
- ✅ Transform file content during copy
- ✅ Development server support with live serving
- ✅ Production build integration
- ✅ Multiple wildcard types: *, ?, [abc], [a-z]
- ✅ TypeScript support with type definitions
- ✅ Robust error handling for undefined URLs
- ✅ Force file watching in development mode
``bash`
npm install @kpsoftec/vite-copy-plugin
`js
import { defineConfig } from 'vite'
import { copyPlugin } from '@kpsoftec/vite-copy-plugin'
export default defineConfig(({ mode }) => ({
plugins: [
copyPlugin([
{
from: 'src/configs/app-config.json',
to: 'configs/app-config.json',
transform: (content) => {
if (mode === 'production') return content
const config = JSON.parse(content)
return JSON.stringify({
...config,
apiUrl: config.apiUrl.replace('prod', 'dev')
}, null, 2)
}
}
])
]
}))
`
The plugin includes TypeScript definitions out of the box:
`typescript
import { copyPlugin, CopyPattern } from '@kpsoftec/vite-copy-plugin'
const patterns: CopyPattern[] = [
{
from: 'src/config.json',
to: 'config.json',
transform: (content: string) => content.toUpperCase()
}
]
export default defineConfig({
plugins: [copyPlugin(patterns)]
})
`
Version 1.0.1+ includes improved error handling:
- Handles undefined request URLs gracefully
- No more "Cannot read properties of undefined" errors
- Robust middleware implementation
- * - Matches any characters (zero or more)
- ? - Matches single character
- [abc] - Matches any character in brackets
- [a-z] - Matches character range
`js
import { copyPlugin } from '@kpsoftec/vite-copy-plugin'
copyPlugin([
// Copy single file
{
from: 'src/configs/app-config.json',
to: 'configs/app-config.json'
},
// Copy all JSON files ending with -config
{
from: 'src/configs/*-config.json',
to: 'configs/' // trailing slash = directory
},
// Copy all JSON files
{
from: 'src/configs/*.json',
to: 'configs/'
},
// Copy files with single character variation
{
from: 'src/data/file?.json', // file1.json, fileA.json
to: 'data/'
},
// Copy files matching character set
{
from: 'src/env/[123]-config.json', // 1-config.json, 2-config.json, 3-config.json
to: 'env/'
},
// Copy files matching character range
{
from: 'src/assets/[a-c]*.png', // a-logo.png, b-icon.png, c-banner.png
to: 'assets/'
}
])
`
Use the force property to enable file watching in development mode for real-time updates:
`js`
copyPlugin([
{
from: 'src/config.json',
to: 'config.json',
force: true, // Enable file watching
transform: (content) => {
const config = JSON.parse(content)
return JSON.stringify({ ...config, timestamp: Date.now() }, null, 2)
}
}
])
When to use force: true:
- Files that change frequently during development
- Configuration files that need live updates
- Files with dynamic content that should reflect immediately
Performance note: Only enable force for files that actually need watching to avoid unnecessary file system overhead.
`js`
{
from: 'src/config.json',
to: 'config.json',
transform: (content) => {
// Access to mode via closure or environment
if (process.env.NODE_ENV === 'production') {
return content // No transformation in production
}
// Transform for development
const config = JSON.parse(content)
return JSON.stringify({
...config,
debug: true,
apiUrl: 'http://localhost:3000'
}, null, 2)
}
}
`js
// Specific filename
{ from: 'src/file.json', to: 'output.json' }
// Directory (keeps original filenames)
{ from: 'src/*.json', to: 'configs/' }
// Nested directory
{ from: 'src/data/*.json', to: 'api/data/' }
`
- Development: Files are served dynamically via middleware
- Production: Files are copied to dist folder during build
- Transform: Applied in both modes (use mode check to skip in production)
`js
import { copyPlugin } from '@kpsoftec/vite-copy-plugin'
export default defineConfig(({ mode }) => ({
plugins: [
copyPlugin([
// Main app config with environment-specific transforms
{
from: 'src/configs/app-config.json',
to: 'configs/app-config.json',
transform: (content) => {
if (mode === 'production') return content
const config = JSON.parse(content)
return JSON.stringify({
...config,
clientId: config.clientId.replace('#client_id#', 'dev-client'),
env: config.env.replace('#client_env#', 'development'),
apiUrl: config.apiUrl.replace('prod-api', 'dev-api')
}, null, 2)
}
},
// Copy all environment-specific configs
{
from: 'src/configs/*-configs.json',
to: 'configs/'
},
// Copy locale files
{
from: 'src/locales/[a-z][a-z].json', // en.json, fr.json, etc.
to: 'locales/'
}
])
]
}))
`
- patterns: Array - Array of copy patterns
- from: string - Source file path (supports wildcards)string
- to: - Destination path (file or directory)(content: string) => string
- transform: - Optional transform functionboolean
- force: - Enable file watching in development mode (default: false)
| Pattern | Description | Example Matches |
|---------|-------------|----------------|
| *.json | Any JSON file | config.json, data.json |*-config.json
| | Files ending with -config | app-config.json, db-config.json |file?.txt
| | Single character variation | file1.txt, fileA.txt |[123].json
| | Character set | 1.json, 2.json, 3.json |[a-z]*.js
| | Character range + wildcard | a-script.js, b-module.js` |
MIT