2

I am using Gulp to store multiple SVG files into SVG storages which are later reused in order to maximize performance. However, I am now using a rather interesting folder structure where the paths contain interchangeable fixed and dynamic parts.

Let me illustrate. Here is the folder structure I am using. The app/images/products folder contains folders named productA, productB etc. which again contain a subfolder called color-sprites full of SVG files ready to get combined into a single file and stored in build/images/products/{product name}/color-sprites.svg.

root/
    |_ gulpfile.js
    |_ app 
        |_ images
            |_ products
                |_ **productA**
                    |_ color-sprites
                        |_ sprite1.svg
                        |_ sprite2.svg
                        |_ ...
    |_ build
        |_ images
            |_ products
                |_ **productA**
                    |_ color-sprites.svg

Here is a simplified version of the code I am trying to use to accomplish what I need (take note that rename is an instance of gulp-rename).

gulp.task('svg-color-sprites', function () {
    return gulp.src('app/images/products/**/color-sprites/*.+(svg)')
        .pipe(svgMin())
        .pipe(svgStore())
        .pipe(rename(...))
        .pipe(gulp.dest('build/images/'));
});

The problem is that I am not exactly sure how to access current stream parameters in order to construct a target with gulp-rename because running the gulpfile.js like this results in taking the first parent element of the path before * or ** which again results in creating a file called products.svg in build/images/. I've seen a couple of examples which use path to access the basename, relative path etc. but I am not sure how to use it in the context of gulp streams.

1 Answers1

0

The way you're doing things now will create one combined SVG for all of your SVGs, not one combined SVG per product. In fact if you have two files like this:

productA/color-sprites/sprite1.png
productB/color-sprites/sprite1.png

the whole thing will fail because gulp-svgstore expects file names to be unique.

What you need to do is have one gulp stream per product that each generates one combined SVG.

That means you need to iterate over all the directories in your products folder, initialize one stream per directory, then merge them so you can return one single stream from your task.

The easiest way to get all the directories in your products folder is to use glob and merging streams is made really simple with merge-stream.

var glob = require('glob');
var merge = require('merge-stream');
var path = require('path');

gulp.task('svg-color-sprites', function () {
  return merge(glob.sync('app/images/products/*').map(function(productDir) {
    var product = path.basename(productDir);
    return gulp.src(productDir + '/color-sprites/*.+(svg)')
      .pipe(svgMin())
      .pipe(svgStore())
      .pipe(gulp.dest('build/images/products/' + product));
  }));
});

Since gulp-svgstore automatically names the resulting combined SVG after the base folder you don't even need to use gulp-rename at all. The combined SVG file will automatically be named color-sprites.svg.

Sven Schoenung
  • 30,224
  • 8
  • 65
  • 70
  • A lot of useful info here. I even slipped off my mind that `gulp-svgstore` puts everything into one destination file. I'll have to try this out first. If it checks out I'll make it an accepted answer. Many thanks. –  Sep 24 '16 at 12:20
  • Everything works fine except the results are stored in the wrong place because they include the whole base path (i.e. `build/images/products/app/images/products/productA/color-sprites.svg`). I understand why it's happening (the resulting individual path is just added on top of the `gulp.src` base path) but I don't know how to change those in a merged stream. –  Sep 24 '16 at 15:05
  • 1
    Oops, you're right. The problem was that the `product` variable contained the entire path (`app/images/products/productA`) instead of only the last directory (`productA`). Fixed it by using [`path.basename()`](https://nodejs.org/api/path.html#path_path_basename_path_ext). – Sven Schoenung Sep 24 '16 at 15:19
  • As a matter of fact I already did the exact same thing because `path` was already used in several other places. Works as expected. Accepted answer. Thank you again! –  Sep 24 '16 at 15:35
  • For some odd reason the generated `color-sprites.svg` files contain just ``. I've tested all the paths with `gulp-print` and everything checks out, however the destination file still contains no source SVG files. The only thing that comes to my mind is a potential issue with `merge-stream` but I really don't have any experience with it. –  Sep 24 '16 at 15:59
  • 1
    `merge-stream` doesn't alter file contents, so that can't be the cause. No idea what could be causing this though. When I run the code in my answer the resulting `color-sprites.svg` files look fine. Maybe a problem with `gulp-svgstore` and the specific SVGs you're using? – Sven Schoenung Sep 24 '16 at 16:10
  • Well I use `gulp-svgstore` a lot and honestly this is the first time I've seen this kind of behavior. Since I am not exactly familiar with all the nooks and crannies of node.js and Vinyl my natural reaction to the code is "it must be something from the new code". Anyway, my current issue is out of the scope of the original question so I'll either try to figure it out by myself or simply raise a new question. –  Sep 24 '16 at 16:16
  • Never mind, I am stupid. My `gulp.watch` paths weren't in sync with the watched resources. –  Sep 24 '16 at 16:33