Modern, production-grade Gulp plugin for Rollup
gulp-rollup-2 is a ground-up rewrite for Rollup v3+ (fully tested with v4), delivering robust behavior in caching, sourcemap handling, and multi-output scenarios. This package aims to overcome limitations of legacy gulp-rollup / rollup-stream approaches.
- ✅ Rollup 3.x / 4.x compatibility - Fully tested with latest Rollup
- ✅ Native Rollup API in Gulp
pipe()chains - ✅ Multiple output formats - ES, CJS, UMD, IIFE, AMD, System
- ✅ Production-grade caching - Intelligent incremental builds with
object-hash - ✅ Duplicate detection - Prevents configuration conflicts automatically
- ✅ Memory-safe - Automatic bundle cleanup, no leaks
- ✅ Sourcemap intelligence - Secure merge & fallback handling
- ✅ Dual modes - Use with
gulp.src()or standalonesrc()factory - ✅ Deterministic builds - No streaming, predictable output
- Node.js >= 18.0.0 (recommended: latest LTS)
- Gulp >= 4.0.0
- Rollup >= 4.0.0 (tested with 4.x)
npm install --save-dev gulp-rollup-2 rollupThe most common usage scenario:
const gulp = require('gulp');
const rollup2 = require('gulp-rollup-2');
const resolve = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
gulp.task('bundle', () =>
gulp
.src('src/index.js')
.pipe(
rollup2.rollup({
plugins: [resolve(), commonjs()],
output: {
file: 'bundle.js',
format: 'iife',
name: 'App',
sourcemap: true,
},
})
)
.pipe(gulp.dest('dist'))
);Generate multiple formats from a single input:
.pipe(rollup2.rollup({
plugins: [resolve(), commonjs()],
output: [
{ file: 'app.esm.js', format: 'es', sourcemap: true },
{ file: 'app.umd.js', format: 'umd', name: 'App', sourcemap: true },
{ file: 'app.cjs.js', format: 'cjs', sourcemap: true }
]
}))Important: Output files must be unique. Duplicate output files will throw an error.
gulp-rollup-2 leverages Rollup's native caching mechanism with enhanced reliability:
- Cache keys are generated using
object-hashfor stability - Incremental builds reuse cached AST when input configuration matches
- Automatic invalidation when configuration changes
const { watch } = require('gulp');
function bundle() {
return gulp
.src('src/**/*.js')
.pipe(
rollup2.rollup({
input: 'src/index.js',
cache: true, // Enable Rollup's cache
plugins: [resolve(), commonjs()],
output: {
file: 'bundle.js',
format: 'umd',
name: 'MyLib',
},
})
)
.pipe(gulp.dest('dist'));
}
// Watch mode benefits from caching
watch('src/**/*.js', bundle);- ✅ Stable cache keys using
object-hashalgorithm - ✅ Duplicate detection prevents conflicting configurations
- ✅ Memory management with automatic
bundle.close()
If your Rollup plugins have dynamic behavior:
rollup2.rollup({
cache: false, // Disable caching
plugins: [...]
})Note: Some Rollup plugins may behave differently with the same name but different configurations. This edge case is intentionally kept simple.
Sourcemap handling is production-grade:
- ✅ Rollup-first: If Rollup generates
output.map, it's used directly - ✅ Fallback support: If no Rollup map, upstream Gulp sourcemaps are preserved
- ✅ Path correction: Source paths are automatically resolved
This ensures seamless integration with:
gulp-sourcemaps- Transpiler chains (Babel, TypeScript, etc.)
- Multi-stage build pipelines
const sourcemaps = require('gulp-sourcemaps');
gulp.task('bundle', () =>
gulp
.src('src/**/*.js')
.pipe(sourcemaps.init())
.pipe(
rollup2.rollup({
input: 'src/index.js',
output: {
file: 'bundle.js',
format: 'umd',
name: 'App',
sourcemap: true, // Rollup generates sourcemap
},
})
)
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('dist'))
);For builds outside the Gulp graph:
- No
gulp.src()required - Async factory pattern
- Ideal for: Multi-entry scenarios, CI/CD pipelines
const rollup2 = require('gulp-rollup-2');
const { dest } = require('gulp');
(async () => {
const stream = await rollup2.src({
input: 'src/index.js',
plugins: [resolve(), commonjs()],
output: {
file: 'bundle.js',
format: 'es',
sourcemap: true,
},
});
stream.pipe(dest('dist'));
})();Prevents accidental configuration conflicts:
// ❌ This will throw an error:
rollup2.rollup([
{
input: 'src/app.js',
plugins: [resolve()],
output: { file: 'bundle1.js', format: 'umd' },
},
{
input: 'src/app.js',
plugins: [resolve()], // Same config!
output: { file: 'bundle2.js', format: 'umd' },
},
]);
// Error: gulp-rollup-2: Duplicate input configurationsPrevents multiple outputs targeting the same file:
// ❌ This will throw an error:
rollup2.rollup({
input: 'src/app.js',
output: [
{ file: 'bundle.js', format: 'umd' },
{ file: 'bundle.js', format: 'es' }, // Same file!
],
});
// Error: gulp-rollup-2: Multiple outputs target the same fileThe following are intentionally not supported:
- ❌ Streaming input (
file.isStream()) - ❌ Rollup v1 / v2
These constraints are deliberate design decisions for reliability and predictability.
This plugin:
- ✅ No magic - Transparent Rollup integration
- ✅ Doesn't hide Rollup behavior - Native API exposed
- ✅ Deterministic builds - Predictable, reproducible outputs
- ✅ Production-ready - Battle-tested in CI/CD environments
If your goals are:
- Modern Rollup integration
- Robust build outputs
- Production CI reliability
Then gulp-rollup-2 is the right tool.
Use inside a Gulp pipeline.
Parameters:
config(Object | Array | String) - Rollup configuration- Object: Single Rollup config
- Array: Multiple Rollup configs
- String: Format shorthand (e.g.,
'umd','es')
Returns: Transform stream
Standalone bundle factory (async).
Parameters:
config(Object | Array) - Rollup configurationconfig.input(String) - Required - Entry point
Returns: Promise<Stream>
- Production-grade caching: Improved cache system using
object-hashfor reliable cache key generation - Duplicate detection: Automatic detection and prevention of duplicate input configurations
- Duplicate output detection: Prevents multiple outputs targeting the same file
- Memory leak prevention: Automatic
bundle.close()after each build
- Fixed sourcemap paths: Corrected sourcemap path resolution for accurate debugging
- Better error messages: More descriptive errors for configuration issues
- Deep equality checks: Proper configuration comparison using deep equality
- Modern async/await patterns throughout
- Replaced custom equality with robust deep equality checking
- Better memory management with Map-based caching
- Added
object-hashdependency for stable cache keys
- Updated config files to latest standards
- Improved development workflow
- Better code quality tools
- Updated SEO-friendly package description
- Updated to Rollup 4.x
- Node.js 18+ support
- Modernized dependencies
- Added GitHub Actions CI
- Improved code quality with Prettier & ESLint
No breaking changes! v2.1.0 is fully backward compatible.
What's New:
- Automatic duplicate detection (will catch configuration errors early)
- Improved caching reliability
- Better memory management
- Fixed sourcemap paths
Action Required:
- ✅ None! Just upgrade:
npm install gulp-rollup-2@latest ⚠️ If you have duplicate configurations, they will now throw errors (this is intentional!)
If you experience unexpected caching behavior:
rollup2.rollup({
input: 'src/app.js',
cache: false, // Disable cache temporarily
plugins: [...],
output: { file: 'bundle.js', format: 'umd' }
})Check that:
- Input configurations are unique (different
input,external, ortreeshakeoptions) - Output files have unique paths
v2.1.0 automatically calls bundle.close() to prevent memory leaks. If you still experience issues, please open an issue.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT © Orçun Saltık
Orçun Saltık
- GitHub: @orcunsaltik
- Email: saltikorcun@gmail.com
Made with care for the Gulp + Rollup community 🚀