Documentation

An overview of files, folders, helpers and partials.

Naturally, this site is made using Broccoli Taco. It’s hosted on Github Pages. The source can be viewed here.

Getting Started

Installing

Install the command line utility globally via NPM. This makes broccoli-taco new available everywhere.

npm install -g broccoli-taco

Creating a Site

To create a new site, run the new command with the folder name as an argument. Then, install dependencies and run the development server. Your new site should now be available at http://localhost:4200/.

broccoli-taco new my-site
cd my-site && npm install
broccoli-taco serve

Now you can start adding pages, assets, and data.

Building a Site

To build your entire site into a folder, you can run the build command with the destination folder as an argument. To compress assets, set the BROCCOLI_TACO_ENV variable to production.

broccoli-taco build dist
# or
BROCCOLI_TACO_ENV=production broccoli-taco build dist

Brocfile.js

Conguring the site happens in the top-level Brocfile.js. There is currenly 1 option to configure, which is the basePath. The following configuration could be used to serving the site at a path (i.e. http://other-site.com/docs) instead of the root path. This makes sure assets and link-to helpers render with the correct url.

var Site = require('broccoli-taco');
var site = new Site();

site.basePath = 'docs';

module.exports = site.toTree();

Folder Structure

Root Folder

The only top level files are site/, Brocfile.js and package.json. You can add others as needed (i.e. node_modules/, bower_components/).

  • site/
    This folder includes folders and files relevant to the entire site.

    • helpers/
      Handlebars helpers. Each helper should have its own file that exports a function. The filename is the name of the helper.

    • layouts/
      Layouts used by the layout helper. The file should contain a {{{yield}}}. This is where the page content will be rendered.

    • pages/
      The pages of the site. See the next section for details.

    • partials/
      Handlebars partials made available in the view (i.e. {{>header}}).

    • static/
      This folder is copied over as-is.

    • data.js
      Data made available to all templates as the site object (i.e. {{site.name}}). See the data section for more details.

    • site.scss
      CSS file included on every page.

    • site.js
      JavaScript file included on every page.

  • Brocfile.js
    Configure options here

  • package.json
    Declare you dependencies here like any other Node project.

Page Folder

Each folder within site/pages/ represents a page. Folders can contain other folders of pages.

  • pages/
    The first page folder is pages, making it the index page (i.e. broccoli-taco.com).

    • index.hbs
      The Handlebars template for the page. Here you can render partials, use helpers and access the global {{site}} object and the page-specific {{page}} object. This is the only required file for a page folder.

    • page.scss
      A SCSS file that gets compiled to CSS and included on the page. Useful if you have CSS only relevant to that specific page.

    • page.js
      A JavaScript file that gets Browserified. Useful if you have JavaScript only relevant to that specific page.

    • data.(js|json)
      The data provided by this file is exposed to the Handlebars template as the {{page}} object. It can be a JSON object, object literal, or a function returning a value or Promise. If an array is returned, a page for each item in the array is generated allowing you to use the same index.hbs template with a set of data (like a list of blog posts).

    • documentation/
      Any nested folder that has an index.hbs file becomes another page. For example, to add a page at broccoli-taco.com/documentation, you would create site/pages/documentation/index.hbs.


Templating

Variables and Data

Each index.hbs file can have a corresponding data.js file. The value of that file is made available to the template in the {{page}} namespace. The site can also have a global data file at site/data.js. Global data can be accessed through the {{site}} namespace.

/* site/pages/about/data.js
 * The following are equivalent
 * This can also be a JSON file: site/pages/about/data.json
 */

module.exports = {
  content: 'Foo Bar'
}

module.exports = function () {
  return {
    content: 'Foo Bar'
  }
}

module.exports = function () {
  return new RSVP.Promise(function (resolve) {
    resolve({
      content: 'Foo Bar'
    });
  });
}
<!-- site/pages/about/index.hbs -->

<h1>
  <!-- available in every template, defined in site/data.js -->
  {{site.title}}
</h1>
<p>
  <!-- only available in this template -->
  {{page.content}}
</p>

Dynamic Pages

To create a 1:N mapping between an index.hbs template and data you can return an array as the page’s data. The filename property is used as the path of the page. If no filename property is found, a hash of the data is used.

// site/pages/blog-post/data.js
var glob = require('glob');

module.exports = function () {
  var posts = glob.sync('**/*.md', {cwd: 'site/posts'});

  return posts.map(post, function (post) {
    var postTitle = path.basename(post, 'md');
    return {
      title: postTitle
    , body: fs.readFileSync(post).toString()
    , filename: postTitle.toLowerCase()
    }
  });
};
<!-- site/pages/blog-post/index.hbs -->
<h1>
  {{page.title}}
</h1>

{{#markdown}}
  {{page.body}}
{{/markdown}}

Assuming site/posts/Foo.md and site/posts/Bar.md, it would create pages at http://example.com/foo and http://example.com/bar using the site/pages/blog-post/index.hbs template.

Using Helpers

Any files in site/helpers/ will be treated as helpers. Each helper should have its own file and export a single function.

// site/helpers/first-name.js

module.exports = function (value) {
  return value.split(' ')[0];
};
<!-- site/pages/about/index.hbs -->
{{first-name site.author.name}}

Helpers can require other modules or files like a normal node program. For example, to create a markdown helper that can require a file or be used as a block:

// page/helpers/markdown.js
var marked = require('marked');

module.exports = function (value) {
  var input;
  if ('string' === typeof value) {
    input = fs.readFileSync(path.join('site/pages', value)+'.md').toString();
  } else if ('object' === typeof value) {
    input = value.fn(this).trim();
  }
  return new Handlebars.SafeString(marked(input));
}
<!-- site/pages/about/index.hbs -->

{{markdown "about/bio"}}

{{#markdown}}
# Contact
- [email](mailto:foo@bar.com)
{{/markdown}}

Using Partials

Partials should go in site/partials/. They work like regular Handlebars partials.

<!-- renders 'site/partials/footer.hbs' -->
{{>footer}}

Helpers

layout

arguments: ( [name] )
A block helper to wrap content in other markup. The layout file should include {{{yield}}} somewhere. Layouts can be nested inside each other.

<!-- defaults to 'site/layouts/default.hbs' -->
{{#layout}}
  <h1>Hello</h1>

  <!-- uses 'site/layouts/aricle.hbs' -->
  {{#layout 'article'}}
    <p>World</p>
  {{/layout}}

{{/layout}}

css-tags

arguments: (args…)
Adds fingerprinted site.css and page.css (when available) files to the page.

<!-- global 'site.css' and current page's 'page.css' -->
{{css-tags}}

<!-- only that page's 'page.css' -->
{{css-tags 'page'}}

<!-- only the global 'site.css' -->
{{css-tags 'site'}}

javascript-tags

arguments: (args…)
Adds fingerprinted site.js and page.js (when available) files to the page.

<!-- global 'site.js' and current page's 'page.js' -->
{{javascript-tags}}

<!-- only that page's 'page.js' -->
{{javascript-tags 'page'}}

<!-- only the global 'site.js' -->
{{javascript-tags 'site'}}

Naturally, this site is made using Broccoli Taco. It’s hosted on Github Pages. The source can be viewed here.