Giter VIP home page Giter VIP logo

grunt-bake's Introduction

grunt-bake

Build Status Downloads Version

Bake static pages for production while using modular files while in development.

Getting Started

This plugin requires Grunt ~0.4.0

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

npm install grunt-bake --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks( "grunt-bake" );

The "bake" task

Overview

This module helps creating static pages while still having the coding comfort of multiple small files. It also helps not to repeat yourself as includes can be used at multiple places.

The module parses the files recursivly, meaning it allows for nested includes. While parsing the includes it also performs a simple find and replace on placeholders. The replacements are supplied in a JSON file but more an here.

When grunt-bake parses files it looks for anchors like this: <!--(bake path/to/file.html)-->.

Setup the bake task like so:

grunt.initConfig( {
    bake: {
        your_target: {
            options: {
                // Task-specific options go here.
            },

            files: {
                // files go here, like so:

                "dist/index.html": "app/index.html",
                "dist/mobile.html": "app/mobile.html"

                // etc ...
            }
        },
    },
} )

With a app/index.html file like this one:

<html>
    <head></head>
    <body>
        <!--(bake includes/container.html)-->
        <!--(bake includes/footer.html)-->
    </body>
</html>

The paths given are relative to the file being parsed.

Options

options.content

Type: String or Object or Function Default value: null

A string value that determines the location of the JSON file that is used to fill the place holders. If a Object is specified it will be used as content. If a Function is specified its return (should be JSON) will be used as content.

Additionally to the content provided, bake comes with a set of default values that are attached to a __bake object which gets injected to the user content. Even if no content is provided.

__bake.filename // the file path tbeing baked
__bake.srcFilename // same as __bake.filename
__bake.destFilename // the file path it is being written to
__bake.timestamp // a timestamp (milliseconds) at baking

These can be especially usefull in combnation with transforms.

<html>
    <head></head>
    <body>
        <!--(bake-start)-->
        {{__bake.destFilename}} was written at {{__base.timestamp | parseDate }}
        <!--(bake-end)-->
    </body>
</html>

options.section

Type: String Default value: ""

A string that determines which subsection of the JSON passed as content should be used. If no section is passed the entire JSON will be used for templating.

Given a content JSON like such:

{
    "en": {
        "title": "Book",

        "info": {
            "author": "Joe Do",
            "job": "Writer"
        }
    },

    "de": {
        "title": "Buch",

        "info": {
            "author": "Joe Do",
            "job": "Schreiber"
        }
    }
}

If "en" is passed as section, { "title": "Book", "info": { ... } } will be passed to the include. If no section is specified the entire JSON will be passed.

This could be used to parse a template like such:

<div>{{title}}</div>
<div>
    <span>{{info.author}}</span>
    <span>{{info.job}}</span>
</div>

options.parsePattern

Type: Regex Default value: /\{\{\s?([\.\-\w]*)\s?\}\}/g

Determines the regex to parse the files in order to insert the content from the JSON file. The default pattern allows place holders such as: {{value}}.

options.process

Type: Function Default value: default process procedure

A Function which is used to process the template before putting it into the file. If process is defined as null or false the includes won't be processed at all. The default process uses two curly braces as marker, such as {{json.value.name}}. However the parse regex is costumizable using options.parsePattern.

The function gets passed two arguments:

  • String: representing the template to parse.
  • Object: the content from the JSON file as object.

options.basePath

Type: String Default value: ""

Determines the base directory for includes that are specified with an absolute path. All paths starting with an / are absolute while other paths starting with folder or file names are relative to the include being parsed.

<!--(bake includes/footer.html)--> relative to the file

<!--(bake /includes/footer.html)--> relative to the basePath (level of Gruntfile by default)

options.transforms

Type: Object Default value: {}

Registers callbacks that can be used as transforms in the template with {{myvar | upper}}. It is possible to chain transforms like {{myvar | upper | nl2br}}.

transforms: {
    upper: function(str) {
        return String(str).toUpperCase();
    },
    nl2br: function(str) {
        // ...
    }
}

Transforms support parameters like {{myvar | replace:'A':'B'}}. Parameters are handed into the callback as additional parameters.

transforms: {
    // str => content of myvar,  searchvalue => 'A',  newvalue => 'B'
    replace: function(str, searchvalue, newvalue) {
        return String(str).replace(searchvalue, newvalue);
    }
}

options.semanticIf

Type: Bool | Array | Function Default value: false

Set to true enables support for no/yes and off/on in _if statements. Alternatively false values can be defined via Array or a callback can be used for evaluation.

options.removeUndefined

Type: Bool Default value: true

Set to false, placeholders that could not be resolved (= no matching key in content) will be kept untouched in the output.

options.variableParsePattern

Type: Regex Default value: /\{\{!\s*([^\}]+)\s*\}\}/

This regex is used to parse the variable specified inline with the bake task. Any inline attribute that is not preficed with an underscore such as _if and _section is considered a variable and is passed to the bake include. For more detail check out the section on Inline Attributes. However, if you want to pass not a value but a reference to an different object you can do so by writing the inline value as variable="{{!foo.bar}}". Mind the exclamation mark. Assuming bar is an object as well, this will give you a reference to bar instead of the string.

Usage Examples

Simple bake

This example shows a simple baking process with all default options.

grunt.initConfig( {
    bake: {
        build: {
            files: {
                "app/index.html": "app/base.html"
            }
        }
    }
} )

