使用Gulp遍历目录?

36

我对 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文件。


gulp-folders 看起来是一个选项。 - Castro Roy
5个回答

47

这个有官方的配方:每个文件夹生成一个文件

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);
});

谢谢你指出这个问题。最终我做了类似的事情。 - Nathan Rutman
1
@NathanRutman 有没有可能让我看看你的 gulpfile.js。我遇到了同样的问题,不想重复造轮子 ;) - Paranoid Android
如果我想编译 scsssass 文件,这个能用吗? - SalahAdDin
我需要查询根文件夹,这段代码可以帮我实现。但是一开始我以为它会返回所有子文件夹,但实际上它只返回了根子文件夹。谢谢@ghidello。 - saber tabatabaee yazdi
fs包是必须在顶部引入的吗?它是内置于gulp中还是需要作为开发依赖项安装?谢谢。 - Stephanie Hobson
1
@StephanieHobson "fs" 是 Node.js 的文件系统模块,因此您无需安装它(就像“path”一样)。 - Ghidello

17

你可以使用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

我正在尝试理解Node中的流(Stream)是如何工作的。我为您制作了一个简单的示例,演示如何创建一个流来筛选文件夹并为它们启动一个新的给定流。

'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自定义流一样。

试试看,让我知道它是否适用于您。


0

首先,安装gulp-concatgulp-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
感谢 @OverZealous。这促使我重新阅读 gulp 的异步文档 - adamb
1
@adamb 这是我想要避免的方法...假设我有10或20个特征目录...如果可以避免,我不想写20个任务...有没有一种实用的方法来解决这种情况? - Nathan Rutman
2
这就是 gulp 命令式本质的好处所在:根据一组特征的唯一标识符数组编程生成任务...类似于这样。你可以采用这种方法,进一步自动加载相关目录名称等。 - adamb

0

我在使用gulp 4时遇到了麻烦,可能是因为我不想合并所有文件夹的输出。 我对食谱进行了调整,以生成(但不运行)每个文件夹的匿名函数,并返回函数数组以使它们能够被gulp.parallel处理 - 这样我生成的函数数量将是可变的。这种方法的关键在于:

每个生成的函数都需要是一个函数或组合(而不是流)。在我的情况下,每个生成的函数都是一个系列组合,因为我在构建每个模块文件夹时要做很多事情。
函数数组需要使用javascript apply()传递到我的构建任务中,因为在我的情况下,数组的每个成员都需要转换为gulp.parallel的参数。
以下是生成函数数组的函数摘录:
function getModuleFunctions() { //按照上面的步骤获取文件夹列表 - 在我的情况下,是一个名为modules的数组
//对于每个模块,返回一个函数或组合(在这种情况下是gulp.series)。 return modules.map(function (m) { var moduleDest = env.folder + 'modules/' + m; return gulp.series( //说明性函数...所有函数必须返回流或调用回调函数,但可以有任意数量的函数或组合(gulp.series或gulp.parallel) function () { return gulp.src('modules/' + m + '/img/*', { buffer: false }) .pipe(gulp.dest(moduleDest + '/img')); }, function (done) { console.log('In my function'); done(); } ); }); }
//说明性构建任务,运行两个命名任务,然后将上面生成的所有模块并行处理为gulp.parallel的动态参数,这是gulp 4的方式 gulp.task('build', gulp.series('clean', 'test', gulp.parallel.apply(gulp.parallel, getModuleFunctions())));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接