Partie View et Template

NodeAtlas fonctionne avec une configuration via l'utilisation d'un webconfig.json qui lui permet d'étendre les possibilités du site de manière évolutive tout au long de sa vie. Par exemple, pour créer un site sans JavaScript côté serveur (pas de controller), il suffit de ne renseigner qu'un template pour chaque route.

Cependant, vous pourrez toujours utilisé du JavaScript inline dans ses templates grâce à l'utilisation du moteur de template EJS2 avec lequel fonctionne NodeAtlas.

Voyons les possibilités de nos sites par agrégat simple de fichiers templates.

Plusieurs pages

Ci-dessous un exemple de configuration.

{
    "templatesRelativePath": "templates",
    "routes": {
        "/": {
            "template": "index.htm"
        },
        "/member.html": {
            "template": "member.htm",
            "postSupport": false
        },
        "/member-without-extension/": {
            "template": "member.htm",
            "getSupport": false
        },
        "about.html": {
            "template": "about.htm"
        },
        "/error.html": {
            "template": "error.htm",
            "statusCode": 404,
            "mimeType": "text/plain"
        }
    }
}

Pour faire tourner cet ensemble de fichier :

├─ templates/
│  ├─ index.htm
│  ├─ member.htm
│  └─ error.htm
└─ webconfig.json

aux adresses :

Note : Si templatesRelativePath n'est pas présent dans « webconfig.json », par défaut le dossier des templates est bien templates. templatesRelativePath est donc utile seulement pour changer le nom/chemin du répertoire.

Raccourci de template

La configuration ci-dessous est équivalente à la configuration de la section juste au-dessus

{
    "templatesRelativePath": "templates",
    "routes": {
        "/": "index.htm",
        "/member.html": {
            "template": "member.htm",
            "postSupport": false
        },
        "/member-without-extension/": {
            "template": "member.htm",
            "getSupport": false
        },
        "about.html": "about.htm",
        "/error.html": {
            "template": "error.htm",
            "statusCode": 404,
            "mimeType": "text/plain"
        }
    }
}

car

"about.html": "about.htm",

est un raccourci de

"about.html": {
    "template": "about.htm"
}

Évidemment ce raccourci ne sert que si template est le seul paramètre à déclarer de la route.

Héberger des images, polices, CSS, JS, etc.

Vous pouvez également héberger tout un tas de fichier sur votre site dans un dossier public. Par exemple avec cette configuration :

{
    "assetsRelativePath": "assets",
    "routes": {
        "/": {
            "template": "index.htm"
        }
    }
}

et cet ensemble de fichiers :

├─ assets/
│  ├─ stylesheets/
│  │  └─ common.css
│  ├─ javascript/
│  │  └─ common.js
│  └─ media/
│     └─ images/
│        └─ logo.png
├─ templates/
│  └─ index.htm
└─ webconfig.json

vous aurez accès aux adresses :

Note : Si assetsRelativePath n'est pas présent dans « webconfig.json », par défaut le dossier public est bien assets. assetsRelativePath est donc utile seulement pour changer le nom/chemin du répertoire.

maxAge, Etag, etc.

Il est possible de manager les informations livrées par NodeAtlas à la demande d'une ressource (comme le maxAge, l'etag, etc.) via la propriété staticOptions du webconfig. Pour connaître la totalité des possibilités, voir les options d'Express.

Par exemple, pour un webconfig de développement, il peut être intéressant de mettre le maxAge à 0 de manière à toujours avoir la dernière modification d'un fichier sans s'acharner sur le rechargement de page.

{
    "staticOptions": {
        "maxAge": 0
    },
    "routes": {
        "/": {
            "template": "index.htm"
        }
    }
}

Gérer des inclusions pour éviter la redondance du code

Vous pouvez segmenter vos codes HTML afin de ne pas répéter le code redondant comme par exemple les parties « head » et « foot » ou tout autre fragment de code :

{
    "componentsRelativePath": "components/",
    "routes": {
        "/": {
            "template": "index.htm"
        },
        "/liste-des-membres/": {
            "template": "members.htm"
        }
    }
}

avec les fichiers suivants :