app/base.html:

<html>
    <body>
        <!--(bake includes/container.html)-->
    </body>
</html>

app/includes/container.html:

<div id="container"></div>

This bake task will create app/index.html:

<html>
    <body>
        <div id="container"></div>
    </body>
</html>

Bake with content

This example shows how to use the bake process to parse the templates with a provided JSON and a section.

grunt.initConfig( {
    bake: {
        build: {
            options: {
                content: "app/content.json",
                section: "en"
            }

            files: {
                "app/index.html": "app/base.html"
            }
        }
    }
} )

app/content.json:

{
    "en": {
        "title": "Hello World"
    },

    "de": {
        "title": "Hallo Welt"
    }
}

app/base.html:

<html>
    <body>
        <!--(bake includes/container.html)-->
    </body>
</html>

app/includes/container.html:

<div id="container">{{title}}</div>

This bake task will create app/index.html:

<html>
    <body>
        <div id="container">Hello World</div>
    </body>
</html>

Inline attributes

In addition to the file the bake anchor tag also allows for inline attributs which will override the content from the JSON file. Note: Please note that the parsing of inline attributes requires double quotes in the definition as shown in the example

Same scenario as above.

app/base.html:

<html>
    <body>
        <!--(bake includes/container.html title="Salut Monde" name="Mathias")-->
    </body>
</html>

app/includes/container.html:

<div id="container">{{title}}</div>
<span>{{name}}</span>

This bake task will create app/index.html:

<html>
    <body>
        <div id="container">Salut monde</div>
        <span>Mathias</span>
    </body>
</html>

IF Statement

The bake task also allows a simple if conditional. Inline attributes named _if are treated as such. If the value that _if holds can't be found in the content.json or if found equals to the value false the include will be ignored. The _if can also be used inverted to create a _else effect in a way. A definition as _if="!name" would mean the template will be rendered when name cannot be found or is false.

Alternativly, _if suppoerts two operators. the == and the != operator. This allows to specify the name of the value and the content in single quotes, if the content is a string. Note: This is a simple implementation of the equals operator and is based solely on strings.

app/base.html:

<html>
    <body>
        <!--(bake includes/container.html _if="name")-->

        <!--(bake includes/other.html _if="foo == 'bar'")-->
    </body>
</html>

includes/other.html:

<span>{{foo}}</span>

app/content.json:

{
    "foo": "bar"
}

This bake task will create app/index.html:

<html>
    <body>

        <span>bar</span>
    </body>
</html>

Additionally the _if statement also works with inlining the bake content.

<html>
    <body>
        <!--(bake-start _if="name")-->
        <h1>{{name}}</h1>
        <!--(bake-end)-->
    </body>
</html>

Foreach Loop

Another special inline attribute is the _foreach attribute. This keyword expects a specific syntax and can be used both inline as well as pulling content from the json. This allows to loop over a set of values and using that value in the partial. It accepts an inline syntax: _foreach="name:[mike, drew, steve]" as well as a reference to an array in the json: _foreach="name:authors.names". The values from the array can then be used with the key name. This key can be chosen arbitrarily.

app/base.html:

<html>
    <body>
        <ul class="first">
            <!--(bake includes/li.html _foreach="name:[mike, drew, steve]")-->
        </ul>

        <ul class="second">
            <!--(bake includes/li.html _foreach="name:authors.names")-->
        </ul>
    </body>
</html>

app/includes/li.html:

<li>{{name}}</li>

app/content.json:

{
    "authors": {
        "names": [ "jenna", "carla", "susy" ]
    }
}

This bake task will create app/index.html:

<html>
    <body>
        <ul class="first">
            <li>mike</li>
            <li>drew</li>
            <li>steve</li>
        </ul>

        <ul class="second">
            <li>jenna</li>
            <li>carla</li>
            <li>susy</li>
        </ul>
    </body>
</html>

Just like the _if statement the _foreach also works with inlined content:

<html>
    <body>
        <ul>
        <!--(bake-start _foreach="name:[robert, susan, carl]")-->
            <li>{{name}}</li>
        <!--(bake-end)-->
        </ul>
    </body>
</html>

Bake automatically supplies meta information for each loop, like current index. Values can be accessed by the defined key followed by @index, @iteration, @first, @last, or @total.

<html>
    <body>
        <ul>
        <!--(bake-start _foreach="name:[Robert, Susan, Carl]")-->
            <li><a href="#anchor-{{name@iteration}}">{{name}}</a></li>
        <!--(bake-end)-->
        </ul>
    </body>
</html>

This will render the following:

<html>
    <body>
        <ul>
            <li><a href="#anchor-1">Robert</a></li>
            <li><a href="#anchor-2">Susan</a></li>
            <li><a href="#anchor-3">Carl</a></li>
        </ul>
    </body>
</html>

Inline Section statement

The _section attribute, when used inline, allows to use a specific subcontent of the values.

app/base.html:

<html>
    <body>
        <!--(bake includes/file.html _section="home")-->
        <!--(bake includes/file.html _section="about")-->
    </body>
</html>

app/includes/file.html:

<h1>{{title}}</h1>
<p>{{content}}</p>

With the following content file

{
    "home": {
        "title": "Home",
        "content": "This is home"
    },
    "about": {
        "title": "About",
        "content": "This is about"
    }
}

This will render the following:

<html>
    <body>
        <h1>Home</h1>
        <p>This is home</p>
        <h1>About</h1>
        <p>This is about</p>
    </body>
