Caio Vertematti
Caio Vertematti

Reputation: 274

Compile client-side Jade templates using Gulpjs

I'm trying to compile all my .jade templates into a single js file, I'm using Gulpjs and gulp-jade, gulp-concat..

I can get the single file but the problem is that all the functions rendered there have the same name, they are all called "template".

foo.jade:

.fooDiv
    h1 Foo here

foo2.jade:

.foo2Div
    h1 Foo2 here

Gulp file:

gulp.src("templates/**/*.jade")
    .pipe(jade({client: true}))
    .pipe(concat("templates.js"))
    .pipe(gulp.dest("../website/templates"))

That would output a file like this:

function template(locals) {
    var buf = [];
    var jade_mixins = {};

    buf.push("<div class=\"fooDiv\"><h1>Foo here</h1></div>");;return buf.join("");
}
function template(locals) {
    var buf = [];
    var jade_mixins = {};

    buf.push("<div class=\"foo2Div\"><h1>Foo2 here</h1></div>");;return buf.join("");
}

And what I want is something like:

function foo(locals) {
    var buf = [];
    var jade_mixins = {};

    buf.push("<div class=\"fooDiv\"><h1>Foo here</h1></div>");;return buf.join("");
}
function foo2(locals) {
    var buf = [];
    var jade_mixins = {};

    buf.push("<div class=\"foo2Div\"><h1>Foo2 here</h1></div>");;return buf.join("");
}

Is there any way I can do this? I've been searching for quite some time now and didn't find anything.

Cheers. Caio

Edit:

Jade now accepts the name option for jade.compileClient. Check it here: https://github.com/jadejs/jade/blob/master/jade.js

Upvotes: 4

Views: 3221

Answers (3)

coderfin
coderfin

Reputation: 1763

The following code snippet comes from this comment that I found to be very helpful.

gulp.task('strings', function() {
    return gulp.src('media/templates/*.jade')
        .pipe(foreach(function(stream,file){
            var filename = path.basename(file.path);
            filename = filename.split('.')[0]
            return stream
                .pipe(jade({
                    client: true,
                    name: filename
                }));
        }))
        .pipe(concat('all.js'))
        .pipe(gulp.dest('media/strings/'))
});

Using gulp-foreach you can get the current file's name, change it, and then pass it on to jade. After that you can perform other actions, like concat, as normal.

Upvotes: 3

qwe123asdA
qwe123asdA

Reputation: 21

I found an elegant solution that works for me.

Basically, in your main script (the one you load BEFORE the jade generated scripts in your .html file), you have an array that will hold the returned values of the template() functions, say var document = [];

You then use gulp-insert to wrap to the scripts '(function() {' and ;\n;document.push(template()); })();, then concatenate those scripts as you have already done.

Now pop the document[] array as you need, with the computed values from each template() call inside!

I use LiveScript for my build, but here is a converted JavaScript version:

var jade   = require('gulp-jade');
var concat = require('gulp-concat');
var insert = require('gulp-insert');
gulp.task('jade-to-js', function(){
  return gulp.src('src/node/jade/*.jade')
  .pipe(jade({client: true}))
  .pipe(insert.wrap('(function() {', '\n;document.push(template()); })();')
  .pipe(concat('bundle.js'))
  .pipe(gulp.dest('src/js/'))
});

Upvotes: 2

Shuhei Kagawa
Shuhei Kagawa

Reputation: 4777

It seems that jade.compileClient hard-codes function template(locals) and it has no option to change the function name. https://github.com/visionmedia/jade/blob/master/lib/jade.js

This is a bit hacky but you can modify the contents of the compiled scripts after the jade compilation.

var through = require('through2');
var path = require('path');

function modify() {
  function transform(file, enc, callback) {
    if (!file.isBuffer()) {
      this.push(file);
      callback();
      return;
    }
    var funcName = path.basename(file.path, '.js');
    var from = 'function template(locals) {';
    var to = 'function ' + funcName + '(locals) {';
    var contents = file.contents.toString().replace(from, to);
    file.contents = new Buffer(contents);
    this.push(file);
    callback();
  }
  return through.obj(transform);
}

gulp.src("templates/**/*.jade")
    .pipe(jade({client: true}))
    .pipe(modify())
    .pipe(concat("templates.js"))
    .pipe(gulp.dest("../website/templates"));

You can change the funcName as you like based on file.path if your jade templates are in multiple subdirectories.

Upvotes: 8

Related Questions