2014-03-03 96 views
26

我是gulp的新手,但我想知道是否可以遍历吞噬任务中的目录。用Gulp遍历目录?

下面是我的意思,我知道很多教程/演示显示使用类似“**/*。js”的方式处理一堆JavaScript文件,然后将它们编译成单个JavaScript文件。但是我想迭代一组目录,并将每个目录编译到它自己的JS文件中。

举例来说,我有这样的文件结构:

/js/feature1/something.js 
/js/feature1/else.js 
/js/feature1/foo/bar.js 
/js/feature1/foo/bar2.js 
/js/feature2/another-thing.js 
/js/feature2/yet-again.js 

......我想两个文件:/js/feature1/feature1.min.js/js/feature2/feature2.min.js其中首先包含4个文件,第二个包含最后2个文件。

这是可能的,还是我将不得不手动添加这些目录到清单?实际上迭代/js/内的所有目录将是非常好的。

感谢您给我的任何帮助。

-Nate

编辑:应当指出的是,我不仅有2个目录,但我有很多(也许10-20),所以我真的不希望写一个任务每个目录。我想以相同的方式处理每个目录:获取其中的所有JS(以及任何子目录)并将其编译为基于特征的缩小JS文件。

+0

[吞掉文件夹(https://www.npmjs.com/package/gulp-folders)似乎是一个选项 –

回答

37

有这种正式的食谱:Generating a file per folder

var fs = require('fs'); 
var path = require('path'); 
var merge = require('merge-stream'); 
var gulp = require('gulp'); 
var concat = require('gulp-concat'); 
var rename = require('gulp-rename'); 
var uglify = require('gulp-uglify'); 

var scriptsPath = 'src/scripts'; 

function getFolders(dir) { 
    return fs.readdirSync(dir) 
     .filter(function(file) { 
     return fs.statSync(path.join(dir, file)).isDirectory(); 
     }); 
} 

gulp.task('scripts', function() { 
    var folders = getFolders(scriptsPath); 

    var tasks = folders.map(function(folder) { 
     return gulp.src(path.join(scriptsPath, folder, '/**/*.js')) 
     // concat into foldername.js 
     .pipe(concat(folder + '.js')) 
     // write to output 
     .pipe(gulp.dest(scriptsPath)) 
     // minify 
     .pipe(uglify())  
     // rename to folder.min.js 
     .pipe(rename(folder + '.min.js')) 
     // write to output again 
     .pipe(gulp.dest(scriptsPath));  
    }); 

    // process all remaining files in scriptsPath root into main.js and main.min.js files 
    var root = gulp.src(path.join(scriptsPath, '/*.js')) 
     .pipe(concat('main.js')) 
     .pipe(gulp.dest(scriptsPath)) 
     .pipe(uglify()) 
     .pipe(rename('main.min.js')) 
     .pipe(gulp.dest(scriptsPath)); 

    return merge(tasks, root); 
}); 
+0

谢谢你指出这一点。我结束了一些非常相似的事情。 –

+0

@NathanRutman有机会看到你的'gulpfile.js'。我有同样的问题,我不想重新发明车轮;) – Mirko

+0

这是否工作,如果我想编译'scss'和'sass'文件? – SalahAdDin

0

首先,安装gulp-concat & gulp-uglify

$ npm install gulp-concat 
$ npm install gulp-uglify 

接下来,做这样的事情:

//task for building feature1 
gulp.task('minify-feature1', function() { 
return gulp.src('/js/feature1/*') 
    .pipe(uglify()) //minify feature1 stuff 
    .pipe(concat('feature1.min.js')) //concat into single file 
    .pipe(gulp.dest('/js/feature1')); //output to dir 
}); 

//task for building feature2 
gulp.task('minify-feature2', function() { //do the same for feature2 
return gulp.src('/js/feature2/*') 
    .pipe(uglify()) 
    .pipe(concat('feature2.min.js')) 
    .pipe(gulp.dest('/js/feature2')); 
}); 

//generic task for minifying features 
gulp.task('minify-features', ['minify-feature1', 'minify-feature2']); 

现在,所有你需要做的,从CLI运行如下的一切是:

$ gulp minify-features 
+1

你需要'return'来自两个任务的管道,否则它们将同步运行,这意味着它们将在任务实际完成之前返回*。只需在'gulp.src'之前添加'return'即可。 – OverZealous

+0

谢谢@OverZealous。这促使我重新阅读[gulp的异步文档](https://github.com/gulpjs/gulp/blob/master/docs/API.md#async-task-support)。 – adamb

+1

@adamb这是我想避免的那种方法...说我有10或20个功能目录...我不想写20个任务,如果我能避免它...有没有办法做这种事情务实? –

15

你可以使用glob获取列表的目录并迭代它们,使用gulp.src为每个特征创建一个单独的管道。然后,您可以返回一个承诺,当您的所有流都有end版本时,该承诺将被解决。

var fs = require('fs'); 
var Q = require('q'); 
var gulp = require('gulp'); 
var glob = require('glob'); 

gulp.task('minify-features', function() { 
    var promises = []; 

    glob.sync('/js/features/*').forEach(function(filePath) { 
    if (fs.statSync(filePath).isDirectory()) { 
     var defer = Q.defer(); 
     var pipeline = gulp.src(filePath + '/**/*.js') 
     .pipe(uglify()) 
     .pipe(concat(path.basename(filePath) + '.min.js')) 
     .pipe(gulp.dest(filePath)); 
     pipeline.on('end', function() { 
     defer.resolve(); 
     }); 
     promises.push(defer.promise); 
    } 
    }); 

    return Q.all(promises); 
}); 
4

我正在尝试自己弄清流在节点中的工作方式。 我为你做了一个简单的例子,介绍如何制作一个流来过滤文件夹并为它们开启一个新的给定流。

'use strict'; 

var gulp    = require('gulp'), 
    es    = require('event-stream'), 
    log    = require('consologger'); 

// make a simple 'stream' that prints the path of whatever file it gets into 
var printFileNames = function(){ 

    return es.map(function(data, cb){ 

     log.data(data.path); 
     cb(null, data); 
    }); 
}; 

// make a stream that identifies if the given 'file' is a directory, and if so 
// it pipelines it with the stream given 
var forEachFolder = function(stream){ 

    return es.map(function(data, cb){ 

     if(data.isDirectory()){ 

      var pathToPass = data.path+'/*.*'; // change it to *.js if you want only js files for example 

      log.info('Piping files found in '+pathToPass); 

      if(stream !== undefined){ 
       gulp.src([pathToPass]) 
       .pipe(stream()); 
      } 
     } 

     cb(null, data); 
    }); 
}; 


// let's make a dummy task to test our streams 
gulp.task('dummy', function(){ 
    // load some folder with some subfolders inside 
    gulp.src('js/*') 
    .pipe(forEachFolder(printFileNames)); 
    // we should see all the file paths printed in the terminal 
}); 
你的情况

所以,你可以用你想用一个文件夹中的文件(如它们最小化和将它们连接起来),然后通过该流的一个实例到forEachFolder流我不管流制作。就像我对printFileNames自定义流一样。

试一试,让我知道它是否适合你。