108

I have a gulp task that is attempting to convert .scss files into .css files (using gulp-ruby-sass) and then place the resulting .css file into the same place it found the original file. The problem is, since I'm using a globbing pattern, I don't necessarily know where the original file is stored.

In the code below I'm trying to use gulp-tap to tap into the stream and figure out the file path of the current file the stream was read from:

gulp.task('convertSass', function() {
    var fileLocation = "";
    gulp.src("sass/**/*.scss")
        .pipe(sass())
        .pipe(tap(function(file,t){
            fileLocation = path.dirname(file.path);
            console.log(fileLocation);
        }))
        .pipe(gulp.dest(fileLocation));
});

Based on the output of the console.log(fileLocation), this code seems like it should work fine. However, the resulting CSS files seem to be placed one directory higher than I'm expecting. Where it should be project/sass/partials, the resulting file path is just project/partials.

If there's a much simplier way of doing this, I would definitely appreciate that solution even more. Thanks!

Dan-Nolan
  • 6,594
  • 4
  • 27
  • 32

5 Answers5

163

As you suspected, you are making this too complicated. The destination doesn't need to be dynamic as the globbed path is used for the dest as well. Simply pipe to the same base directory you're globbing the src from, in this case "sass":

gulp.src("sass/**/*.scss")
  .pipe(sass())
  .pipe(gulp.dest("sass"));

If your files do not have a common base and you need to pass an array of paths, this is no longer sufficient. In this case, you'd want to specify the base option.

var paths = [
  "sass/**/*.scss", 
  "vendor/sass/**/*.scss"
];
gulp.src(paths, {base: "./"})
  .pipe(sass())
  .pipe(gulp.dest("./"));
