node package manager

shimjs

ShimJS

the two similar api calls in the render chain should reuse data rather than running the api call again

module.exports = function (html, render, query, cb) {
    var user_get_params = {
        token:              query.token,
        requesting_user_id: query.user_id,
        user_id:            query.user_id
    };
    var chain = [['collection', 'navbar', 'user/get', user_get_params],
                 ['collection', 'title'],
                 ['collection', 'insert'],
                 ['collection', 'entry', 'collection/entry/get', {}],
                 ['collection', 'entry', 'collection/entry/get', {}]];
    render(html, chain, function (err, html) {
        if (err) return cb(err);
        return cb(null, html);
    });
};

ShimJS is an HTML/API templating system similar to AngularJS and ReactJS.

There are two major concerns with building a complicated website:

  1. Loading a page that has been prerendered with all appropriate data from the server.

  2. Updating a loaded with page with new data via pagination (next 10 results), addition (add an entry to a list), removal (remove an entry from a list), or update (following and unfollowing another user).

Project Setup

A ShimJS project is made up of two distinct parts that are shimmed together:

  1. The API folder which contains a directory tree representing the API, with files named fn.js representing API calls (containing the API logic). For example if our API directory was ./api_directory/:

    api_directory/
        user/
            get/
                fn.js
            update/
                fn.js
        collection/
            get/
                fn.js
            add/
                fn.js
            remove/
                fn.js

    The above directory would result in 5 available API calls:

    user/get
    user/update
    collection/get
    collection/add
    collection/remove
  2. The HTML folder which contains a directory tree representing the HTML page structure. The HTML structure does not have to match or resemble the API structure at all. For example if our HTML directory was ./html_directory/:

    html_directory/
        index.html
        user/
            profile.html
            profile_edit.html
            profile_card.html
        collection/
            display.html

    The above directory would result in 5 available HTML pages:

    index
    user/profile
    user/profile_edit
    user/profile_card
    collection/display

The Include Tag

Including one page in another and populating it with API data is done using include tags in HTML pages, and calling the render function.

  1. Including a file with no data.

    Syntax:

    <include id="header" file="header">

    Example:

    index.html

    <html>
        <include id="header" file="header">
        <body>This is my Page</body>
    </html>

    header.html

    <head>This is my header</head>

    rendered

    <html>
        <head>This is my header</head>
        <body>This is my Page</body>
    </html>
  2. Including a file with an object.

    Syntax:

    <include id="profile" file="profile">

    Example:

    index.html

    <html>
        <include id="profile" file="profile">
    </html>

    profile.html

    <img src="@(user.avatar)"><b>@(user.username)</b>
    <a href="user.html?user_id=@(user.user_id)&action=view">

    object

    {
        "user": {
            "avatar":  "http://img.com/myavatar",
            "username": "Willy",
            "user_id":  12345
        }
    }

    rendered

    <html>
        <img src="http://img.com/myavatar"><b>Willy</b>
        <a href="user.html?user_id=12345&action=view">
    </html>
  3. Conditionally including a file.

    Syntax:

    <include id="profile" file="profile" if="user.show">

    Example:

    index.html

    <html>
        <include id="profile" file="profile" if="user.show">
    </html>

    profile.html

    <img src="@(user.avatar)"><b>@(user.username)</b>
    <a href="user.html?user_id=@(user.user_id)&action=view">

    object

    {
        "user": {
            "avatar":  "http://img.com/myavatar",
            "username": "Willy",
            "user_id":  12345,
            "show":     false
        }
    }

    rendered

    <html>
        <include id="profile">
    </html>
  4. Including an array of objects using the same file.

    Syntax:

    <include id="profile" file="profile" for="users" each="user">

    Example:

    index.html

    <html>
        <include id="profile" file="profile" for="users" each="user">
    </html>

    profile.html

    <div class="card">
        <img src="@(user.avatar)"><b>@(user.username)</b>
        <a href="user.html?user_id=@(user.user_id)&action=view">
    </div>

    object

    {
        "users": [
            {
                "avatar":  "http://img.com/myavatar",
                "username": "Willy",
                "user_id":  12345
            },
            {
                "avatar":  "http://img.com/hisavatar",
                "username": "Jackson",
                "user_id":  12346
            },
            {
                "avatar":  "http://img.com/heravatar",
                "username": "April",
                "user_id":  12347
            },
        ]
    }

    rendered

    <html>
        <div class="card">
            <img src="http://img.com/myavatar"><b>Willy</b>
            <a href="user.html?user_id=12345&action=view">
        </div>
        <div class="card">
            <img src="http://img.com/hisavatar"><b>Jackson</b>
            <a href="user.html?user_id=12346&action=view">
        </div>
        <div class="card">
            <img src="http://img.com/heravatar"><b>April</b>
            <a href="user.html?user_id=12347&action=view">
        </div>
    </html>

todo:

  • make a true and false for conditional inclusion
  • conditional iterative inclusion?
  • recursive injection
  • what if we want to inject a json object itself and not the value of one of its keys
  • for in just a base array object
  • render_append
  • render_prepend