</html>

Inline _render statement

The _render statement simular to the _if statement determines whether or not the include is parsed. However the _render statement looks for it's counterpart in the options not in the content JSON. It then determines whether or not the field exists and if so, if the field has a truthy value. If the field doesnt exist the _render will be ignored. If it does existes a true value will render the template and a false value will skip the template.

app/base.html:

<html>
    <body>
        <!--(bake includes/file.html _render="baseline")-->
    </body>
</html>

With the following grunt task:

bake: {
    your_target: {
        options: {
            baseline: false
        },

        files: {
            "dist/index.html": "app/base.html"
        }
    },
}

This will create:

dist/index.html:

<html>
    <body>
    </body>
</html>

Inline _assign statement

The _assign statement determines to save included content into a variable instead of placing it directly. The variables name is defined by _assign-value.

app/base.html:

<html>
    <body>
        <!--(bake includes/file.html _assign="foo")-->
        {{foo}}
        <p>{{foo}}</p>
    </body>
</html>

app/includes/file.html:

<span>Hello World</span>

This will create:

dist/index.html:

<html>
    <body>
        <span>Hello World</span>
        <p><span>Hello World</span></p>
    </body>
</html>

Inline _process statement

Set to true the _process statement prevents bake from processing the included files content. The include takes place, but neither placeholders become replaced nor further bake sections processed.

app/base.html:

<html>
    <body>
        <!--(bake includes/file.html _process="false")-->
    </body>
</html>

app/includes/file.html:

<!--(bake includes/other.html)-->
<span>{{foo}}</span>

This will create:

dist/index.html:

<html>
    <body>
        <!--(bake includes/other.html)-->
		<span>{{foo}}</span>
    </body>
</html>

Bake extra pages (e.g. detail pages)

Another special inline attribute is the _bake attribute. This keyword expects a specific syntax which allows to dynamically create additional files. It accepts the syntax: _bake="template.html > target.html".

The following example will create two additional files named info-John.html and info-Jane.html which will be baked using app/detail.html with corresponding values from app/content.json. For linking to genereated files a @link variable is available. For linking the originating file from generated files a @referrer variable is available.

app/detail.html:

<html>
    <body>
        <h1>My name is {{member.name}}</h1>
        <p>I am a {{member.profession}}</p>
        <p>
            <a href="{{@referrer}}">Back to team</a>
        </p>
    </body>
</html>

app/base.html:

<html>
    <body>
        <ul>
            <!--(bake li.html _foreach="member:members" _bake="detail.html > member-{{member.name}}.html")-->
        </ul>
    </body>
</html>

app/li.html:

    <li><a href="{{@link}}">More about {{member.name}}</a></li>

app/content.json:

{
    "members": [
        {
            "name": "John",
            "profession": "Dentist"
        },
        {
            "name": "Jane",
            "profession": "Pilot"
        }
    ]
}

Alternative app/base.html with inline-section instead of additional app/li.html file:

app/base.html:

<html>
    <body>
        <ul>
            <!--(bake-start _foreach="member:members" _bake="detail.html > member-{{member.name}}.html")-->
                <li><a href="{{@link}}">More about {{member.name}}</a></li>
            <!--(bake-end)-->
        </ul>
    </body>
</html>

app/detail.html and app/content.json same as above.

Custom process

This example shows the use of a custom process function.

var processFunction( source, content ) {
    return source + "<br>";
}

grunt.initConfig( {
    bake: {
        build: {
            options: {
                content: "app/content.json",
                section: "en",
                process: processFunction
            },

            files: {
                "app/index.html": "app/base.html"
            }
        }
    }
} )

Continuous development

For ease of development just add the bake task to your watch list. The static page will be baked every time you change the template.

watch: {
    bake: {
        files: [ "app/includes/**" ],
        tasks: "bake:build"
    }
}

Changelog

  • 1.9.0 1-2-2018 Adds variableParsePattern for inline variables.
  • 1.8.0 4-20-2016 Adds permanent variables under __bake.
  • 1.7.2 4-20-2016 Resolves recursion issues in _process and _assign.
  • 1.7.1 4-8-2016 Fix for issue with _process.
  • 1.7.0 4-7-2016 Adds _process and _assign attributes.
  • 1.6.4 4-4-2016 Bug fixes.
  • 1.6.3 2-26-2016 Allow inline section attribute to have multiple leves.
  • 1.6.2 2-26-2016 Update dependecies.
  • 1.6.1 2-11-2016 fixes error for options.section on multiple files.
  • 1.6.0 2-10-2016 adds support for parameters in transforms. Also introduces a breaking change away from transformGutter.
  • 1.5.1 2-9-2016 adds @referrer attribute to _bake.
  • 1.5.0 2-2-2016 adds support for _bake attribute.
  • 1.4.1 2-2-2016 fixes minor bug fix #72.
  • 1.4.0 1-30-2016 adds full JS support for evaluating _if.
  • 1.3.1 1-20-2016 adds support for parsing values in inline variables.
  • 1.3.0 1-13-2016 adds support for parsing file paths in bake tag.

grunt-bake's People

Contributors

barryceelen avatar david-zacharias avatar fewstera avatar k-funk avatar larixk avatar millette avatar paulhuizer avatar roboshoes avatar wispproxy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

grunt-bake's Issues

Multiple JSON Content Files for Multiple HTML Files

