在一个管道中定义的gulp var在另一个管道中未定义

问题描述:

我正在使用gulp来处理网站的页面,其中一些页面是php文件。问题是,在所有页面通过模板引擎运行后,它们的文件扩展名为.html。我将一个属性添加到文件中,指定它是否应该是除html之外的文件,然后重命名文件以匹配。但是,由于某种原因,gulp-rename一直说我用来存储扩展名的变量是undefined。在gulpfile.js在一个管道中定义的gulp var在另一个管道中未定义

相应的任务:

var gulp   = require('gulp'), 
    gutil  = require('gulp-util'), 
    lodash  = require('lodash'), 
    data   = require('gulp-data'), 
    filesize  = require('gulp-filesize'), 
    frontMatter = require('gulp-front-matter'), 
    rename  = require('gulp-rename'), 
    util   = require('util');  


gulp.task('metalsmith', function(){ 
var ext;      //Variable to store file extension 
return gulp.src(CONTENT_DIR) 
    .pipe(frontMatter()).on("data", function(file){ 
     lodash.assign(file, file.frontMatter); 
     delete file.frontMatter; 
    }) 
    .pipe(data(function(file){     //ext is defined here 
     if(typeof file.filetype === 'undefined'){ 
      ext = {extname: '.html'}; 
     }else{ 
      ext = {extname: file.filetype}; 
     } 
    })) 
    .pipe(tap(function(file){ 
     console.log(ext);  //when I print to the console, ext is defined and correct 
    })) 
    .pipe(rename(ext)) //ext is undefined 
    .pipe(gulp.dest(BUILD_DIR)) 
}); 
当我 Unsupported renaming parameter type supplied运行它上面的错误

另外我试图具有它选项OBJ上的同一行rename(),与ext仅存储该文件的扩展名例如:.pipe(rename({extname: ext}))这使得文件已经未定义添加作为扩展名(代替phpfile.php下面md文件将是命名phpfileundefined

YAML在phpfile.md

--- 
layout: php.hbt 
filetype: ".php" 
title: "php" 
--- 

的package.json

"devDependencies": { 
    "gulp": "^3.9.1", 
    "gulp-data": "^1.2.1", 
    "gulp-filter": "^4.0.0", 
    "gulp-front-matter": "^1.3.0", 
    "gulp-rename": "^1.2.2", 
    "gulp-util": "^3.0.7", 
    "lodash": "^4.11.1" 
    } 
+0

1)您的标题说,'ext'在某些时候和不确定的定义在另一个。这些是什么? 2)在这个任务中有很多事情要做,并且没有通读每个插件的文档,我们不知道是否有任何促成因素的语法错误等等。是否有可能把这个任务削减到更小的东西,仍然给你错误,还是它们都是产生错误的关键所在? – henry

+1

我编辑了我的问题,在相关的部分包括了评论,我也拿出了不必要的代码,并澄清了我拥有的确切问题 –

+0

太棒了。你可以添加你的gulpfile的'require'部分吗? – henry

你的问题是,你的时间执行rename(ext)ext值仍然undefined因为你data(...)代码尚未运行。

咕嘟咕嘟插件的工作是这样的:

  1. 你调用插件功能,并将它传递任何必要的参数。在你的情况下rename(ext)
  2. 插件函数返回一个duplex stream
  3. 您传递全双工流.pipe()
  4. 只有所有.pipe()调用被执行并您流开始运行后

所以rename(ext)是用来函数调用构造流本身。只有在流构建之后,流才能开始运行

但是,只有在流正在运行时才设置值ext。当您构建流时,您需要ext之前的值

您的情况最简单的解决方案是简单地在您的data(...)函数中手动重命名,而不是依靠gulp-rename。您可以使用Node.js的内置path模块为(这是什么gulp-rename引擎盖下使用):

var path = require('path'); 

