22

I'm trying to configure my Gruntfile to compile all of my Jade files to individual HTML files. For example, if I have the following source folder:

source
└── templates
    ├── first.jade
    ├── second.jade
    └── third.jade

Then I would expect grunt jade to output:

build
└── templates
    ├── first.html
    ├── second.html
    └── third.html

Here's my Gruntfile using grunt-contrib-jade:

module.exports = function(grunt) {
    grunt.initConfig({

        jade: {
            compile: {
                options: {
                    client: false,
                    pretty: true
                },
                files: [ {
                  src: "*.jade",
                  dest: "build/templates/",
                  ext: "html",
                  cwd: "source/templates/"
                } ]
            }
        },
    });

    grunt.loadNpmTasks("grunt-contrib-jade");
};

However, when I run the jade command I get the following errors:

Running "jade:compile" (jade) task
>> Source file "first.jade" not found.
>> Source file "second.jade" not found.
>> Source file "third.jade" not found.

What am I doing wrong?

LandonSchropp
  • 10,084
  • 22
  • 86
  • 149

3 Answers3

50

To complete the above answer

    jade: {
        compile: {
            options: {
                client: false,
                pretty: true
            },
            files: [ {
              cwd: "app/views",
              src: "**/*.jade",
              dest: "build/templates",
              expand: true,
              ext: ".html"
            } ]
        }
    }

So if your source is structured as so:

app
└── views
    └── main.jade
    └── user
        └── signup.jade
        └── preferences.jade

grunt jade will create the following structure

build
└── templates
    └── main.html
    └── user
        └── signup.html
        └── preferences.html

EDIT: The grunt-contrib-jadeis deprecated. You should rather use grunt-contrib-pug. It is exactly the same, but they had to rename jade to pug!

Slobo
  • 616
  • 7
  • 3
  • 2
    The `files:` section is a little confusing. Does Grunt expand that, or are they options to the grunt jade plugin? I ask because I'd like to be able to use a layout.jade file in a `/views/` directory as an include, but I don't want to compile the `layout.jade` file. Is there a slick way to `-I` include a single file in the `files` field. And I want to keep it in /views/ because it is used by the Express rendering engine. Thx. – PeterT Feb 11 '15 at 00:07
3

Just in case anyone needs it. Nothing above worked. This is how it finally worked for me.

I'm using grunt.loadNpmTasks('grunt-contrib-pug'); I dunno if contrib-jade as since been deprecated but this solution works for me. I need the first file object to handle just the index.jade and the 2nd to deal with the templates. Now if I don't split it up and just point to the project directory the jade compiler gets lost inside my npm package folder so this runs much faster.

pug: {
        compile: {
            options: {
                client: false,
                pretty: true,
                data: {
                    debug: false
                }
            },
            files: [
            {
                'dist/index.html': ['index.jade']
            },
            {
                src: "templates/*.jade",
                dest: "dist",
                expand: true,
                ext: ".html"
            } ]
        }
    }
Mike Kerr
  • 41
  • 3
1

I know this is an old post but I kept coming back here whilst trying to solve a similar problem. I wanted to output multiple html files from a single jade template file using a for-loop. So needed greater control of the 'files' object.

The two problems I came across and eventually solved, was setting the output filename (a javascript object literal KEY) and making sure inline javascript functions are run immediately so that the loop variables are available.

Here is my full source code with comments. I hope this is of use to anyone else stumbling across this post.

Gruntfile.js:

module.exports = function(grunt) {

  // Create basic grunt config (e.g. watch files)
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    watch: {
      grunt: { files: ['Gruntfile.js'] },
      jade: {
        files: 'src/*.jade',
        tasks: ['jade']
      }
    }
  });

  // Load json to populate jade templates and build loop
  var json = grunt.file.readJSON('test.json');

  for(var i = 0; i < json.length; i++) {
      var obj = json[i];

      // For each json item create a new jade task with a custom 'target' name.
      // Because a custom target is provided don't nest options/data/file parameters 
      // in another target like 'compile' as grunt wont't be able to find them 
      // Make sure that functions are called using immediate invocation or the variables will be lost
      // http://stackoverflow.com/questions/939386/immediate-function-invocation-syntax      
      grunt.config(['jade', obj.filename], {
        options: {
            // Pass data to the jade template
            data: (function(dest, src) {
                return {
                  myJadeName: obj.myname,
                  from: src,
                  to: dest
                };
            }()) // <-- n.b. using() for immediate invocation
        },
        // Add files using custom function
        files: (function() {
          var files = {};
          files['build/' + obj.filename + '.html'] = 'src/index.jade';
          return files;
        }()) // <-- n.b. using () for immediate invocation
      });
  }

  grunt.loadNpmTasks('grunt-contrib-jade');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // Register all the jade tasks using top level 'jade' task
  // You can also run subtasks using the target name e.g. 'jade:cats'
  grunt.registerTask('default', ['jade', 'watch']);
};

src/index.jade:

doctype html
html(lang="en")
  head
    title= pageTitle
    script(type='text/javascript').
      if (foo) {
         bar(1 + 5)
      }
  body
    h1 #{myJadeName} - node template engine    
    #container.col
      p.
        Jade is a terse and simple
        templating language with a
        strong focus on performance
        and powerful features.

test.json:

[{
    "id" : "1", 
    "filename"   : "cats",
    "tid" : "2016-01-01 23:35",
    "myname": "Cat Lady"
},
{
    "id" : "2", 
    "filename"   : "dogs",
    "tid" : "2016-01-01 23:45",
    "myname": "Dog Man"
}]

After running 'grunt' the output should be:

build/cats.html
build/dogs.html
Wayne Shelley
  • 992
  • 10
  • 25