Reputation: 119
I am using gulp to processes pages for a site, some of these pages are php files. The problem is that after all the pages are run through the template engine they have a .html
file extension. I am adding a property to the file that designates if it's supposed to be a file besides html and then renaming the file to match. However, for some reason gulp-rename keeps saying that the variable I am using to store the extension is undefined
.
Corresponding task in 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))
});
when I run the above it errors with Unsupported renaming parameter type supplied
.
Also I have tried it having options obj on the same line as rename()
, with ext
only storing the file extension eg: .pipe(rename({extname: ext}))
which causes the files to have undefined added as the extension (instead of phpfile.php
the below md
file would be named phpfileundefined
)
yaml in 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"
}
Upvotes: 0
Views: 965
Reputation: 4385
@Sven's answer looks like the way to go, since you're hoping for something generalizable to other sites and since you can't drop the gulp-front-matter
pipe.
Just to finish going over the code you had: Even
var ext = {extname: '.html'};
…
.pipe(rename(ext))
…
wouldn't work: gulp-rename
would say "I don't know how to deal with the kind of data I was passed." You'd need to do
var ext = '.html';
…
.pipe(rename({extname: ext})
…
(or ext = 'html'
and {extname: '.' + ext}
, for example if the "html" string was being pulled from somewhere else and didn't have the ".")
As we discussed in chat, I was hoping to find that your php and html could be easily distinguished by file name or path. Since all your php files are in /blog
you could use gulp-filter
. Probably in the end it's not the best solution for this scenario, but it's a useful tool to know about so here's what it would look like:
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))
});
Upvotes: 1
Reputation: 30574
Your problem is that by the time you execute rename(ext)
the value of ext
is still undefined
because your data(...)
code hasn't run yet.
Gulp plugins work like this:
rename(ext)
..pipe()
.pipe()
calls have been executed does you stream start running.So rename(ext)
is a function call that is used to construct the stream itself. Only after the stream has been constructed can the stream start running.
However you set value of ext
only once the stream is running. You need the value of ext
before that when you are constructing the stream.
The easiest solution in your case is to simply do the renaming manually in your data(...)
function instead of relying on gulp-rename
. You can use the node.js built-in path
module for that (which is what gulp-rename
uses under the hood):
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))
});
Alternatively you could also use gulp-foreach
as I suggest in this answer to a similar question. However that's not really necessary in your case since you're already accessing the file
object directly in data(...)
.
EDIT: for completeness sake here's a version using 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))
});
Upvotes: 2