Skip to content

Latest commit

 

History

History
232 lines (181 loc) · 4.03 KB

README.md

File metadata and controls

232 lines (181 loc) · 4.03 KB

ECMAScript Template

ECMAScript Template is a solution to write template in JavaScript. It's based on JsonML and ES2015.

Maybe ECMAScript Template challenges traditional design of template engine, and at first glance some of the ideas may seem crazy. Give it five minutes while reading this documentation.

Why

  • Easy to learn. It is just JavaScript and some conventions.
  • High-extensible.
    • It is just JavaScript, and we can apply any JavaScript trick to it.
    • JsonML is something like AST, and we can operate it easily.
  • Mature ecosystem.
    • Use the latest JavaScript features with Babel.
    • Lint your code style with ESLint.
    • And so on...

Usage

You can run the following code in CodePen.

const layout = (content) => (data) => {
  return [
    'html',
    [
      'head',
      ['title', 'ECMAScript Template'],
    ],
    [
      'body',
      content(data),
    ],
  ];
}

function home({ name }) {
  return [
    'h1',
    `Hello, ${name}!`,
  ];
}
home = layout(home);

const html = JsonML.toHTMLText(home({ name: 'Benjy' }));
console.log(html);

// Output
// <html>
//   <head>
//     <title>ECMAScript Template</title>
//   </head>
//   <body>
//     <h1>Hello, Benjy!</h1>
//   </body>
// </html>

Note: To simplify examples, we just use jsonml-html to convert JsonML to HTML. However, we can use any library to convert JsonML to any format.

Documentation

Version: 0.1.0-beta.0

Tags

An HTML element will be represented as an array, and the first item is tag name.

['br']
// =>
<br />

Attributes

If the second item in array is an object, it will be treated as attributes.

['a', { class: 'link', href: 'google.com' }, 'Google']
// =>
<a class='link' href='google.com'>Google</a>

// Attribute is not required
['h1', 'Hello world!']
// =>
<h1>Hello world!</h1>

Children

The rest items in array will be treated as children.

['ul',
  ['li', 'First.'],
  ['li', 'Second.'],
  ['li', 'Third.'],
]
// =>
<ul>
  <li>First.</li>
  <li>Second.</li>
  <li>Third.</li>
</ul>

Conditionals

const hour = 9;

['p',
  hour < 12 ? 'Good morning! ' : 'Good afternoon! ',
  'My friends',
]
// =>
<p>Good morning! My friends</p>

String Interpolation

const child = 'boy';

['p', `A ${child} will grow up to be a ${child === 'boy' ? 'man' : 'woman'}.`]
// =>
<p>A boy will grow up to be a man.</p>

Loop

['ul',
  ...['First.', 'Second.', 'Third.'].map((item) => ['li', item]),
]
// =>
<ul>
  <li>First.</li>
  <li>Second.</li>
  <li>Third.</li>
</ul>

Template

A template is a function which receives data and return JsonML.

function greeting({ name }) {
  return [
    'h1',
    `Hello, ${name}!`,
  ];
}

greeting({ name: 'Benjy' }); // => ['h1', 'Hello, Benjy']

Includes

Includes allow you to insert the contents into template.

function todoList({ todos}) {
  return [
    'ul',
    ...todos.map((todo) => ['li', todo]),
  ];
}

function todoApp(data) {
  return [
    'section',
    todoList(data),
  ];
}

todoApp({
  todos: [
    'eat',
    'sleep',
    'beat Doudou',
  ],
});

Layout

A layout is a HOF which receives blocks and return a template.

// layout.js
export default const layout = (content) => (data) => {
  return [
    'html',
    [
      'head',
      ['title', 'ECMAScript Template'],
    ],
    [
      'body',
      content(data),
    ],
  ];
}

Extends

To extends a layout, just pass blocks(templates) to layout.

// home.js
import layout from './layout';

function home(data) {
  return [
    'h1',
    `Hello, ${data.name}!`,
  ];
}

// Extends layout.
home = layout(home);

home({ name: 'Benjy' });

Liscense

MIT