Is there any way to use multiple content JSON files with the bake task? I would like to have one JSON file per HTML file in my project if possible. I read issue #27 but I'm not sure if a solution for it has been implemented.

By the way, great job on this project!

Bake task regex?

Is there a way to make bake work with a regex and maybe tell it to render into one directory?

Like this:

bake: {
  build: {
    options: {
      basePath: '<%= yeoman.app %>/views/_includes'
    },
    files: {
      '<%= yeoman.app %>/*': '<%= yeoman.app %>/views/_pages/*',
    }
  }
}

Thank you.

_if should not generates a blank line when false

I've started using grunt-bake for generating POC code, and use directory comparison to verify the output or watch what has changed.

It would be nice if the _if statements didn't generate blank lines when false so that adding an _if doesn't cause all my files to have a minor change.

Ability to use the inline _render flag with JS and Sass/CSS?

I've been using Grunt on a daily basis for a good year or so now so firstly, thanks for the great plugin.

I have now reached a point on a project where I would like to facilitate some simple switching of logic across HTML, CSS and JS files.

With grunt-bake, in HTML this is working well. I have this kind of thing in my Gruntfile:

options: {
    process : false,
    case1: true,
    case2: false
}

And I switch the values as needed. That way includes like this get switched on or off:

<!--(bake /source/thing.html _render="case1")-->

However, I'd like to enjoy the same capability in Sass/CSS and JS files so that code can be switched on/off and included in the same manner (and crucially based upon the same flags in the Gruntfile).

For example, this syntax in JS/Sass:

//  (bake-start _render="case1")
Case 1 specific code here
// (bake-end)

And this syntax in CSS:

/* (bake-start _render="case1") */
Case 1 specific CSS here
/* (bake-end) */

Could grunt-bake be extended to facilitate this requirement? Or do you consider it out of scope?

Lint error caused by regex

The main regex for parsing bake tags causes following jshint error:

[L110:C64] Unescaped '^'.
    var regex = /(\n?)([ \t]*)<!--\(\s?bake(-start|-end)?([^]*?)\)-->/;

I think we can change the [^] part to [\s\S] which also covers everything, but does not cause a linting error. Tests run green with that change. I will leave final decision to you, @MathiasPaumgarten.

Consecutive includes error

Hey Mattie, found an issue.

If there are consecutive includes that are after one another, like so -

            <!--(bake include_first.html)-->
            <!--(bake include_second.html)-->

the bake task fails at the first include with the following error:

Warning: Unable to read "include_first.html)-->" file (Error code: ENOENT). Use --force to continue.

Even with new line and tab character between them. If I put in a space character after the first include, it works fine. Just logging this one as it was an issue when using TidyHTML which removes white spaces and new lines and the errors were being thrown.

Feature Request: Unescape special characters in content

I'm trying to include HTML and HTML entities in my content strings in a JSON file, but they're being escaped (e.g. < becomes <). Is there a way to prevent this from happening, e.g. by using {{{ }}} to add unescaped content like Handlebars/Mustache?

A possible feature

Hi,

I'm using bake now for 2 weeks to build my html templates and it's really a great plugin.

I'm trying to figure out how can i do to have the possibility to generate my master html file and all its included html file, but not having to "bake" all my 300 html template. Only those that are concerned. It could be a great feature to bake the master file and its dependancies.

I'm looking to make a sourcemap like file that knows which files are bound together and when i "bake" one file then it "bakes" all the files that are related to the one i've just "baked", the master and/or the included files.

Don't know if i've been clear :), i'm not native english :).

bye.

Question about parsing array

I think it's a question not an issue.

I have a json with this data:

(...)
    "unique-colours": [
        "#749DCB",
        "#3C3C3C",
        "#E6EDF2",
        "#2C5078"
  },
(...)

In html i have

<p>unique-colours {{unique-colours}}</p>

Which output:

unique-colours #749DCB,#3C3C3C,#E6EDF2,#2C5078

But i want to output to determined spaces. Like this:

<p>color #749DCB</p>
<p>color #3C3C3C</p>
<p>color #E6EDF23C</p>
<p>color #2C50783C</p>

Can i do it? How?

Arguments to path.join must be strings

Hi,

I have this following error, using your task :

I used this as configuration :

files: {
// files go here, like so:
"templates/built/confirmation.html":"templates/confirmation.html",.
}

unfortunately this doesn't work.

I had to write a little fix ;

bake.js - line 315

