LandonSchropp
LandonSchropp

Reputation: 10244

Grunt compiling Jade files

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?

Upvotes: 22

Views: 15542

Answers (3)

Slobo
Slobo

Reputation: 616

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!

Upvotes: 50

Mike Kerr
Mike Kerr

Reputation: 41

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"
            } ]
        }
    }

Upvotes: 3

Wayne Shelley
Wayne Shelley

Reputation: 1032

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

Upvotes: 1

Related Questions