├─ assets/
│  ├─ stylesheets/
│  │  └─ common.css
│  └─ javascript/
│     └─ common.js
├─ components/
│  ├─ head.htm
│  └─ foot.htm
├─ templates/
│  ├─ index.htm
│  └─ members.htm
└─ webconfig.json

components/head.htm

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title>Hello world</title>

        <link type="text/css" rel="stylesheet" href="stylesheets/common.css" media="all" />
    </head>
    <body>

components/foot.htm

        <script async type="text/javascript" src="javascript/common.js"></script>
    </body>
</html>

templates/index.htm

    <%- include('head.htm') %>

    <div>
        <h1>Bienvenue</h1>
        <p>C'est la page d'accueil.</p>
    </div>

    <%- include('foot.htm') %>

templates/members.htm

    <%- include('head.htm') %>

    <div>
        <h1>Liste des members</h1>
        <p>C'est la page des membres.</p>
    </div>

    <%- include('foot.htm') %>

vous aurez accès aux adresses :

Note : Si componentsRelativePath n'est pas présent dans « webconfig.json », par défaut le dossier des includes est bien components. componentsRelativePath est donc utile seulement pour changer le nom/chemin de répertoire.

Gérer des variations au sein d'un même template

Il est possible avec le même template et les mêmes includes de générer des pages au contenu différent (utile en mode génération d'assets HTML). Activer les variations avec la configuration suivante :

{
    "commonVariation": "common.json",
    "variationsRelativePath": "variations",
    "routes": {
        "/": {
            "template": "template.htm",
            "variation": "index.json",
        },
        "/liste-des-membres/": {
            "template": "template.htm",
            "variation": "members.json",
        }
    }
}

avec les fichiers suivants :

├─ assets/
│  ├─ stylesheets/
│  │  ├─ common.css
│  │  ├─ index.css
│  │  └─ members.css
│  └─ javascript/
│     ├─ common.js
│     ├─ index.js
│     └─ members.js
├─ components/
│  ├─ head.htm
│  └─ foot.htm
├─ variations/
│  ├─ common.json
│  ├─ index.json
│  └─ members.json
├─ templates/
│  └─ template.htm
└─ webconfig.json

components/head.htm

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title><%- specific.titlePage %></title>

        <link type="text/css" rel="stylesheet" href="stylesheets/<%= common.classCssCommon %>.css" media="all" />
        <link type="text/css" rel="stylesheet" href="stylesheets/<%= specific.classPage %>.css" media="all" />
    </head>
    <body class="<%= specific.classPage %>">

components/foot.htm

        <script async type="text/javascript" src="javascript/<%= common.classJsCommon %>.js"></script>
    </body>
</html>

templates/template.htm

    <%- include('head.htm') %>

    <div class="title"><%- common.titleWebsite %></div>

    <div>
        <h1><%- specific.titlePage %></h1>
        <%- specific.content %>
    </div>

    <%- include('foot.htm') %>

variations/common.json

{
    "titleWebsite": "Titre du site",
    "classCssCommon": "common",
    "classJsCommon": "common"
}

variations/index.json

{
    "titlePage": "Bienvenue",
    "classPage": "index",
    "content": "<p>C'est la page d'accueil.</p>"
}

variations/members.json

{
    "titlePage": "Liste des membres",
    "classPage": "members",
    "content": "<p>C'est la page des membres.</p>"
}

vous aurez accès aux adresses :

Note : Si variationsRelativePath n'est pas présent dans « webconfig.json », par défaut le dossier des variations est bien variations. variationsRelativePath est donc utile seulement pour changer le nom/chemin de répertoire.

Gérer le multilingue

Toutes les langues sur le même site

Sur le même principe, les variations peuvent être utilisées pour créer la même page, mais dans des langues différentes :

{
    "languageCode": "en-gb",
    "variationsRelativePath": "languages",
    "routes": {
        "/": {
            "template": "landing.htm",
            "variation": "landing.json"
        },
        "/home/": {
            "template": "home.htm",
            "variation": "home.json"
        },
        "/accueil/": {
            "template": "home.htm",
            "variation": "home.json",
            "languageCode": "fr-fr"
        }
    }
}

Note : Dans cet exemple j'ai décidé de me passer d'un fichier de variation commune, car je n'ai pas précisé de commonVariation. J'ai également totalement arbitrairement décidé de renommer mon dossier variations en languages.

avec les fichiers suivants :

├─ components/
│  ├─ head.htm
│  └─ foot.htm
├─ languages/
│  ├─ landing.json
│  ├─ en-gb
│  │  └─ home.json
│  └─ fr-fr
│     └─ home.json
├─ templates/
│  ├─ landing.htm
│  └─ home.htm
└─ webconfig.json

components/head.htm

<!DOCTYPE html>
<html lang="<%= languageCode %>">
    <head>
        <meta charset="utf-8" />
        <title><%= specific.titlePage %></title>
    </head>
    <body class="<%= specific.classPage %>">

components/foot.htm

    </body>
</html>

templates/landing.htm

    <%- include('head.htm') %>

    <select>
        <% for (var i = 0; i < specific.selectLabel.length; i++) { %>
        <option><%= specific.selectLabel[i] %></option>
        <% } %>
    </select>

    <%- include('foot.htm') %>

templates/home.htm

    <%- include('head.htm') %>

    <div>
        <h1><%- specific.titlePage %></h1>
        <%- specific.content %>
    </div>

    <%- include('foot.htm') %>

languages/landing.json

{
    "titlePage": "Landing",
    "classPage": "landing",
    "selectLabel": [
        "English",
        "Français"
    ]
}

languages/en-gb/home.json

{
    "titlePage": "Welcome",
    "classPage": "home",
    "content": "<p>This is a home page.</p>"
}

languages/fr-fr/home.json

{
    "titlePage": "Bienvenue",
    "classPage": "home",
    "content": "<p>C'est la page d'accueil.</p>"
}

vous aurez accès aux adresses :

Note : Par défaut c'est le languageCode racine qui conditionne la langue d'affichage du site. Cependant, spécifiquement par page on peut changer la langue avec également le languageCode. Il faut également savoir que dès que le site ou une page à un languageCode dans la configuration, ses fichiers de variations doivent être placées dans un sous répertoire portant le nom du languageCode.

Utiliser seulement les variations avec le multilingue actif

Vous avez peut-être constaté dans l'exemple précédent que le fichier landing.json n'était pas dans le dossier en-gb/ ou fr-fr/. Cela est tout à fait possible et signifie qu'il sera utilisé dans les langues qui ne le possèdent pas dans leur dossier.

Aussi, quand un languageCode est précisé, NodeAtlas part d'abord chercher la valeur dans le fichier du dossier correspondant. Si celle-ci n'y ai pas, alors il part la chercher dans le dossier parent (celui utilisé en standard pour les variations sans multilingue).

Cela va vous permettre par exemple de manager la langue maître directement dans le dossier de variation. Ainsi avec l'exemple suivant :

│
┊┉
├─ variations/
│  ├─ common.json
│  ├─ home.json
│  ├─ fr-fr
│  │  ├─ common.json
│  │  └─ home.json
┊┉

vous pouvez

ainsi, si une phrase n'est pas encore traduite dans un fichier fr-fr, au lieu de renvoyer une erreur, NodeAtlas renverra la version racine, soit la version en-gb.

À chaque langue sa configuration

Vous pouvez également décider de faire tourner chaque langue dans un « webconfig.json » différent. Avec l'ensemble de fichier suivant :

├─ components/
│  ├─ head.htm
│  └─ foot.htm
├─ variations/
│  ├─ landing.json
│  ├─ en-gb
│  │  ├─ home.json
│  │  └─ members.json
│  └─ fr-fr
│     ├─ home.json
│     └─ members.json
├─ templates/
│  ├─ landing.htm
│  ├─ home.htm
│  └─ members.htm
├─ webconfig.json
├─ webconfig.en-gb.json
└─ webconfig.fr-fr.json

vous pourriez avoir les « webconfig.json » suivant :

webconfig.json

{
    "routes": {
        "/": {
            "template": "landing.htm",
            "variation": "landing.json"
        }
    }
}

webconfig.en-gb.json

{
    "httpPort": 81,
    "urlRelativeSubPath": "english",
    "languageCode": "en-gb",
    "routes": {
        "/": {
            "template": "home.htm",
            "variation": "home.json"
        },
        "/members-list/": {
            "template": "members.htm",
            "variation": "members.json"
        }
    }
}

webconfig.fr-fr.json

{
    "httpPort": 82,
    "urlRelativeSubPath": "francais",
    "languageCode": "fr-fr",
    "routes": {
        "/": {
            "template": "home.htm",
            "variation": "home.json"
        },
        "/liste-des-membres/": {
            "template": "members.htm",
            "variation": "members.json"
        }
    }
}

et avoir accès aux adresses :

Il est ensuite possible de faire du reverse proxy avec Bouncy (par exemple) pour ramener l'ensemble des urls sur le port 80 afin d'obtenir :

Changer les paramètres d'url

Par défaut, si vous utilisez la configuration suivante :

{
    "routes": {
        "/": {
            "template": "index.htm"
        }
    }
}

cela est identique à utiliser celle-ci :

{
    "httpHostname": "localhost",
    "httpPort": 80,
    "httpSecure": false,
    "urlRelativeSubPath": "",
    "routes": {
        "/": {
            "template": "index.htm"
        }
    }
}

et vous pourrez accéder à l'url : http://localhost/.

Changez alors la configuration en ceci :

{
    "httpHostname": "127.0.0.1",
    "httpPort": 7777,
    "httpSecure": true,
    "urlRelativeSubPath": "sub/folder",
    "routes": {
        "/": {
            "template": "index.htm"
        }
    }
}

pour accéder à : https://127.0.0.1:7777/sub/folder/

Créer ses propres variables de webconfig

Imaginons deux webconfigs dans lesquels nous allons créer nos propres variables comme suit :

  1. « webconfig.json »
{
    "routes": {
        "/": {
            "template": "index.htm"
        }
    },
    "_minified": ""
}
  1. « webconfig.prod.json »
{
    "routes": {
        "/": {
            "template": "index.htm"
        }
    },
    "_minified": ".min"
}

avec cet ensemble de fichiers

├─ assets/
│  ├─ stylesheets/
│  │  ├─ common.css
│  │  └─ common.min.css
│  └─ javascript/
│     ├─ common.js
│     └─ common.min.js
├─ templates/
│  └─ index.htm
├─ webconfig.json
└─ webconfig.prod.json

et « index.htm » contenant :

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title>Hello world</title>
        <link rel="stylesheet" type="text/css" href="stylesheets/common<%= webconfig._minified %>.css" />
    </head>
    <body>
        <div>Ceci est un test de récupération de ressources minifiées/non-minifiées.</div>
        <script type="text/javascript" src="javascript/common<%= webconfig._minified %>.js"></script>
    </body>
</html>

En lançant (depuis le dossier du site) la commande :

\> node </path/to/>node-atlas/

Nous aurons à l'adresse « http://localhost/ » la sortie suivante avec les fichiers non minifiés :

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title>Hello world</title>
        <link rel="stylesheet" type="text/css" href="stylesheets/common.css" />
    </head>
    <body>
        <div>Ceci est un test de récupération de ressources minifiées/non-minifiées.</div>
        <script type="text/javascript" src="javascript/common.js"></script>
    </body>
</html>

Cependant en lançant la commande :

\> node </path/to/>node-atlas/server.js --webconfig webconfig.prod.json

Nous aurons à l'adresse « http://localhost/ » la sortie suivante avec les fichiers minifiés :

<!DOCTYPE html>
<html lang="fr-fr">
    <head>
        <meta charset="utf-8" />
        <title>Hello world</title>
        <link rel="stylesheet" type="text/css" href="stylesheets/common.min.css" />
    </head>
    <body>
        <div>Ceci est un test de récupération de ressources minifiées/non-minifiées.</div>
        <script type="text/javascript" src="javascript/common.min.js"></script>
    </body>
</html>

Note : Il vaut mieux préfixer ses variables personnelles avec « _ » pour éviter des conflits avec des variables de configuration existantes ou futures.

Utiliser NodeAtlas pour générer des maquettes HTML

Générer des assets HTML

Avec la configuration suivante il est possible de générer des assets HTML du rendu de chaque page dans un fichier associé. Le fichier sera (re)créé à chaque affichage de la page dans votre navigateur.

{
    "htmlGeneratesBeforeResponse": true,
    "generatesRelativePath": "generates",
    "routes": {
        "/": {
            "template": "index.htm",
            "generate": "/index.html"
        },
        "/liste-des-membres/": {
            "template": "members.htm",
            "generate": "/members/list.html"
        },
        "/liste-des-membres/?foo=bar": {
            "template": "members.htm",
            "generate": false
        },
        "/no/generate/property/": {
            "template": "members.htm"
        }
    }
}

et l'ensemble de fichiers suivant :

├─ assets/
│  ├─ stylesheets/
│  │  ├─ common.css
│  └─ javascript/
│     └─ common.js
├─ generates/
├─ templates/
│  ├─ index.htm
│  └─ members.htm
└─ webconfig.json

on peut créer physiquement les assets :

├─ assets/
│  ┊┉
├─ generates/
│  ├─ stylesheets/
│  │  ├─ common.css
│  ├─ javascript/
│  │  └─ common.js
│  ├─ index.html
│  ├─ members/
│  │  └─ list.html
│  └─ no/
│     └─ generate/
│        └─ property ⤆ Ceci est un fichier
├─ templates/
│  ┊┉
└─ webconfig.json

en se rendant aux adresses :

Note : Il n'y a pas de génération pour « /liste-des-membres/?foo=bar » car generate est à false. Utilisez cette valeur pour ignorer des routes à la génération.

La génération s'enclenche quand on affiche la page uniquement parce que htmlGeneratesBeforeResponse existe et est à true. S'il est passé à false (ou enlevé) le seul moyen de générer toutes les pages du site sera via la commande node </path/to/>node-atlas/server.js --generate qui génèrera toutes les pages d'un coup uniquement si le dossier de generatesRelativePath existe. Bien entendu dans tous les cas cette commande marche et permet de régénérer toutes les pages suite à un changement telle qu'une modification dans un composant appelé sur toutes les pages.

De plus avec --generate, l'intégralité du dossier assetsRelativePath (dossier des fichiers publiques) sera copié dans le dossier generatesRelativePath si les deux dossiers n'ont pas un chemin identique, et que generatesRelativePath existe. Cela vous permet réellement d'obtenir en sortie dans le dossier de génération des pages « stand-alone » avec l'intégralité des fichiers auxquelles elles font appel (CSS / JS / Images, etc.).

Vous pouvez également désactiver la génération, même si un dossier generatesRelativePath existe dans les dossiers, avec htmlGenerateEnable à false.

Note : Si generatesRelativePath n'est pas présent dans « webconfig.js », par défaut le dossier des générations est bien generates/. generatesRelativePath est donc utile seulement pour changer le nom/chemin répertoire.

Générer un site sans partie serveur

Il est également possible de manager la création d'un site en simple page HTML avec la configuration suivante :

{
    "languageCode": "fr-fr",
    "enableIndex": true,
    "htmlGeneratesBeforeResponse": true,
    "generatesRelativePath": "../HTML/",
    "assetsRelativePath": "../HTML/",
    "routes": {
        "/cv.html": {
            "template": "index.htm",
            "variation": "index.json"
        },
        "/en/cv.html": {
            "template": "index.htm",
            "variation": "index.json",
            "languageCode": "en"
        }
    }
}

et l'ensemble de fichiers suivant :

├─ HTML/
│  ├─ stylesheets/
│  │  └─ common.css
│  └─ javascript/
│     └─ common.js
└─ engine/
   ├─ variations/
   │  ├─ fr-fr/
   │  │  └─ index.json
   │  └─ en/
   │     └─ index.json
   ├─ templates/
   │  └─ index.htm
   └─ webconfig.json

À l'adresse http://localhost/ s'affichera la liste des pages composants votre site (grâce à enableIndex à true).

Il ne restera plus qu'à, une fois votre travail terminé, admirer votre site HTML dans le dossier :

└─ HTML/
   ├─ stylesheets/
   │  └─ common.css
   ├─ javascript/
   │  └─ common.js
   ├─ cv.html
   └─ en/
      └─ cv.html