gulp.src base option misbehaves with nested directories during gulp.series
0 reputation · 03 Dec 2020, 04:47 UTC
0 reputation · 03 Dec 2020, 04:47 UTC
When gulp.src is configured with a base option, the resulting file paths written by gulp.dest sometimes differ from expectations, especially when nested directories or gulp.series transformations are involved.
In practice, setting base: 'src' on a glob like src/**/*.js should preserve the relative structure under dist. However, if the source tree contains subfolders that are not part of the base, or if a stream step (e.g., gulp-rename) modifies a file’s path, the base may be lost or ignored. Additionally, gulp.watch that matches nested directories may default to the deepest matched folder as the base, altering the output hierarchy.
Given these nuances, the following uncertainties remain:
1. Does gulp retain the original base when a file passes through a transform that changes its path?
2. How does gulp.watch adjust the base when the glob includes nested directories?
3. If the base option is omitted, can we reliably predict the destination structure across different environments?
Gulp itself never "loses" the base — the base property lives on each vinyl file object and survives the stream unless a plugin or your own code rewrites file.path or file.base. Almost every case of "base misbehaving" is one of three things: a transform that changes file.path (which changes the path relative to the unchanged base), a glob whose implicit base isn't what you assumed, or a watch task that re-runs gulp.src with a different pattern than the original build.
Yes. gulp.dest writes each file to dest + (file.path − file.base). Plugins like gulp-rename modify file.path but leave file.base alone, so the renamed file is still placed relative to the original base. What changes is the relative portion: renaming src/a/b.js to src/a/c.js still lands at dist/a/c.js when base: 'src'. The structure only breaks when a plugin (or hand-rolled through2 code) sets file.path to something outside the base — then the relative calculation produces ../ segments or flattened output. The confirmed fact: base is sticky; the likely explanation for your drift is a path rewrite, not base loss.
gulp.watch itself doesn't compute a base — the base is computed inside gulp.src each time the watched task runs. If your task uses the same static glob (src/**/*.js with base: 'src'), the base is identical on every trigger. The "deepest matched folder" behavior appears when the base option is omitted: gulp (via vinyl-fs/glob-stream) derives the base from the portion of the glob before the first wildcard. So src/**/*.js implies base src, but src/components/**/*.js implies src/components — and a watch task that passes a narrower glob than the initial build will silently re-root the output for changed files only.
Only if the glob never changes. The implicit base is purely a function of the glob string, not the environment, so it is portable — but it is fragile: anyone who narrows the glob (a watch task, a one-off build of a subdirectory) changes the output tree. For any project with nested sources, set base explicitly everywhere the files are sourced.
{ base: 'src' } in every gulp.src call, including the one inside the watch-triggered task.const through2 = require('through2');
function logVinyl() {
return through2.obj((file, _, cb) => {
console.log('base:', file.base, '| path:', file.path);
cb(null, file);
});
}
exports.build = () =>
gulp.src('src/**/*.js', { base: 'src' })
.pipe(logVinyl())
.pipe(gulp.dest('dist'));Run npx gulp build and confirm each logged base ends in src and each path starts with it. If a rename plugin is in the chain, place logVinyl() after it to see exactly what changed.
This describes Gulp 4.x / vinyl-fs behavior; Gulp 3.x glob expansion differs in edge cases, so verify against your installed version (npx gulp --version). Avoid absolute paths in base — they make builds OS-dependent. If your output is still wrong after these checks, the one detail worth capturing is the logged base/path pair immediately before gulp.dest; that pinpoints which step rewrote the path.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.