gulp.task('metalsmith', function(){ 
    return gulp.src(CONTENT_DIR) 
    .pipe(frontMatter()).on("data", function(file){ 
     lodash.assign(file, file.frontMatter); 
     delete file.frontMatter; 
    }) 
    .pipe(data(function(file){ 
     var ext; 
     if(typeof file.filetype === 'undefined'){ 
      ext = '.html'; 
     }else{ 
      ext = file.filetype; 
     } 
     var parsedPath = path.parse(file.path); 
     file.path = path.join(parsedPath.dir, parsedPath.name + ext); 
    })) 
    .pipe(gulp.dest(BUILD_DIR)) 
}); 

另外,您也可以使用gulp-foreach我在this answer建议类似的问题。但是,对于您的情况,这并不是必需的,因为您已经直接在data(...)中访问file对象。

编辑:为了完整起见,这里使用gulp-foreach版本:

var foreach = require('gulp-foreach'); 

gulp.task('metalsmith', function(){ 
    return gulp.src(CONTENT_DIR) 
    .pipe(frontMatter()).on("data", function(file){ 
     lodash.assign(file, file.frontMatter); 
     delete file.frontMatter; 
    }) 
    .pipe(foreach(function(stream, file){ 
     var ext; 
     if(typeof file.filetype === 'undefined'){ 
      ext = {extname: '.html'}; 
     }else{ 
      ext = {extname: file.filetype}; 
     } 
     return stream.pipe(rename(ext)); 
    })) 
    .pipe(gulp.dest(BUILD_DIR)) 
}); 
+0

我的印象是,当你返回gulp任务时,例如:'return gulp.src()...'它将按顺序运行,并且它只会在你不返回它时运行。 –

+0

这是为了顺序执行**任务**。这与流的构建或处理方式无关。 –

+0

这工作完美! –

@斯文的回答貌似要走的路,因为你希望到其他网站的一些普及和因为你可以”放下gulp-front-matter管道。

只是为了完成去在你有代码:即使

var ext = {extname: '.html'}; 
… 
.pipe(rename(ext)) 
… 

是行不通的:“我不知道如何处理的数据类型,我通过了” gulp-rename会说你需要做的

var ext = '.html'; 
… 
.pipe(rename({extname: ext}) 
… 

(或ext = 'html'{extname: '.' + ext},例如,如果“html”的字符串正在从别的地方拉,没有了“”)


正如我们在聊天中讨论的那样,我希望能够通过文件名或路径轻松识别您的php和html。由于所有的php文件都在/blog中,因此您可以使用gulp-filter。也许它到底是不是这种情况下的最佳解决方案,但它是了解所以这里一个有用的工具是它会是什么样子:

var gulp = require('gulp'), 
    gutil = require('gulp-util'), 
    lodash = require('lodash'), 
    data = require('gulp-data'), 
    filesize = require('gulp-filesize'), 
    filter = require('gulp-filter'),   // ADDED 
    frontMatter = require('gulp-front-matter'), 
    rename = require('gulp-rename'), 
    util = require('util'); 

gulp.task('metalsmith', function() { 
    const filterPHP = filter('blog/**/*', { restore: true }); 
    const filterHTML = filter('!blog/**/*', { restore: true }); 
    return gulp.src(CONTENT_DIR) 

                //---- if the only purpose of this particular gulp-front-matter pipe was to support the extension assignment, you could drop it 
     .pipe(frontMatter()).on("data", function(file) { // 
      lodash.assign(file, file.frontMatter);   // 
      delete file.frontMatter;      // 
     })             // 
               //--------- 

     .pipe(filterPHP)     // narrow down to just the files matched by filterPHP 
     .pipe(rename({ extname: '.php' })) 
     .pipe(filterPHP.restore)   // widen back up to the full gulp.src 
     .pipe(filterHTML)     // narrow down to just the files matched by filterHTML 
     .pipe(rename({ extname: '.html' })) 
     .pipe(filterHTML.restore)   // widen back up 
     .pipe(gulp.dest(BUILD_DIR)) 
});