【问题标题】:Iterating over directories with Gulp?用 Gulp 遍历目录?
【发布时间】:2014-04-04 16:33:54
【问题描述】:

我是 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 个文件,第二个包含最后两个文件。

这可能吗,还是我必须手动将这些目录添加到清单中?务实地遍历/js/ 中的所有目录会非常好。

感谢您能给我的任何帮助。

-内特

编辑: 需要注意的是,我不仅有 2 个目录,而且有很多(可能 10-20 个)所以我真的不想为每个目录编写一个任务.我想以相同的方式处理每个目录:获取其中的所有 JS(以及任何子目录)并将其编译为基于特征的缩小 JS 文件。

【问题讨论】:

标签: javascript gulp


【解决方案1】:

有一个官方配方: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);
});

【讨论】:

  • 感谢您指出这一点。我最终做了非常相似的事情。
  • @NathanRutman 有机会看到你的gulpfile.js。我有同样的问题,我不想重新发明轮子;)
  • 如果我想编译 scsssass 文件,这行得通吗?
  • 我需要查询根文件夹,这段代码为我做这件事。但首先我认为它返回了所有子子文件夹,但它只返回了根子文件夹。谢谢@ghidello
  • @StephanieHobson "fs" 是 nodejs 文件系统模块,所以你不需要安装它(比如 "path")
【解决方案2】:

您可以使用glob 获取目录列表并对其进行迭代,使用gulp.src 为每个功能创建单独的管道。然后,您可以返回一个承诺,当您的所有流都具有 ended 时,该承诺将被解决。

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

【讨论】:

    【解决方案3】:

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

    '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 自定义流所做的那样。

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

    【讨论】:

      【解决方案4】:

      首先,安装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
      

      【讨论】:

      • 你需要return来自你的两个任务的管道,否则它们将同步运行,这意味着它们将在任务实际完成之前返回。只需在两者中的gulp.src 之前添加一个return
      • 感谢@OverZealous。这促使我重新阅读gulp's async documentation
      • @adamb 这是我想要避免的那种方法......假设我有 10 或 20 个功能目录......如果可以避免的话,我不想写 20 个任务...... .有没有办法务实地做这种事情?
      • 这就是 gulp 的命令式性质派上用场的地方:以编程方式基于功能的唯一标识符数组生成任务...Something like this。您可以根据需要采用这种方法,例如以编程方式加载有问题的目录名称。
      【解决方案5】:

      我在使用 gulp 配方时遇到了问题,可能是因为我使用的是 gulp 4 和/或因为我不想合并所有文件夹的输出。 我调整了配方,为每个文件夹生成(但不运行)一个匿名函数,并返回函数数组以使它们能够被 gulp.parallel 处理——在某种程度上,我将生成的函数数量是可变的。这种方法的关键是:

      1. 每个生成的函数都必须是函数或组合(而不是流)。就我而言,每个生成的函数都是一个系列组合,因为我在构建每个模块文件夹时会做很多事情。

      2. 函数数组需要使用 javascript apply() 传递到我的构建任务中,因为在我的例子中,数组的每个成员都需要转换为 gulp.parallel 的参数。 生成函数数组的函数摘录:

        function getModuleFunctions() {
            //Get list of folders as per recipe above - in my case an array named modules
        
            //For each module return a function or composition (gulp.series in this case).
            return modules.map(function (m) {
                var moduleDest = env.folder + 'modules/' + m;
                return gulp.series(
                    //Illustrative functions... all must return a stream or call callback but you can have as many functions or compositions (gulp.series or gulp.parallel) as desired
                    function () {
                        return gulp.src('modules/' + m + '/img/*', { buffer: false })
                            .pipe(gulp.dest(moduleDest + '/img'));
                    },
                    function (done) {
                        console.log('In my function');
                        done();
                    }
                );
            });
        }
        
        //Illustrative build task, running two named tasks then processing all modules generated above in parallel as dynamic arguments to gulp.parallel, the gulp 4 way
        gulp.task('build', gulp.series('clean', 'test', gulp.parallel.apply(gulp.parallel, getModuleFunctions())));  
        

        `

      【讨论】:

        猜你喜欢
        • 2016-07-24
        • 1970-01-01
        • 2018-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-04
        相关资源
        最近更新 更多