View and Template Part
NodeAtlas works with a configuration with usage of webconfig.json
that allow its to scale and upgrade possibilities in a versatille way. For example, to create a website without JavaScript server-side (no controller), just add a template
parameter to each route.
It's still possible to use JavaScript inline into templates with the capabilities offer by template engine EJS2 used by NodeAtlas.
We will see all possibilities with couples of templates files together.
More one page
Below is a sample 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"
}
}
}
To run this set of file:
├─ templates/
│ ├─ index.htm
│ ├─ member.htm
│ └─ error.htm
└─ webconfig.json
with the addresses:
- http://localhost/ (responds to the root)
- http://localhost/member.html (will not respond if is POST requested)
- http://localhost/member-without-extension/ (will not respond if is GET requested)
- http://localhost/error.html (return of the plain-text content (without markup) with a 404)
Note : If templatesRelativePath is not present in "webconfig.json", template folder is templates. templatesRelativePath is useful only to change the name/path of directory.
Template shortcut
The configuration below is equivalent to the configuration section just above
{
"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"
}
}
}
because
"about.html": "about.htm",
is a shortcut for
"about.html": {
"template": "about.htm"
}
Obviously this shortcut is used only if template
is the only parameter to declare in the route.
Host images, fonts, CSS, JS, etc.
You can also host any file on your site in a public folder. For example, with this configuration:
{
"assetsRelativePath": "assets",
"routes": {
"/": {
"template": "index.htm"
}
}
}
and this set of files:
├─ assets/
│ ├─ stylesheets/
│ │ └─ common.css
│ ├─ javascript/
│ │ └─ common.js
│ └─ media/
│ └─ images/
│ └─ logo.png
├─ templates/
│ └─ index.htm
└─ webconfig.json
you will have access to the addresses:
- http://localhost/
- http://localhost/stylesheets/common.css
- http://localhost/javascript/common.js
- http://localhost/media/images/logo.png
Note : If assetsRelativePath is not present in "webconfig.json", default public folder is assets. assetsRelativePath is useful only to change the name/path of directory.
maxAge, Etag, etc.
It's possible to manage informations provided by NodeAtlas when a ressource is requested (like maxAge
, etag
, etc.) via the staticOptions
property in webconfig. For more informations, see the Express documentation about static files.
For exemple, for a devlopment webconfig, it's interresting to put the maxAge
to 0 in order to always get the last modifications into a file and avoid frenetic browser reload.
{
"staticOptions": {
"maxAge": 0
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
Manage inclusions to avoid redundancy code
You can segment your HTML codes to not repeat the redundant code such "head" part and "foot" part or any other code fragment:
{
"componentsRelativePath": "components",
"routes": {
"/": {
"template": "index.htm"
},
"/list-of-members/": {
"template": "members.htm"
}
}
}
with the following files:
├─ 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>Welcome</h1>
<p>This is the home page.</p>
</div>
<%- include('foot.htm') %>
templates/members.htm
<%- include('head.htm') %>
<div>
<h1>List of members</h1>
<p>It is the Members page.</p>
</div>
<%- include('foot.htm') %>
you will have access to the addresses:
Note : If componentsRelativePath is not present in "webconfig.json", default include folder is components. componentsRelativePath is useful only to change the name/path of directory.
Manage variations within the same template
It is possible with the same template and the same includes, generating pages with different content (useful in generation HTML assets mode). Activate the variations with the following configuration:
{
"commonVariation": "common.json",
"variationsRelativePath": "variations",
"routes": {
"/": {
"template": "template.htm",
"variation": "index.json",
},
"/list-of-members/": {
"template": "template.htm",
"variation": "members.json",
}
}
}
with the following files:
├─ 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": "Website title",
"classCssCommon": "common",
"classJsCommon": "common"
}
variations/index.json
{
"titlePage": "Welcome",
"classPage": "index",
"content": "<p>This is the home page.</p>"
}
variations/members.json
{
"titlePage": "List of members",
"classPage": "members",
"content": "<p>It is the Members page.</p>"
}
you will have access to the addresses:
Note : If variationsRelativePath is not present in "webconfig.json", default variations folder is variations. variationsRelativePath is useful only to change the name/path of directory.
Manage Multilingual
All languages on the same site
On the same principle, the variations can be used to create the same page, but in different languages:
{
"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 : In this example I decided to do without a common variation file, because I did not specify commonVariation. I also completely arbitrarily decided to rename my folder variations to languages.
with the following files:
├─ 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>"
}
you will have access to the addresses:
Note : By default is the languageCode root that determines the display language of the wesite. However, specifically by page language, we can be changed also the languageCode*. You should also know that once the site or page has a languageCode in the configuration, variations files must be placed in a subdirectory named with the languageCode.
Use only changes with the active multilingual
You may have noticed in the previous example that the landing.json
file was not in the en-gb/
or fr-fr/
. This is quite possible and means that will be used in languages that do not have it in their file.
Also, when a languageCode
is specified, NodeAtlas seek first hand the value in the corresponding folder file. If it was not there, so he went to fetch the parent folder (the one used as standard for variations without multilingual).
This will allow you, for example, to manage master language directly in the variation folder. So with the following example:
│
┊┉
├─ variations/
│ ├─ common.json
│ ├─ home.json
│ ├─ fr-fr
│ │ ├─ common.json
│ │ └─ home.json
┊┉
you can
- manage the version
en-gb
directly to the root ofvariations/
(as NodeAtlas find nothing inen-gb
then it uses the values of the root files) and - manage the
fr-fr
release in thefr-fr /
,
thus, if a sentence has not yet translated into a file fr-fr
, instead of returning an error, NodeAtlas return the root version or the versionen-gb
.
Each language has its configuration
You can also choose to configure each language in a "webconfig.json" different. With the following set of file:
├─ 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
you could have "webconfig.json» next:
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"
},
"/list-of-members/": {
"template": "members.htm",
"variation": "members.json"
}
}
}
and have access to addresses:
- http://localhost/
- http://localhost:81/english/
- http://localhost:81/english/
- http://localhost:81/english/members-list/
- http://localhost:82/francais/
- http://localhost:82/francais/list-of-members/
It is then possible to reverse proxy with Bouncy (for example) to bring all urls on port 80 to obtain:
- http://www.website.ext/
- http://www.website.ext/english/
- http://www.website.ext/english/
- http://www.website.ext/english/members-list/
- http://www.website.ext/francais/
- http://www.website.ext/francais/list-of-members/
Change the url parameters
By default, if you use the following configuration:
{
"routes": {
"/": {
"template": "index.htm"
}
}
}
This is the same to using it:
{
"httpHostname": "localhost",
"httpPort": 80,
"httpSecure": false,
"urlRelativeSubPath": "",
"routes": {
"/": {
"template": "index.htm"
}
}
}
and you will be access to the url: http://localhost/.
Then change the configuration to this:
{
"httpHostname": "127.0.0.1",
"httpPort": 7777,
"httpSecure": true,
"urlRelativeSubPath": "sub/folder",
"routes": {
"/": {
"template": "index.htm"
}
}
}
for access to : https://127.0.0.1:7777/sub/folder/
Create your own webconfig variables
Imagine two webconfigs in which we create our own variables as follows:
- "webconfig.json"
{
"routes": {
"/": {
"template": "index.htm"
}
},
"_minified": ""
}
- "webconfig.prod.json"
{
"routes": {
"/": {
"template": "index.htm"
}
},
"_minified": ".min"
}
with this set of files
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ │ └─ common.min.css
│ └─ javascript/
│ ├─ common.js
│ └─ common.min.js
├─ templates/
│ └─ index.htm
├─ webconfig.json
└─ webconfig.prod.json
and "index.htm" containing:
<!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>This is a test to get a file minify/unminify.</div>
<script type="text/javascript" src="javascript/common<%= webconfig._minified %>.js"></script>
</body>
</html>
To run (since the site folder) the the command:
\> node </path/to/>node-atlas/
We will have to address "http://localhost/" the following output with non-minified files:
<!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>This is a test to get a file minify/unminify.</div>
<script type="text/javascript" src="javascript/common.js"></script>
</body>
</html>
However, running the command:
\> node </path/to/>node-atlas/server.js --webconfig webconfig.prod.json
We will have to address "http://localhost/" the following output with minified files:
<!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>This is a test to get a file minify/unminify.</div>
<script type="text/javascript" src="javascript/common.min.js"></script>
</body>
</html>
Note : It is better to prefix his personal variables with "_" to avoid conflicts with existing or future configuration variables.
NodeAtlas use to generate HTML assets
Generate HTML assets
With the following configuration it is possible to generate HTML rendering assets of each page in a linked file. The file will be (re)created every display of page in your browser.
{
"htmlGeneratesBeforeResponse": true,
"generatesRelativePath": "generates",
"routes": {
"/": {
"template": "index.htm",
"generate": "/index.html"
},
"/list-of-members/": {
"template": "members.htm",
"generate": "/members/list.html"
},
"/list-of-members/?foo=bar": {
"template": "members.htm",
"generate": false
},
"/no/generate/property/": {
"template": "members.htm"
}
}
}
and the following set of files:
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ └─ javascript/
│ └─ common.js
├─ generates/
├─ templates/
│ ├─ index.htm
│ └─ members.htm
└─ webconfig.json
can physically create assets:
├─ assets/
│ ┊┉
├─ generates/
│ ├─ stylesheets/
│ │ ├─ common.css
│ ├─ javascript/
│ │ └─ common.js
│ ├─ index.html
│ ├─ members/
│ │ └─ list.html
│ └─ no/
│ └─ generate/
│ └─ property ⤆ Ceci est un fichier
├─ templates/
│ ┊┉
└─ webconfig.json
by going to the address:
Note : No generate page are generated for "/list-of-members/?foo=bar" because generate
is set to false
. Use this value to ignore a route generation.
The generation starts when displaying the page if htmlGeneratesBeforeResponse exist and if it is true. If it is passed false (or removed) the only way to generate all the pages of the website will be via the command node </path/to/>node-atlas/server.js --generate
will generate all pages once if generatesRelativePath
exist. Of course in all cases this command work and allow you to regenerate all pages after a change into all page (a change in a component called on all pages e.g.).
Also with --generate
, the entire assetsRelativePath
folder (public folder files) will be copied in the generatesRelativePath
if both folder does not have the same path, and if generatesRelativePath
exist. It really allows you to get the stand-alone pages you want in output folder with all files which they call (CSS / JS / Images, etc.).
You could desactivate the HTML generation, even if a directory generatesRelativePath
exist in the système file, with htmlGenerateEnable
à false
.
Note : If generatesRelativePath is not present in "webconfig.json", default generates folder is generates/. generatesRelativePath is useful only to change the name/path of directory.
Generate website without server side
You can also manager a simple HTML website page with the following configuration:
{
"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"
}
}
}
and the following set of files:
├─ HTML/
│ ├─ stylesheets/
│ │ └─ common.css
│ └─ javascript/
│ └─ common.js
└─ engine/
├─ variations/
│ ├─ fr-fr/
│ │ └─ index.json
│ └─ en/
│ └─ index.json
├─ templates/
│ └─ index.htm
└─ webconfig.json
To address http://localhost/ will show a list of pages your site components (with enableIndex set to true).
It will do more than, once your work is done, enjoy your HTML site in the folder:
└─ HTML/
├─ stylesheets/
│ └─ common.css
├─ javascript/
│ └─ common.js
├─ cv.html
└─ en/
└─ cv.html