numbers1311407
  • 33,686
  • 9
  • 90
  • 92
  • Ah, awesome. Thank you. Is there also an easy way to use a glob for the source, but just put everything straight up in the `sass` folder? – Dan-Nolan Apr 23 '14 at 17:54
  • 2
    This didn't work for me. I had to do `gulp.src("dist/**/*")` ... `gulp.dest("./")` – niftygrifty Feb 09 '15 at 01:09
  • @Dan-Nolan one way of flattening the folder structure looks to be using [gulp-rename](https://github.com/hparra/gulp-rename), see [this question](http://stackoverflow.com/questions/24658011/can-you-remove-a-folder-structure-when-copying-files-in-gulp) – numbers1311407 Mar 23 '15 at 14:18
  • @niftygrifty According to [the docs](https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpdestpath-options) it *should* work in a normal situation. Files are written to their matching globbed path against a [calculated relative base](https://github.com/wearefractal/glob2base), in this case `sass`. Perhaps the sass plugin here is already modifying the paths? – numbers1311407 Mar 23 '15 at 14:26
  • 1
    But doesn't this save the file in /sass and not in the according subdirectory like /sass/any/where ? How do I make the files save in the globbed path? – Mark Sep 24 '15 at 09:15
  • @MonkeyKing gulp by default calculates the base as everything before the glob, then replicates the file structure of the glob when it writes. It won't flatten the structure. E.g. in this example `sass/foo/bar.scss` would be exported to `sass/foo/bar.css`. See [the docs](https://github.com/gulpjs/gulp/blob/master/docs/API.md#optionsbase) for more examples and the usage of options like `base`. – numbers1311407 Sep 24 '15 at 19:40
  • @numbers1311407 in my case it does not work, what am I missing? Here is my complete task: `gulp.task('theme-scripts-build', function () { return gulp.src([ 'app/View/Themed/**/*.js', '!app/View/Themed/**/bundle.theme.js' ], { base: "app/View/Themed" }) .pipe(plugins.stripDebug()) .pipe(plugins.concat('bundle.theme.js')) .pipe(plugins.uglify()) .pipe(gulp.dest('app/View/Themed')); });` I also tried variations like gulp.dest('app') and without setting the "base" option but the result is always the same: bundle.theme.js is saved in app/View/Themed/ – Mark Sep 25 '15 at 06:42
  • I think you might be confused with how `concat` works. In the example for this question, each file matched by the glob is transformed and written out *individually* to a matching path at the destination dir. `concat` on the other hand is taking every file matched by the glob and writing them *all to a single file*, independent of *any* of the paths matched by the glob. You might want to break that into separate tasks per theme instead of globbing, or there may be a way to rewrite this so it works, but as is it doesn't really make sense and is probably outside the scope of this question. – numbers1311407 Sep 25 '15 at 19:52
  • In any case though, `dest('wherever')` should work to designate where the final file goes. I just put together a very simple testing situation using the concat plugin to make sure I'm not lying, and works just fine. – numbers1311407 Sep 25 '15 at 19:54
72

This is simpler than numbers1311407 has led on. You don't need to specify the destination folder at all, simply use .. Also, be sure to set the base directory.

gulp.src("sass/**/*.scss", { base: "./" })
    .pipe(sass())
    .pipe(gulp.dest("."));
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • 8
    This is the right answer. If you're trying to preserve the destination structure (i.e., not flatten the structure), you *must* indicate the base directory in gulp.src. – Gui Ambros Jul 12 '15 at 01:21
  • 2
    When I try this, the files are saved in "/" and not under the globbed path. – Mark Sep 24 '15 at 09:20
  • 1
    What @GuiAmbros says is not true, at least not according to [the docs](https://github.com/gulpjs/gulp/blob/master/docs/API.md#optionsbase). The base, by default, is calculated to be everything before the globbed path. In my answer the base would be calculated to be `./sass`,but the question specifies that the output retains the `sass` dir, which is why it's repeated in the `dest`. This answer achieves the same result using the base option, but neither approach is wrong. – numbers1311407 Sep 24 '15 at 15:11
  • It's also notable that the OP's situation is probably not that common, at least for CSS processing, as typically you'd expect to export into a `css` directory or similar, not from `sass` to `sass`. In such cases the accepted answer is actually simpler than this alternative. – numbers1311407 Sep 24 '15 at 19:34
33
gulp.src("sass/**/*.scss")
  .pipe(sass())
  .pipe(gulp.dest(function(file) {
    return file.base;
  }));

Originally answer given here: https://stackoverflow.com/a/29817916/3834540.

I know this thread is old but it still shows up as the first result on google so I thought I might as well post the link here.

Community
  • 1
  • 1
bobbarebygg
  • 366
  • 3
  • 9
  • This thread is old but the answers are still correct, though I suppose this method is slightly DRYer (if slightly less efficient). The linked question, really, was an issue of using `dest` incorrectly. Sure the given solutions work, but doing it right the first time, simply replacing `dest('./')` with `dest('./images')`, would have achieved the same result. – numbers1311407 Nov 27 '15 at 00:31
  • The reason the other solution did not work for me was that I had an array inside gulp.src() e.g. gulp.src(['sass/**', 'common/sass/**']) and when I searched for the answer, this was the post I found. Should probably have made that clearer though – bobbarebygg Nov 27 '15 at 08:16
  • Makes sense. In your case the problem is that there's no common base for gulp to calculate. Your solution works, but the solution given by @NightOwl888 of specifying the base would have worked as well. Updating the accepted answer to include the case of having no common base. – numbers1311407 Nov 27 '15 at 18:02
  • This should be the accepted answer! Not the other ones, which are specific to only one file or to a base path. – MrCroft Jun 22 '18 at 05:51
0

This was very helpful!

gulp.task("default", function(){

    //sass
    gulp.watch([srcPath + '.scss', '!'+ srcPath +'min.scss']).on("change", function(file) {
         console.log("Compiling SASS File: " + file.path)
         return gulp.src(file.path, { base: "./" })
        .pipe(sass({style: 'compressed'}))
        .pipe(rename({suffix: '.min'}))
        .pipe(sourcemaps.init())
        .pipe(autoprefixer({
            browsers: ['last 2 versions'],
            cascade: false
        }))
        .pipe(sourcemaps.write('./'))         
        .pipe(gulp.dest(".")); 
    });

    //scripts
    gulp.watch([srcPath + '.js','!'+ srcPath + 'min.js']).on("change", function(file) {
        console.log("Compiling JS File: " + file.path)
        gulp.src(file.path, { base: "./" })
        .pipe(uglify())
        .pipe(rename({suffix: '.min'}))       
        .pipe(gulp.dest(".")); 
    });
})
mftohfa
  • 9
  • 2
0

if you want to save all files in their own path in the dist folder

const media = () => {
    return gulp.src('./src/assets/media/**/*')
        .pipe(gulp.dest(file => file.base.replace('src', 'dist'))
    )
}

const watch = () => {
  gulp.watch(
    "./src/**/*",
    media
  );
};
Joundill
  • 6,828
  • 12
  • 36
  • 50
Ayhanexe
  • 61
  • 5