rollup-plugin-smart-cache
v1.0.0
Published
Rollup plugin with persistent hash-based cache that skips bundling when inputs haven't changed
Maintainers
Readme
rollup-plugin-smart-cache
A Rollup plugin that uses persistent hash-based cache to completely skip bundling when inputs haven't changed. Perfect for large projects that need fast incremental builds.
Why This Exists
Traditional build caches (like timestamp-based) still execute Rollup partially, which can be slow for large projects. This plugin computes a deterministic hash of all inputs and completely skips Rollup execution when the hash matches a cached build, dramatically reducing build times for large codebases.
Installation
npm install --save-dev rollup-plugin-smart-cacheBasic Usage
import { smartCache } from 'rollup-plugin-smart-cache'
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'es',
},
plugins: [
smartCache({
inputs: ['src/**/*', 'package.json'],
ignore: ['node_modules/**', 'dist/**'],
env: ['NODE_ENV'],
}),
],
}API Reference
smartCache(options)
Options
inputs(required):string[]- Glob patterns for files to include in hash calculationcacheDir(optional):string- Cache directory (default:'.rollup-smart-cache')ignore(optional):(string | RegExp)[]- Files/directories to ignoreenv(optional):string[]- Environment variables that affect the buildplatform(optional):boolean- Include platform in hash (default:false)node(optional):boolean- Include Node version in hash (default:false)debug(optional):boolean- Enable debug logging (default:false)legacyCacheDir(optional):string- Migrate from existing cache directorylockTimeout(optional):number- Lock timeout in milliseconds (default:300000= 5 minutes)
Rules
inputsis mandatory - no magic defaults- No callbacks or dynamic hash logic
- Defaults are conservative (fail-safe)
- All paths normalized for cross-platform compatibility
lockTimeoutconfigurable for large builds (default: 5 minutes)
Presets
Basic Preset
Simple single-bundle setup:
import { basic } from 'rollup-plugin-smart-cache/presets'
export default {
plugins: [basic()],
}Multi-Bundle Preset
For projects with multiple Rollup configs:
import { multiBundle } from 'rollup-plugin-smart-cache/presets'
export default {
plugins: [multiBundle()],
}How Hashing Works
The plugin computes a SHA-256 hash of:
- File contents: Normalized for CRLF/LF differences (cross-platform consistency)
- File paths: Normalized to POSIX format (forward slashes)
- File sizes: Included as metadata
- Optional metadata:
- Node version (if
node: true) - Platform (if
platform: true) - Environment variables (from
envoption)
- Node version (if
Files are sorted deterministically (case-insensitive alphabetical) to ensure order-independent hashing.
Cache Invalidation Rules
Cache is invalidated when:
- Input file contents change
- Input files are added/removed
- Environment variables change (if specified in
env) - Node version changes (if
node: true) - Platform changes (if
platform: true) - Cache metadata doesn't match
- Output files are missing or corrupted
Debugging Guide
Enable debug mode to see detailed information:
smartCache({
inputs: ['src/**/*'],
debug: true,
})Debug output includes:
- Hash computation details
- Files included/excluded
- Cache hit/miss reason
- Invalidation reason
- Lock acquisition/release
- Performance metrics (hash time, lookup time, write time, time saved)
When NOT to Use
The plugin automatically disables in unsafe scenarios:
- Watch mode: Detected via
this.meta.watchMode - Multiple output formats: Different formats can produce different outputs
- Non-deterministic plugins: Blacklist includes
rollup-plugin-replacewith timestamps - Capacitor builds: Detected via
CAPACITOR_PLATFORM,--capacitorflag, orcapacitor.config.json
In these cases, the plugin logs a warning and allows normal Rollup execution.
Migration from Timestamp-Based Cache
The plugin detects legacy timestamp-based cache and invalidates it gracefully on first run:
- Detects existence of output directories without smart cache
- Removes legacy outputs to ensure clean state
- Next build uses smart cache
For explicit migration, use legacyCacheDir:
smartCache({
inputs: ['src/**/*'],
legacyCacheDir: '.old-cache',
})Integration with NPM Scripts
Add to your package.json:
{
"scripts": {
"build": "rollup -c",
"build:cached": "rollup -c --plugin smart-cache",
"clean:smart-cache": "rimraf .rollup-smart-cache"
}
}Troubleshooting
Cache not working
- Check debug logs:
debug: true - Verify inputs include all relevant files
- Check for unsafe conditions (watch mode, etc.)
- Ensure cache directory is writable
Wrong cache hit
- Verify ignore patterns exclude outputs
- Check environment variables are included if they affect build
- Ensure platform/node options match your needs
Performance issues
- Reduce number of input files (better ignore patterns)
- Increase
lockTimeoutfor large builds - Check disk I/O performance
Performance Tips
Expected Performance Gains
Performance metrics based on EdenwareApps/Megacubo project:
- Full build: 45-60 seconds
- Cache hit: 3-8 seconds (file writing only)
- Time saved: ~85-90%
- Comparison: Superior to timestamp-based cache that still executes Rollup partially
Optimization Tips
- Minimize inputs: Only include files that affect the build
- Use ignore patterns: Exclude outputs, node_modules, temp files
- Environment variables: Only include vars that actually affect output
- Platform/node hashing: Only enable if builds differ between platforms/Node versions
License
MIT