this.files.forEach( function( file ) {

        grunt.log.write(JSON.stringify(file));

        //HERE IS THE FIX, but I don't understand everything....
        file=file.orig;


        var src = file.src[ 0 ];
        var dest = file.dest;

What do you think ?

TypeError: Arguments to path.join must be strings
at path.js:360:15
at Array.filter (native)
at Object.exports.join (path.js:358:36)
at Object.file.exists (/Users/jeremy/Projets/airport-mails/node_modules/grunt/lib/grunt/file.js:373:28)
at checkFile (/Users/jeremy/Projets/airport-mails/node_modules/grunt-bake/tasks/bake.js:75:22)
at /Users/jeremy/Projets/airport-mails/node_modules/grunt-bake/tasks/bake.js:318:4
at Array.forEach (native)
at Object. (/Users/jeremy/Projets/airport-mails/node_modules/grunt-bake/tasks/bake.js:312:14)
at Object. (/Users/jeremy/Projets/airport-mails/node_modules/grunt/lib/grunt/task.js:264:15)
at Object.thisTask.fn (/Users/jeremy/Projets/airport-mails/node_modules/grunt/lib/grunt/task.js:82:16)

Allow section to be defined inline

Currently section is defined globally but it would make Bake super powerful if it can be defined inline. That would allow you to set most of the site content in the JSON file.

For example if your JSON is:

{
    "home": {
        "title": "Home Title",
        "content": "<p>This is the home page content</p>"
    },

    "about-us": {
        "title": "About Us Title",
        "content": "<p>This is the about us page content</p>"
    }
}

On your home page you can do:
<!--(bake includes/content.html _section="home")-->

And then in content.html

<div>
    <h1>{{title}}</h1>
    {{content}}
</div>

And your rendered output for home will be:

<div>
    <h1>Home Title</h1>
    <p>This is the home page content</p>
</div>

JSHint

Currently JSHint won't run through. It also needs a watch task that hint's every file on save.

Using hyphens in inline attributes

Hello,

I like to use hyphens for my CSS Classes, and I came across an issue with Bake where it does't allow hyphens in inline attributes.

This is how I am using it:

Include
<!--(bake product-view.html class="product-view")-->

Template
<div class="{{class}}"></div>

Is there a fix for this, or why it doesn't work with hyphens?

Thanks

Recursive call to bake:build in watch

Hey,

This is probably a problem my end as I have used bake on a previous project and it worked fine. I'm using the lates yo webapp generator and have added bake to my project. When i include 'bake:build' in the watch task and update an 'include' it calls 'bake:build' infinely, constantly refreshing the page as if the files changing over and over.

Sorry for the inconvenience but i love the tool and would love to get it working properly my end.

DP

How to automate the baking process?

Hi!

I would like to automate the process in the Gruntfile in order to avoid any modification for every new page:

    bake: {
        build: {
            files: {
                src: ['*.html'],
                dest: '<%= config.app %>/',
                cwd: '<%= config.app %>/templates/'
            }
        }
    },

Any solution?

Feature request: globbing files

First of all .. thanx for the nice script. Love it. It works very well!!
If I may ask ... would it be possible to make it so that we can use wildcards and such in order to bake files in one blow for my whole project?
Thankx in advance for your reply ...

Prevent Mustache replacements in Bake

We are using Bake alongside our own mustache based templating system. We were having problems with Bake trying to replace mustache areas that we needed to replace ourselves afterwards.

It would be useful to have an option to disable the Bake template processing; currently we have added a fake function to do this at the top of the Gruntfile.js:

var nonProcess = function( source, content ) {
    return source;
};

Option to disable transforms

Hi! I have this code in templates:

<p class="greetings">Dear {{var customer_name}},</p>
...
<td class="price">{{var quote.getGrandTotal()|formatPrice}}</td>

[email protected] and 1.1.1 output:

<p class="greetings">Dear ,</p>
...
<td class="price"></td>

But I need this code untouched because it's using in futher tools. I using [email protected] and everything fine.

Is there any way to prevent code removing for this case?

bower injection support in docs

to support bower injection in base.html you need to change index.html to base.html

line 5: index.html --> base.html

    // Automatically inject Bower components into the HTML file
    wiredep: {
      app: {
        ignorePath: /^\/|\.\.\//,
        src: ['<%= config.app %>/base.html'],
        exclude: ['bower_components/bootstrap-sass-official/assets/javascripts/bootstrap.js']
      },
      sass: {
        src: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
        ignorePath: /(\.\.\/){1,2}bower_components\//
      }
    },

btw. love to bake with this ๐Ÿ‘

Contributors

Hey, @PaulHuizer @david-zacharias

As you see I've added an contributors section into the package.json. I wasn't sure what you want in your fields as email address. Probably the same as your npm email, as it will link you that way, I think.

Let me know what you want there as an email address, if you do want to be there at all.

Simple variable checks in includes

Hey Mathias!

I felt bad about asking for extras in what is already a really handy little plugin (as well as liking the fact that it's nice and lean at the moment), but if you're looking to hear of potential enhancements, I have a couple!

A simple variable check was a biggie. We used to use PHP templates for prototypes that moved towards being fairly high-fidelity as they were iterated, so would do something like this:

<ul>
    <li><a href="/">Home:</a></li>
    <li class="<?php if(isset($page_navcurrent) &&($page_navcurrent === "about")) echo('active') ?>"><a href="/about">About</a></li>
    <li class="<?php if(isset($page_navcurrent) &&($page_navcurrent === "link2")) echo('active') ?>"><a href="/link2">Link 2</a></li>
    <li class="<?php if(isset($page_navcurrent) &&($page_navcurrent === "link3")) echo('active') ?>"><a href="/link3">Link 3</a></li>
</ul>

Obviously you wouldn't need issets, but even a really basic 'if' handler, without else, or anything like that, would probably be enough. Would be a lovely little improvement.

Bake has been really handy so far though! It's great that it doesn't try to do heaps of stuff and can compile pretty quickly.

_if issues with empty strings

Hey Mathias,

it's me once again. I have an issue with the _if in combination with empty strings in data. When I have a inline section like

<!--(bake-start _if="employee.quote")-->
  <p class="quote">{{employee.quote}}</p>
<!--(bake-end)-->

and employee.quote is an empty string (""), the section is still rendered. I tracked down the issue and would say its due to two things:

1st: isFalse( value ) does not consider empty strings to be false. I would say it should. So I recommend add this check to line 129, like:

if ( value === '' || value === undefined || value === false || string === "false" ) {

2nd: validateIf( inlineValues, values ) returns true when value is in values. It does not check if resolved value is true or false. I think it is better to check this, so my recommendation is to change line 235 to:

if ( ! hasValue( value, values ) && isFalse( resolveName( value, values ) ) ) return true;

or

if ( ! hasValue( value, values ) ) return isFalse( resolveName( value, values ) );

What do you think?

use HTML inline

Is it possible to use html when supplying inline content? For example I think that it chokes on the span tags unless there is a way to escape them that I'm not aware of.

Idea

Hey there! Great plugin, exactly what I was looking for for internationalizing Websites, plus finally some good HTML templating on Grunt!

Let me tell you one thing though: I lost 2 hours this morning thinking I must have done everything wrong, the JSON wasn't parsing properly and I would get a gigantic {{ SECTION.TITLE }} instead of my logo.

Turns out it was because of the spacing between the {{ and the placeholder. It would be very useful for it to parse spacing, as I think most of us using templating languages will be accustomed to use them for readability.

Don't take it wrong, just a suggestion! Thanks a lot for your work

Thank you for your script!

Not an issue just a praise - sadly we don't have that on here.

I just spent all afternoon writing all the connecting pieces. Your bake is the backbone of my AUTO JQUERY MOBILE:

I rewrote 90% -better instructions coming - essentially this is an all in one build jquery mobile app. You just type grunt setup-jqm and it grabs the latest (beta version of jqm) dependencies,extracts, builds, copies over files to the assets, directory - to top it off this uses bake to automagically watch and build your index.html from components!

https://github.com/imaginethepoet/autojqm/blob/master/README.md

Absolute includes

I guess this is more a personal preference, but it might be handy to be able to set include paths that were a bit more portable:

My terminology most likely sucks, but here's a quick stab! Maybe an include_base_path as a config option. I've been keeping all my source templates in a dir called 'partials'

bake:
  options:
    include_base_path: partials
  build:
    files:
      "dist/index.html": "partials/index.html"

And then that would allow you to do this:

<!--(bake /includes/nav.html)-->

Which would automatically take /partials as the starting point for any includes? That way you could repeat the same code snippet for the header of every page, regardless of whether you're keeping it in a subdirectory structure.

Even just being able to define a path relative to the Gruntfile would do the trick, and possibly be a fair bit easier. So: /partials/includes/nav.html

Obviously feel free to disregard if it doesn't fit where you want to take the plugin ๐Ÿ˜ƒ Sorry for not being able to send you a more useful pull request - I'm not quite up to scratch on building the stuff, yet!

Notes

Hello, stumbled across this in my quest for a partials/includes grunt task and it works really well so far :)

I was wondering if there was a way to include a note(s) in the generated html page?
(Apologies if another Grunt task can/should do this)

Case: Working in a development team, if I came across index.htm I might just start editing that without knowing it had been generated by multiple files. So putting a warning note in would be helpful to tell people the location of the original file(s)?

Keep up the good work!
Thanks
Tom

Parsing fails when inline section contains symbols only

Regular expression in bake does not detect inline sections like:

<!--(bake-start _if="!item@last")--> | <!--(bake-end)-->

Workaround is to add some characters like:

<!--(bake-start _if="!item@last")-->&nbsp;|&nbsp;<!--(bake-end)-->

Feature Requests: Multiple Sources, Pass Option from Gruntfile

Hello,

I'm currently trying to make this work as a templating tool for basic websites and I'm running into a few places where an option or two would be very useful.

First, I'd love to be able to define more than one content section in the json file. For example:

            index: {
                options: {
                    section: ["index", "global"]
                },
                files: {
                    "dist/index.html": "src/index.html",
                }
            },

or instead:

        bake: {
            options: {
                content: "content.json"
            },
            index: {
                options: {
                    section: "index"
                },
                files: {
                    "dist/index.html": "src/index.html",
                }
            },

where in the second example, the index has access to the "index" section and every page has access to the "global" section. In the end, I'm running into an issue where you can't have dynamic content in a template (Page Title for example) and also have an include in that page.

I'd want to pass information to the _header.html file that I'm including at the top of each of the pages that has the site title. If every page had access to global, the content.json file could look like this:

{
    "global": {
        "siteTitle": "Awesome Site Title"
    },
    "index": {
        "h1": "Home Page"
    },
    "events": {
        "h1": "Events Listing Page"
    },
    "event1": {
        "eventName": "Event 1 Single Page"
    },
    "event2": {
        "eventName": "Event 2 Single Page"
    }
}

And you could have a site title, plus a page title and includes can have their own content.

Similar to this, if you pass a content source in your gruntfile and you also pass a content source in your template as _section, both could be available if multiple content sources were possible.

You can actually see in my gruntfile below that I have commented out the lines where I pass a section to the events list page. This is because if I have that line which passes the page title, then the _event.html includes I list do not get content passed to them (I get a grunt error saying content not found). So the script can't access more than one section in the json file, I believe.

The second feature request I have is that it would be great to be able to pass an option to a template from the gruntfile. For example, I have an _event.html partial that I use to create an event.html single page for that one event and I also reuse the same _event.html partial to create a list of all events inside events.html template. This is the standard blog format: single page for each post, but also a list of posts. Unfortunately there is no way to have _event.html use the header and footer sometimes and other times not. This is what I tried:

        bake: {
            options: {
                content: "content/global.json"
            },
            index: {
                options: {
                    section: "index"
                },
                files: {
                    "dist/index.html": "src/index.html",
                }
            },
            events: {
                // options: {
                //     section: "events"
                // },
                files: {
                    "dist/events.html": "src/events.html",
                }
            },
            event1: {
                options: {
                    section: "event1",
                    header: true
                },
                files: {
                    "dist/events/event1.html": "src/includes/_event.html",
                }
            },
            event2: {
                options: {
                    section: "event2",
                    header: true
                },
                files: {
                    "dist/events/event2.html": "src/includes/_event.html",
                }
            },
        },

You can see in event1 and event2 how I could pass "header: true" or something similar and this would allow me to make a full HTML page from the _event.html partial if the event partial file looked like this:

<!--(bake includes/_header.html _if="header")-->
<h1>{{eventName}}</h1>
<!--(bake includes/_footer.html _if="header")-->

In this way, I can use the _event partial to create a full page. I could also call the event partial many times inside the events.html list page:

<!--(bake includes/_header.html siteTitle="Salut Monde")-->

<h1>{{h1}}</h1>
<!--(bake includes/_event.html _section="event1")-->
<!--(bake includes/_event.html _section="event2")-->

<!--(bake includes/_footer.html)-->

Where above, the header and footer do not get appended to each event, since the page they are all getting included onto already has the header and footer.

Anyway, thought I'd pass on my thoughts!

Thanks,

Paul

Conditional Logic in the templates

Hello Mathias,

Do you consider adding if/else or any other conditional logic to bake? While using it, that is one of the things I find missing.

Thanks.

  • M

Resolve also right part in validateIf()

validateIf() currently only resolves the left part of an if-condition into the corresponding value. Especially when the meta information for loops #54 (and more recursion support ๐Ÿ˜‹) make their way into bake, it could be nice to evaluate variable against variable.

As may expected, I have implemented support for this (unfortunalty this is in the same PR as #54, sorry @MathiasPaumgarten for that).

Instead of default resolving the left part

var contentValue = resolveName( left, values );

we can check if the variable is present in the values hash and resolve it:

if( mout.object.has( values, left ) ) left = resolveName( left, values );
if( mout.object.has( values, right ) ) right = resolveName( right, values );

Have run all tests and had no fails.

Support for Meta-Information in foreach-loops

Following problem: I want to create a Bootstrap carousel. To make the carousel indicators work these need numeric ascending ids. Data for the carousel comes from a json file.

One solution could be to add the ids to the json, but that is unnecessary data-overhead (IMHO). So why not letting bake supply meta information about the loop like current iteration number, is this the last iteration, etc.

I came up with the following syntax, where bake injects variables composed of the variables key, an @-sign, and the information name.

...
<!--(bake-start _foreach="slide:slides")-->
    <li data-slide-to="{{slide@index}}">...</li>
<!--(bake-end)-->
...

This way, we can have additional information in the template without having name conflicts.

The extends to bake are pretty small, mainly some of these lines, where the forEachValues are processed.

forEachValues.forEach( function( value, index ) {
    values[ forEachName ] = value;
    // assign meta vars with information about current iteration
    values[ forEachName + "@index" ] = String( index );
    // ...

I already made an implementation and will create a PR in some minutes.

Minor flaw: The String()-casting. It's currently needed because otherwise 0 is not present in template because in resolveName() the || "" kicks in and returns an emptry string instead of 0.

Maybe this behavior can be changed together with #41

Special characters in Inline Attributes

Template does not compile when using inline attributes that contain special characters;

<!--(bake app/modules/module1.html title="A title with a question?")-->
<!--(bake app/modules/module1.html title="title's with a apostophe")-->

These won't compile.

Inline loops

As discussed in #9 there are simples _foreach loops so far. However those loops require to use a external file. I find myself to run into situations where I want to loop over a set of values but only bake a single line for each value. It seems cumbersome to create a seperate file for that.

For example:

<ul>
    <!--(bake menu/line.html _foreach="value:menu.items")-->
</ul>

with the menu/line.html being:

<li>{{value}}</li>

There should be an inline version like so:

<ul>
    <!--(bake-inline menu/line.html _foreach="value:menu.items")-->
        <li>{{value}}</li>
    <!--(bake end)-->
</ul>

Not sure about the syntax. Any suggestions?

Usage of variable in filename

I guy's,

In version 0.3.16, I was using code like this:
<\!--(bake /sources/pages/static-sample-contents/{{tab.content}}.html)-->

Yesterday, I update to the latest version of bake to have access to all new properties and fix. But my bake include doesn't work anymore because it bake doesn't parse the file name before testing if the file exists.
Error is ; Warning: Unable to read "sources/pages/static-sample-contents/{{tab.content}}.html" file (Error code: ENOENT). Use --force to continue.

Pass in parts of options.content as inline values

It would be useful to pass in object from the options.content as inline values.

If I pass this json in via the option.content ...

_myconfig.json_

{
  "myobject": [
    {
      "title": "Git ate the last mint"
    },
    {
      "title": "Git explodes"
    },
    {
      "title": "Waiter says ..."
    }
  ]
}

... i can reference it in a _foreach loop.

item.htm

<!--(bake-start _foreach="item:myobject")-->
<div class="item itmN">
  <h3>
    <a href="/url">{{item.title}}</a>
  </h3>
</div>
<!--(bake-end)-->

This is enough in most cases. But let's say you want to use a different set of data for the item.htm template there would need to be some way of passing in the object that should be used.

{
  "myobject": [
    {
      "title": "Git ate the last mint"
    },
    {
      "title": "Git explodes"
    },
    {
      "title": "Waiter says ..."
    }
  ], 
  "stars": [
    {
      "title": "Jupiter"
    },
    {
      "title": "Pluto. Yes Pluto."
    },
    {
      "title": "Mars"
    }
  ]
}

itemlist.htm

<div class="items">
  <!--(bake item.htm @list="myobject" )-->
  <!--(bake item.htm @list="stars" )-->
</div>

item.htm

<!--(bake-start _foreach="@list")-->
<div class="item itmN">
  <h3>
    <a href="/url">{{title}}</a>
  </h3>
</div>
<!--(bake-end)-->

Not sure about the @ sign, just used it to differentiate from a normal variable.

Am I making any sense ?

_foreach on objects

I have a json file to use in a _foreach:

{
    activites: [
        {
            titre: "ev 1",
            date: "",
            url: ""
        },
        {
            titre: "ev 2",
            date: "",
            url: ""
        },
        {
            titre: "ev 3",
            date: "",
            url: ""
        }
    ]
}

I am trying to loop over those objects and show a div for each, using

<!--(bake partials/activite.html.tpl _foreach="activite:activites")-->  

and partials/activite.html.tpl is a simple

<div>
<h2>titre: {{activites.titre}}</h2>
<!-- insert other fields here... -->
</div>

My Gruntfile.js has something like this for its bake task:

bake: {
  options: {
    activites: "app/activites.json",
    ...
  }
}

But I can't get it to work. I see how a simple case of an array holding strings work, but what about an array holding objects? What am I missing?

Include limitation

I've just found the limitation of including partial HTMLs.

HTML that includes the partial having around 300 lines will be chopped.

I hope this will be fixed soon.

Thanks.

Nested ifs and for-loops

I've been trying to do some templating that leads to nested if-statements or if-statements nested in for-loops. Is there any chance that nested statements like that can be added to the library?

<!--(bake remove when="")-->

HI,

i'm now using bake for a big site project and i'm very pleased with your plugin. I use it in a specific way that allow me to have real semantic html files as input (partial) and real semantic html files as output.

I've got component files that are included in module files that are included in layout files. Every files are semantic and can be viewed in a browser as real html files. I'm using the IF statement to remove <!doctype> when the files are included and to let the <!doctype> when the files are just baked.

. It's not a good usage but it work and all my files, src, output, baked, include, are semantic files and can be view in a browser as standalone files or included in another semantic file

I'm thinking that a <!doctype> could be a great feature to add to your plugin.

With this, it would be the only htlm recursive builder that could take semantic html files as input and deliver real semantic htlm file as output, included or baked. The purpose is to have an html builder that use html file syntax.

I've tried to make this possible but i'm an html/css guy not a javascript one :).

I hope i've been understandable ;).

thanks again for your great work on bake :).

wrap includes?

Is it possible to wrap includes? Lets say you have something called layout.html:

doctype html
html
  head
    /!(bake includes/_head.html)
  body.index
    /! (bake includes/_header.html)
    .row-wrapper
      .outer-container
        #content
          /! (bake includes/_sidebar.html)
          main role="content" 
            {{block_content}}

Is it possible to do something like this?:

/! (bake start includes/layout.html)
  contents of your file.
/! (bake end)

<!doctype html> or html Comments in <!--(bake-start)-->

Hi,

thanks for your great plugin :)

Don't know if this is considered as an issue but i'm trying to use html pattern inside the bake-start anchor.

when the <!doctype html> html is outside the bake anchor :

<!doctype html>
 <!--(bake-start _if="html5")-->
<html>
<head>
//some more html
<!--(bake-end)-->

it generates :

<!doctype html>
<html>
<head>
//some more html

when the <!doctype html&gt is inside the bake anchor :

 <!--(bake-start _if="html5")-->
<!doctype html>
<html>
<head>
//some more html
<!--(bake-end)-->

it generates :

 <!--(bake-start _if="html5")-->
<!doctype html>
<html>
<head>
//some more html
<!--(bake-end)-->

The same happens with HTML comments like

<!-- comments -->

thanks,

Consider indent

In order to create prettier files grunt-bake should include the indent at which the bake line is written:

    <div>
        <!--(bake some/include.html)-->
    </div>

with and include like this

<div>
    <h1>Title</h1>
</div>

should create

    <div>
        <div>
            <h1>Title</h1>
        </div>
    </div>

instead of

    <div>
        <div>
    <h1>Title</h1>
</div>
    </div>

Loops

First, nice work!

But as already mentioned in #2, loops would be fantastic :)

Getting data on key from array

Please, add support for getting data on key from array.

Example:

header.html:

<header>
  <ul class="menu">
    <!--(bake-start _foreach="menu:[page2,page3,page4]")
    <li class="menu__item">
      {{pages[menu].title}}
    </li>
    <!--(bake-end)
  </ul>
</header>

content.json:

{
  "pages": [
    "page1": {
      "title": "Page 1"
    },
    "page2": {
      "title": "Page 2"
    },
    "page3": {
      "title": "Page 3"
    },
    "page4": {
      "title": "Page 4"
    },
    "page5": {
      "title": "Page 5"
    }
  ]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.