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

gulp var defined in one pipe is undefined in another

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

gulpfile.js中的对应任务:

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.

我也试过它在 rename() 的同一行上有选项 obj,ext 只存储文件扩展名,例如:.pipe(rename({extname: ext})) 导致文件添加了未定义作为扩展名(而不是 phpfile.php 下面的 md 文件将被命名为 phpfileundefined

phpfile.md

中的 yaml
---
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"
  }

你的问题是当你执行 rename(ext)ext 的值仍然是 undefined 因为你的 data(...) 代码没有 运行还。

Gulp 插件是这样工作的:

  1. 您调用插件函数并向其传递任何必要的参数。在你的情况下 rename(ext).
  2. 插件函数returns一个duplex stream
  3. 您将该双工流传递给 .pipe()
  4. 只有在 all .pipe() 调用执行后,您才开始流式传输 运行ning.

所以 rename(ext) 是一个函数调用,用于 构造 流本身。流构建完成后才能开始流运行ning

但是,您仅在流为 运行ning 时才设置 ext 的值。在构建流时,您需要 ext before 的值。

在您的情况下,最简单的解决方案是简单地在 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 as I suggest in 来回答类似的问题。但是,在您的情况下,这并不是真正必要的,因为您已经直接在 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))
});

@Sven 的回答看起来像是要走的路,因为你希望得到一些可以推广到其他网站的东西,而且你不能放弃 gulp-front-matter 管道。

只是为了完成您拥有的代码:Even

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

行不通:gulp-rename 会说 "I don't know how to deal with the kind of data I was passed." 你需要做

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