The Progressive Server-side JavaScript Framework
You know HTML & CSS?
But not JavaScript?
Quickly create multilingual websites effortlessly with simple routes, views or variations.
JavaScript client-side Expert?
Ready to embrace Node.js?
Gradually improve your base as you need by using controllers, models or modules.
Already your Front-end habits?
You use Data Binding?
From Vanilla to jQuery and going through Vue, Angular or React: use your favorite tools!
NodeAtlas works with a configuration with the usage of webconfig.json
that allows its to scale and upgrade possibilities in a versatile way. For example, to create a website without JavaScript server-side (no controller), just add a view
parameter to each route.
It's still possible to use JavaScript inline into views with the capabilities offered by template engine EJS used by NodeAtlas by default.
We will see all possibilities with couples of view files together.
To display the content of a file behind an URL, we will register to the webconfig.json
some files. The accès address to this files are called routes, and the content of this routes is called a page.
Below is a sample configuration of webconfig.json
for many pages.
{
"viewsRelativePath": "views",
"routes": {
"/": {
"view": "index.htm"
},
"/member.html": {
"view": "member.htm",
"post": false
},
"/member-without-extension/": {
"view": "member.htm",
"get": false
},
"about.html": {
"view": "about.htm"
},
"/error.html": {
"view": "error.htm",
"statusCode": 404,
"mimeType": "text/plain"
}
}
}
To run this set of file:
├─ views/
│ ├─ about.htm
│ ├─ error.htm
│ ├─ index.htm
│ └─ member.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/about.html
(return « Cannot GET about.html » because route path must start by /
to be referenced),http://localhost/error.html
(return of the plain-text content (without markup) with a 404).Note: if viewsRelativePath
is not present in webconfig.json
, views folder is views
. viewsRelativePath
is useful only to change the name/path of directory.
The configuration below is equivalent to the configuration section just above
{
"viewsRelativePath": "views",
"routes": {
"/": "index.htm",
"/member.html": {
"view": "member.htm",
"post": false
},
"/member-without-extension/": {
"view": "member.htm",
"get": false
},
"about.html": "about.htm",
"/error.html": {
"view": "error.htm",
"statusCode": 404,
"mimeType": "text/plain"
}
}
}
because
"/": "index.htm",
is a shortcut for
"/": {
"view": "index.htm"
}
Obviously, this shortcut is used only if view
is the only parameter to declare in the route.
It's also possible to place routes into an array, that allows you to ordinate routes for an advanced usage in controllers section.
In this case, the path becomes the url
parameter.
{
"viewsRelativePath": "views",
"routes": [{
"url": "/",
"view": "index.htm"
}, {
"url": "/member.html",
"view": "member.htm",
"post": false
}, {
"url": "/member-without-extension/",
"view": "member.htm",
"get": false
}, {
"url": "about.html",
"view": "about.htm"
}, {
"url": "/error.html",
"view": "error.htm",
"statusCode": 404,
"mimeType": "text/plain"
}]
}
In order to not rewrite a long route list in webconfig.json
file to your development environment and webconfig.prod.json
to your production environment, you can group route in a file of your choice. By convention, the name is routes.json
file.
For example:
The following set of file
├─ views/
│ └─ index.htm
├─ webconfig.json
└─ webconfig.prod.json
with webconfig.json
{
"httpPort": 7777,
"routes": {
"/": {
"view": "index.htm"
}
}
}
and with webconfig.prod.json
{
"httpPort": 7776,
"httpHostname": "blog.lesieur.name",
"urlPort": 80,
"routes": {
"/": {
"view": "index.htm"
}
}
}
could be the following set of file
├─ views/
│ └─ index.htm
├─ routes.json
├─ webconfig.json
└─ webconfig.prod.json
with webconfig.json
{
"httpPort": 7777,
"routes": "routes.json"
}
with webconfig.prod.json
{
"httpPort": 7776,
"httpHostname": "blog.lesieur.name",
"urlPort": 80,
"routes": "routes.json"
}
and routes.json
{
"/": {
"view": "index.htm"
}
}
Note: you can create multiple route file as routes.en.json
and routes.fr.json
and associate each of them in a set of webconfig parameterize to run a website in various languages.
You can host any file on your site in a public folder like images, fonts, styles, scripts, etc.. For example, with this configuration:
{
"assetsRelativePath": "assets",
"routes": {
"/": {
"view": "index.htm"
}
}
}
and this set of files:
├─ assets/
│ ├─ stylesheets/
│ │ └─ common.css
│ ├─ javascripts/
│ │ └─ common.js
│ └─ media/
│ └─ images/
│ └─ logo.png
├─ views/
│ └─ index.htm
└─ webconfig.json
you will have access to the addresses:
http://localhost/
http://localhost/stylesheets/common.css
http://localhost/javascripts/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.
It's possible to manage HTTP headers provided when public resources are requested (like maxAge
, Etag
, etc.) via the staticOptions
property in webconfig. For more information, see the Express documentation about static files.
You can segment your HTML codes to not repeat the redundant code such "head" part and "foot" part or any other code fragment (don't worry, we will see later how to manage a mater page with head
and body
tags including opening and closing part into the same file).
webconfig.json
{
"routes": {
"/": {
"view": "index.htm"
},
"/list-of-members/": {
"view": "members.htm"
}
}
}
with the following files:
├─ assets/
│ ├─ stylesheets/
│ │ └─ common.css
│ └─ javascripts/
│ └─ common.js
├─ views/
│ ├─ partials/
│ │ ├─ head.htm
│ │ └─ foot.htm
│ ├─ index.htm
│ └─ members.htm
└─ webconfig.json
views/partials/head.htm
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<title>Hello world</title>
<link type="text/css" rel="stylesheet" href="stylesheets/common.css" media="all" />
</head>
<body>
views/partials/foot.htm
<script async type="text/javascript" src="javascripts/common.js"></script>
</body>
</html>
views/index.htm
<?- include("partials/head.htm") ?>
<div>
<h1>Welcome</h1>
<p>This is the home page.</p>
</div>
<?- include("partials/foot.htm") ?>
views/members.htm
<?- include("partials/head.htm") ?>
<div>
<h1>List of members</h1>
<p>It is the Members page.</p>
</div>
<?- include("partials/foot.htm") ?>
you will have access to the addresses:
http://localhost/
http://localhost/list-of-members/
Note: for more informations to the differences between <?
, <?-
, <?=
, etc. you can refer to the section emplate engine.
It is possible with the same view and the same includes, generating pages with different contents (useful in generation HTML assets mode). Activate the variations with the following configuration:
{
"variation": "common.json",
"variationsRelativePath": "variations",
"routes": {
"/": {
"view": "template.htm",
"variation": "index.json",
},
"/list-of-members/": {
"view": "template.htm",
"variation": "members.json",
}
}
}
with the following files:
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ │ ├─ index.css
│ │ └─ members.css
│ └─ javascripts/
│ ├─ common.js
│ ├─ index.js
│ └─ members.js
├─ variations/
│ ├─ common.json
│ ├─ index.json
│ └─ members.json
├─ views/
│ ├─ partials/
│ │ ├─ head.htm
│ │ └─ foot.htm
│ └─ template.htm
└─ webconfig.json
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>"
}
views/partials/head.htm
<!DOCTYPE html>
<html lang="en-us">
<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 ?>">
views/partials/foot.htm
<script async type="text/javascript" src="javascripts/<?= common.classJsCommon ?>.js"></script>
</body>
</html>
views/template.htm
<?- include("partials/head.htm") ?>
<div class="title"><?- common.titleWebsite ?></div>
<div>
<h1><?- specific.titlePage ?></h1>
<?- specific.content ?>
</div>
<?- include("partials/foot.htm") ?>
you will have access to the addresses:
http://localhost/
http://localhost/list-of-members/
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.
On the same principle, the variations can be used to create the same page, but in different languages (and different routes):
{
"languageCode": "en-us",
"variationsRelativePath": "l10n",
"routes": {
"/": {
"view": "landing.htm",
"variation": "landing.json"
},
"/home/": {
"view": "home.htm",
"variation": "home.json"
},
"/accueil/": {
"view": "home.htm",
"variation": "home.json",
"languageCode": "fr-fr"
}
}
}
Note: in this example, I use the common variation
property because I don't use a common.js
file. I also decided to rename my folder variations
to l10n
(localization).
with the following files:
├─ l10n/
│ ├─ landing.json
│ ├─ en-us
│ │ └─ home.json
│ └─ fr-fr
│ └─ home.json
├─ views/
│ ├─ partials/
│ │ ├─ head.htm
│ │ └─ foot.htm
│ ├─ landing.htm
│ └─ home.htm
└─ webconfig.json
l10n/landing.json
{
"titlePage": "Landing",
"classPage": "landing",
"selectLabel": [
"English",
"Français"
]
}
l10n/en-us/home.json
{
"titlePage": "Welcome",
"classPage": "home",
"content": "<p>This is a home page.</p>"
}
l10n/fr-fr/home.json
{
"titlePage": "Bienvenue",
"classPage": "home",
"content": "<p>C'est la page d'accueil.</p>"
}
views/partials/head.htm
<!DOCTYPE html>
<html lang="<?= languageCode ?>">
<head>
<meta charset="utf-8" />
<title><?= specific.titlePage ?></title>
</head>
<body class="<?= specific.classPage ?>">
views/partials/foot.htm
</body>
</html>
views/landing.htm
<?- include("partials/head.htm") ?>
<select>
<? for (var i = 0; i < specific.selectLabel.length; i++) { ?>
<option><?= specific.selectLabel[i] ?></option>
<? } ?>
</select>
<?- include("partials/foot.htm") ?>
views/home.htm
<?- include("partials/head.htm") ?>
<div>
<h1><?- specific.titlePage ?></h1>
<?- specific.content ?>
</div>
<?- include("partials/foot.htm") ?>
you will have access to the addresses:
http://localhost/
http://localhost/home/
http://localhost/accueil/
Note: by default is the languageCode
root that determines the display language of the wesite. It's also possible to change the page language with a languageCode
for a page. 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
.
You may have noticed in the previous example that the landing.json
file was not in the en-us/
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 a standard for variations without localization).
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:
en-us
directly to the root of variations/
(as NodeAtlas find nothing in en-us
then it uses the values of the root files) andfr-fr
release in the fr-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 version en-us
.
You can also choose to configure each language in a webconfig.json
different. With the following set of file:
├─ variations/
│ ├─ landing.json
│ ├─ en-us
│ │ ├─ home.json
│ │ └─ members.json
│ └─ fr-fr
│ ├─ home.json
│ └─ members.json
├─ views/
│ ├─ partials/
│ │ ├─ head.htm
│ │ └─ foot.htm
│ ├─ landing.htm
│ ├─ home.htm
│ └─ members.htm
├─ webconfig.json
├─ webconfig.en-us.json
└─ webconfig.fr-fr.json
you could have webconfig.json
next:
webconfig.json
{
"routes": {
"/": {
"view": "landing.htm",
"variation": "landing.json"
}
}
}
webconfig.en-us.json
{
"httpPort": 81,
"urlRelativeSubPath": "english",
"languageCode": "en-us",
"routes": {
"/": {
"view": "home.htm",
"variation": "home.json"
},
"/members-list/": {
"view": "members.htm",
"variation": "members.json"
}
}
}
webconfig.fr-fr.json
{
"httpPort": 82,
"urlRelativeSubPath": "francais",
"languageCode": "fr-fr",
"routes": {
"/": {
"view": "home.htm",
"variation": "home.json"
},
"/list-of-members/": {
"view": "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 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/
By default, if you use the following configuration:
webconfig.json
{
"routes": {
"/": {
"view": "index.htm"
}
}
}
with the following view :
views/index.htm
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<title>URLs</title>
</head>
<body>
<div><?- urlRootPath ?></div>
<div><?- urlSubPath ?></div>
<div><?- urlBasePath ?></div>
<div><?- urlFilePath ?></div>
<div><?- urlQueryPath ?></div>
<div><?- urlPath ?></div>
</body>
</html>
This is the same to use it:
webconfig.json
{
"httpHostname": "localhost",
"httpPort": 80,
"httpSecure": false,
"urlRelativeSubPath": "",
"routes": {
"/": {
"view": "index.htm"
}
}
}
and you will be access to the URL: http://localhost/
to see this content:
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<title>URLs</title>
</head>
<body>
<div>http://localhost</div>
<div></div>
<div>http://localhost</div>
<div>/</div>
<div></div>
<div>http://localhost/</div>
</body>
</html>
Then change the configuration to this:
{
"httpHostname": "127.0.0.1",
"httpPort": 7777,
"httpSecure": "security/server",
"urlRelativeSubPath": "sub/folder",
"routes": {
"/index.html": {
"view": "index.htm"
}
}
}
to access this time to : https://127.0.0.1:7777/sub/folder/index.html?test=ok
to see this content:
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<title>URLs</title>
</head>
<body>
<div>https://127.0.0.1:7777</div>
<div>/sub/folder</div>
<div>https://127.0.0.1:7777/sub/folder</div>
<div>/index.html</div>
<div>?test=ok</div>
<div>https://127.0.0.1:7777/sub/folder/index.html</div>
</body>
</html>
Note: this example work only if you have server.crt
and server.key
files valide into security/
folder. Try without "httpSecure": "security/server"
to see it work without https
in URLs.
Imagine two webconfigs in which we create our own variables as follows:
webconfig.json
{
"routes": {
"/": {
"view": "index.htm"
}
},
"_minified": ""
}
webconfig.prod.json
{
"routes": {
"/": {
"view": "index.htm"
}
},
"_minified": ".min"
}
with this set of files:
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ │ └─ common.min.css
│ └─ javascripts/
│ ├─ common.js
│ └─ common.min.js
├─ views/
│ └─ index.htm
├─ webconfig.json
└─ webconfig.prod.json
and index.htm
containing:
<!DOCTYPE html>
<html lang="en-us">
<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="javascripts/common<?= webconfig._minified ?>.js"></script>
</body>
</html>
To run (from the site folder) the command:
$ 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="javascripts/common.js"></script>
</body>
</html>
However, running the command:
$ node-atlas --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="javascripts/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.
Include a head part and foot part in two separate files create the following problem: tag from the head file are only closed into foot file. If you want to put all global things in the same file you could use a global view and indicate into where all views are injected. You can use all other mechanisms of view in this layout.
with this set of files
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ │ └─ index.css
│ └─ javascripts/
│ └─ common.js
├─ variations/
│ ├─ common.json
│ └─ index.json
├─ views/
│ ├─ partials/
│ │ └─ header.htm
│ ├─ about.htm
│ ├─ common.htm
│ └─ index.htm
└─ webconfig.json
and with the following webconfig:
webconfig.json
{
"view": "common.htm",
"variation": "common.json",
"routes": {
"/": {
"view": "index.htm",
"variation": "index.json"
},
"/about/": {
"view": "about.htm"
}
}
}
and this two variation files:
common.json
{
"titleWebsite": "Website Title",
"classCssCommon": "common",
"classJsCommon": "common"
}
index.json
{
"titlePage": "Welcome",
"classPage": "index",
"content": "<p>This is the Homepage.</p>"
}
you could create with this views:
views/common.htm
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<title><?- specific.titlePage || "No title" ?></title>
<link rel="stylesheet" href="stylesheets/<?= common.classCssCommon ?>.css" media="all">
<? if (specific.classPage) { ?>
<link rel="stylesheet" href="stylesheets/<?= specific.classPage ?>.css" media="all">
<? } ?>
</head>
<body>
<!-- Include a file in standard way -->
<?- include("partials/header.htm") ?>
<!-- Include the current `view` file -->
<?- include(routeParameters.view) ?>
<script async="true" type="text/javascript" src="javascripts/<?= common.classJsCommon ?>.js"></script>
</body>
</html>
views/partals/header.htm
<? if (specific.titlePage) { ?>
<header>
<h1><?= specific.titlePage ?></h1>
</header>
<? } ?>
views/index.htm
<div>
<?- specific.content ?>
</div>
views/about.htm
<div>
<h1>NodeAtlas © MachinisteWeb</h1>
</div>
an display the following URL:
/
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<title>Welcome</title>
<link rel="stylesheet" href="stylesheets/common.css" media="all">
<link rel="stylesheet" href="stylesheets/index.css" media="all">
</head>
<body>
<header>
<h1>Welcome</h1>
</header>
<div>
<p>This is the Homepage.</p>
</div>
<script async="true" type="text/javascript" src="javascripts/common.js"></script>
</body>
</html>
/about/
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="utf-8">
<title>Pas de titre</title>
<link rel="stylesheet" href="stylesheets/common.css" media="all">
</head>
<body>
<div>
<h1>NodeAtlas © MachinisteWeb</h1>
</div>
<script async="true" type="text/javascript" src="javascripts/common.js"></script>
</body>
</html>
It is possible to share more than only the assetsRelativePath
public directory. You could for example share views or models with to the client-side. We call them statics files.
We see the following example:
with this set of files
├─ models/
│ └─ user.js
├─ views/
│ └─ index.htm
└─ webconfig.json
webconfig.json
{
"statics": {
"/javascripts/models": "models"
},
"routes": {
"/": "index.htm"
}
}
views/index.htm
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<title>Statics</title>
</head>
<body>
<div id="user"></div>
<script src="javascripts/models/user.js"></script>
<script>
var user = new User(),
mount = document.getElementById("user");
user
.firstname("Bruno")
.lastname("Lesieur");
mount.innerHTML = user.firstname() + " " + user.lastname();
</script>
</body>
</html>
models/user.js
(function (expose, factory) {
if (typeof module !== 'undefined' && module.exports) {
module.exports = factory;
} else {
expose.User = factory;
}
}(this, function User() {
var privates = {},
publics = this;
publics.lastname = function (lastname) {
if (typeof lastname === 'undefined') {
return privates.lastname;
} else {
privates.lastname = lastname;
return publics;
}
};
publics.firstname = function (firstname) {
if (typeof firstname === 'undefined') {
return privates.firstname;
} else {
privates.firstname = firstname;
return publics;
}
};
}));
We can access to the HTML files http://localhost/
and JavaScript http://localhost/javascripts/user.js
.
It's possible to manage information provided by NodeAtlas when a static resource is requested (like maxAge
, Etag
, etc.) via the staticOptions
. In this case, the parameter is not a string
anymore but an Object
and the initial property become the path
parameter. By default, staticOptions
are the same as global webconfig (more information at Express documentation).
{
"statics": {
"/javascripts/models": {
"path": "models",
"staticOptions": {
"index": false
}
}
},
"routes": {
"/": "index.htm"
}
}
It's also possible to place routes into an array, that allows you to ordinate routes for an advanced usage in controllers section.
In this case, the path becomes the virtual
parameter.
{
"statics": [{
"virtual": "/javascripts/models",
"path": "models",
"staticOptions": {
"index": false
}
}],
"routes": {
"/": "index.htm"
}
}
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 the page in your browser.
{
"htmlGenerationBeforeResponse": true,
"assetsRelativePath": "../HTML/",
"serverlessRelativePath": "../HTML/",
"routes": {
"/": {
"view": "index.htm",
"output": "/index.html"
},
"/list-of-members/": {
"view": "members.htm",
"output": "/members/list.html"
},
"/list-of-members/?foo=bar": {
"view": "members.htm",
"output": false
},
"/no/output/parameter/": {
"view": "members.htm"
}
}
}
and the following set of files:
├─ HTML/
│ ├─ stylesheets/
│ │ ├─ common.css
│ └─ javascripts/
│ └─ common.js
├─ views/
│ ├─ index.htm
│ └─ members.htm
└─ webconfig.json
can physically create following output:
├─ HTML/
│ ├─ stylesheets/
│ │ └─ common.css
│ ├─ javascripts/
│ │ └─ common.js
│ ├─ index.html
│ ├─ members/
│ │ └─ list.html
│ └─ no/
│ └─ output/
│ └─ parameter ⤆ Ceci est un fichier
├─ views/
│ ┊┉
└─ webconfig.json
by going to the address:
http://localhost/
http://localhost/list-of-members/
http://localhost/no/output/parameter/
Note: no output page are generated for /list-of-members/?foo=bar
because output
is set to false
. Use this value to ignore a route generation.
The generation starts when displaying the page if htmlGenerationBeforeResponse
exists and if it is true
.
You can also manage a simple HTML website page with --generate
command.
If htmlGenerationBeforeResponse
is set to false
(or removed) the only way to generate all the pages of the website will be via the command node-atlas --generate
will generate all pages into serverlessRelativePath
only if global output
is set to true
.
Also with --generate
, the entire assetsRelativePath
folder (public folder files) will be copied in the serverlessRelativePath
if both folders does not have the same path only if global assetsCopy
is set to true
.
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.).
See this with the following configuration:
{
"output": true,
"assetsCopy": true,
"languageCode": "fr-fr",
"index": true,
"serverlessRelativePath": "serverless",
"routes": {
"/cv.html": {
"view": "index.htm",
"variation": "index.json"
},
"/en/cv.html": {
"view": "index.htm",
"variation": "index.json",
"languageCode": "en"
}
}
}
and the following set of files:
├─ assets/
│ ├─ stylesheets/
│ │ └─ common.css
│ └─ javascripts/
│ └─ common.js
├─ variations/
│ ├─ fr-fr/
│ │ └─ index.json
│ └─ en/
│ └─ index.json
├─ views/
│ └─ index.htm
└─ webconfig.json
With node-atlas --browse
, to address http://localhost/
will show a list of pages your site components (with "index": true
)
It will do more than, once --generate
was used, enjoy your HTML site in the folder:
┊┉
├─ serverless/
│ ├─ stylesheets/
│ │ └─ common.css
│ ├─ javascripts/
│ │ └─ common.js
│ ├─ cv.html
│ └─ en/
│ └─ cv.html
┊┉
Note: if serverlessRelativePath
is not present in webconfig.json
, default folder for generated files is serverless/
. serverlessRelativePath
is useful only to change the name/path of directory.
Files defined into statics
are also copyable into serverlessRelativePath
when you use --generate
. To allow this, you could use for each directory the parameter output
set to true
.
{
"statics": {
"/javascripts/models": {
"path": "models",
"output": true
}
},
}
By default, NodeAtlas already use EJS template engine, it's that allows you to use JavaScript between <?
and ?>
tags.
Tags <?
and ?>
allow you to include JavaScript into templates. There are many different tag format allow you to display JavaScript output into your template (in the same way you should with document.write
). See below:
<?
Opening 'scriptlet' tag by default for control-flow, no output provided.<?=
Outputs the value into the template (HTML escaped).<?-
Outputs the unescaped value into the template.<?#
Comment tag, no execution, no output.<?%
Outputs a literal <?
.?>
Plain ending tag.-?>
Trim-mode ('newline slurp') tag, trims following newline.However, EJS works by default with <%
and %>
. You could set this values or set others values if you want.
{
"templateEngineDelimiter": "%",
"routes": {
"/": {
"view": "index.htm"
}
}
}
For example, to include part of a file instruction is used <?- include("partials/head.htm") ?>
. It would be possible to do it with <%- include("partials/head") %>
with the configuration below:
See the example in files below:
webconfig.json
{
"templateEngineDelimiter": true,
"variation": "common.json",
"routes": {
"/": {
"view": "index.ejs",
"variation": "index.json"
}
}
}
variations/common.json
{
"titleWebsite": "Website Title",
"classCssCommon": "common",
"classJsCommon": "common"
}
variations/index.json
{
"titlePage": "Welcome",
"classPage": "index",
"content": "<p>This is the Homepage.</p>"
}
views/partials/head.ejs
<!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 %>">
views/partials/foot.ejs
<script async type="text/javascript" src="javascripts/<%= common.classJsCommon %>.js"></script>
</body>
</html>
views/index.ejs
<%- include("partials/head") %>
<div class="title"><%- common.titleWebsite %></div>
<div>
<h1><%- specific.titlePage %></h1>
<%- specific.content %>
</div>
<%- include("partials/foot") %>
Learn all about the possibilities of the template engine consult the documentation EJS.
Note: if nothing is set, templateEngineDelimiter
is set to ?
.
It's also possible to change EJS template to Pug Template Engine (new Jade template name) to generate pages with variations. This is possible for all pages like this:
{
"pug": true,
"routes": {
"/": {
"view": "index.pug"
},
"/contenu/": {
"view": "content.pug"
}
}
}
or just for one page like this:
{
"routes": {
"/": {
"view": "index.pug"
},
"/contenu/": {
"pug": true,
"view": "content.pug"
}
}
}
It's also possible to reset EJS only for one page.
{
"pug": true,
"routes": {
"/": {
"pug": false,
"view": "index.pug"
},
"/contenu/": {
"view": "content.pug"
}
}
}
We can see now an example with a set of files below:
webconfig.json
{
"pug": true,
"view": "common.pug",
"variation": "common.json",
"routes": {
"/": {
"view": "index.pug",
"variation": "index.json"
}
}
}
variations/common.json
{
"titleWebsite": "Website Title",
"classCssCommon": "common",
"classJsCommon": "common"
}
variations/index.json
{
"titlePage": "Welcome",
"classPage": "index",
"content": "<p>This is the Homepage.</p>"
}
views/common.pug
doctype html
html(lang="fr-fr")
head
meta(charset="utf-8")
title #{specific.titlePage}
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")
body(class=specific.classPage)
include partials/header
include #{routeParameters.view}
script(async, type="text/javascript", src="javascripts/" + common.classJsCommon + ".js")
views/partials/header.pug
h1 #{titleWebsite}
views/index.pug
div
h2 #{specific.titlePage}
| !{specific.content}
Learn all about the possibilities of the template engine consult the documentation Pug.
Note: if nothing is set, pug
is set to false
.
Vue is a progressive MVVM framework like Angular or React which can be used as a server template engine for NodeAtlas. The main useful feature is the client-side hydrate this code from the response of server and made reactivity and route with it!
Feel free to back to this section later because some controller mechanisms are used and will be explained later in the next chapter.
We propose us to set up an usage of Vue + Vue Router + Vue Server Renderer with the following command:
node-atlas --create hello-vue
then initialize project with the command
cd ./hello-vue/
npm install
and then, run it with the command
node-atlas --browse