More Features
NodeAtlas offers also a large set of features for development or packaging with the configuration sytem. We will see that.
Manage routing (URL Rewriting)
Although you can configure static urls, you can also set of dynamic url!
Standard
With the following configuration:
{
"routes": {
"/list-of-members/:member/": {
"template": "members.htm"
},
"/list-of-members/": {
"template": "members.htm"
},
"/": {
"template": "index.htm"
}
}
}
you can access:
- http://localhost/
- http://localhost/list-of-members/
- http://localhost/list-of-members/toto/
- http://localhost/list-of-members/bob-eponge99/
- http://localhost/list-of-members/node-atlas/
- http://localhost/list-of-members/etc/
and retrieve the :member
value inchangeVariation
(common and specific).
exports.changeVariation = function (params, next) {
var variation = params.variation;
console.log(variation.params.member);
// \> 'toto', 'bob-eponge99', 'node-atlas' or 'etc'.
next(variation);
}
Dynamic url creation rules are those of Express.js.
Regular Expressions
You can also enable regular expressions to a specific path with regExp
. If it is true
, the previous profile no longer works and you pass in Regular Expression mode. If regExp
is a string, it acts as a flag (g, i, m or y).
See the following configuration:
{
"routes": {
"/list-of-members/([-a-z0-9]+)/?": {
"template": "members.htm",
"regExp": "g"
},
"/list-of-members/?": {
"template": "members.htm",
"regExp": true
},
"/": {
"template": "index.htm"
}
}
}
you can access:
- http://localhost/
- http://localhost/list-of-members/ (ou https://localhost/list-of-members)
- http://localhost/list-of-members/toto/ (ou https://localhost/list-of-members/toto)
- http://localhost/list-of-members/bob-eponge99/ (ou https://localhost/list-of-members/bob-eponge99)
- http://localhost/list-of-members/node-atlas/ (ou https://localhost/list-of-members/node-atlas)
- http://localhost/list-of-members/etc/ (ou https://localhost/list-of-members/etc)
and retrieve the ([-a-z0-9] +) value in the
changeVariation
(common and specific).
exports.changeVariation = function (params, next) {
var variation = params.variation;
if (variation.params && variation.params[0]) { variation.params.member = variation.params[0]; }
// variation.params[1] for second match, etc...
console.log(variation.params.member);
// \> 'toto', 'bob-eponge99', 'node-atlas' or 'etc'.
next(variation);
}
The rules for creating dynamic url with regExp
are those of RegExpJavaScript.
Routing in a shared file
In order to not rewrite a long route list in webconfig.json
file to your development environment andwebconfig.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
├─ templates/
│ └─ index.htm
├─ webconfig.json
└─ webconfig.prod.json
with webconfig.json
{
"httpPort": 7777,
"routes": {
"/": {
"template": "index.htm"
}
}
}
and with webconfig.prod.json
{
"httpPort": 7776,
"httpHostname": "blog.lesieur.name",
"urlPort": 80,
"routes": {
"/": {
"template": "index.htm"
}
}
}
could be the following set of file
templates/
— 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
{
"/": {
"template": "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.
Manage a page not found
Listen all urls, and also file provide by assetsRelativePath
To display a custom page when a resource is not found you must:
- Prepare a 404 page.
- Fill the parameter with
pageNotFound
with the followingvalue
:key
of the prepared 404 page.
See the example below:
{
"pageNotFound": "/not-found-page/",
"routes": {
"/list-of-members/": {
"template": "members.htm"
},
"/": {
"template": "index.htm"
},
"/not-found-page/": {
"template": "error.htm",
"statusCode": 404
}
}
}
you can access to:
- http://localhost/this-page-do-not-exist.html
- http://localhost/this/page/either/
- http://localhost/etc
Multilingual Error Page
For this, just create a new route with *
at the end with the languageCode.
See below :
{
"pageNotFound": "/not-found-page/",
"languageCode": "en-gb",
"routes": {
"/list-of-members/": {
"template": "members.htm",
"variation": "members.json"
},
"/": {
"template": "index.htm",
"variation": "index.json"
},
"/not-found-page/": {
"template": "error.htm",
"variation": "error.json",
"statusCode": 404
},
"/francais/liste-des-membres/": {
"template": "members.htm",
"languageCode": "fr-fr",
"variation": "members.json"
},
"/francais/": {
"template": "index.htm",
"languageCode": "fr-fr",
"variation": "index.json"
},
"/francais/*": {
"template": "error.htm",
"languageCode": "fr-fr",
"variation": "error.json",
"statusCode": 404
}
}
}
Manage redirects
To go to a different address (redirect 301 or 302) when you get to a url you must use the redirect
parameter.
Note : if you don't set statusCode
, no redirect will be executed. The statusCode
is mandatory for redirection.
Static
See the example below:
{
"routes": {
"/list-of-members/": {
"template": "members.htm"
},
"/list-of-members": {
"redirect": "/list-of-members/",
"statusCode": 301
},
"/go-to-node-atlas/": {
"redirect": "https://node-atlas.js.org/",
"statusCode": 302
},
"/": {
"template": "index.htm"
}
}
}
You will be redirected:
- to
http://localhost/list-of-members/
when you accesshttp://localhost/list-of-members
with a header permanent redirect. - to
https://node-atlas.js.org/
when you accesshttp://localhost/go-to-node-atlas/
with a header temporary redirect.
Dynamic
See the example below:
{
"routes": {
"/list-of-members/:member/": {
"template": "members.htm"
},
"/list-of-members/:member": {
"redirect": "/membres/:member/",
"statusCode": 301
},
"/": {
"template": "index.htm"
}
}
}
You will be redirected to http://localhost/list-of-members/haeresis/
when you access to http://localhost/list-of-members/haeresis
with a header permanent redirect.
With regular expressions
See the example below:
{
"routes": {
"/membres/([-a-z0-9]+)/": {
"template": "members.htm",
"regExp": true
},
"/list-of-members/([-a-z0-9]+)/": {
"redirect": "/membres/$0/",
"statusCode": 301,
"regExp": true
},
"/list-of-members/": {
"template": "members.htm"
},
"/": {
"template": "index.htm"
}
}
}
You will be redirected to http://localhost/list-of-members/haeresis/
when you access to http://localhost/list-of-members/haeresis
with a header permanent redirect.
For the second match use $1, the third $2, etc.
Manage Headers
By défault, sent Headers by NodeAtlas are followings: Content-Type:text/html; charset=utf-8
with a 200 statusCode
.
It's possible to modify this values for a specific route (for local API for example).
{
"routes": {
"/api/articles": {
"template": "display-json.htm",
"controller": "blog/list-of-articles.js",
"mimeType": "application/json"
"charset": "ISO-8859-1",
"statusCode": 203
}
}
}
It's also possible to modify all Headers values, this erase all shortcuts before, except the statusCode
.
{
"routes": {
"/api/articles": {
"template": "display-json.htm",
"controller": "blog/list-of-articles.js",
"statusCode": 203,
"headers": {
"Content-Type": "application/json; charset=utf-8",
"Access-Control-Allow-Origin": "*"
}
}
}
}
Run Website with HTTPs
It is very simple to run an instance of NodeAtlas with HTTPs protocol. You just have to create such a security
folder in which to place your server.key
and server.crt
file to supply the protocol.
Just use the following configuration:
{
"httpSecure": true,
"httpSecureRelativeKeyPath": "security/server.key",
"httpSecureRelativeCertificatePath": "security/server.crt",
"routes": {
"/": {
"template": "index.htm"
}
}
}
Alternatively , if your two Key and Certificate files have the same name, use this configuration:
{
"httpSecure": "security/server",
"routes": {
"/": {
"template": "index.htm"
}
}
}
This is also possible to just set the httpSecure
value to true
for get a "https" like urlBasePath
or urlBase
in your paths variables. But the server will not running in HTTPs and you will validate certificate by your own other way (with a server proxy for example).
{
"httpSecure": true,
"routes": {
"/": {
"template": "index.htm"
}
}
}
Note : in production, if you use a proxy for redirect request/response, don't forget use urlPort: 443
instead of urlPort: 80
for HTTPs.
Minify CSS / JS
You can automatically generate CSS and JS files minified and obfuscated by creating Bundles by referencing the file by input and output path. Of course you can do as much as you want. The gereration files is execute every time you start NodeAtlas either as a server or via the --generate
command if a Bundle exists in the Webconfig.
Creating Bundles
With the following configuration:
{
"bundles": {
"javascript": {
"javascript/boot.min.js": [
"javascript/modernizr.js",
"javascript/yepnot.js",
"javascript/html5Shiv.js"
],
"javascript/framework.min.js": [
"javascript/jquery.js",
"javascript/jquery-ui.js",
"javascript/prettify.js",
"javascript/prettify/run_prettify.js"
],
"javascript/common.min.js": [
"javascript/components/extended-format-date.js",
"javascript/common.js"
]
},
"stylesheets": {
"stylesheets/common.min.css": [
"stylesheets/common.css",
"stylesheets/common-min780.css",
"stylesheets/common-min1160.css"
]
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
and the following set of file:
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ │ ├─ common-min780.css
│ │ └─ common-min1160.css
│ └─ javascript/
│ ├─ modernizr.js
│ ├─ yepnot.js
│ ├─ html5Shiv.js
│ ├─ jquery.js
│ ├─ jquery-ui.js
│ ├─ prettify.js
│ ├─ prettify/
│ │ └─ run_prettify.js
│ ├─ components/
│ │ └─ extended-format-date.js
│ └─ common.js
├─ templates/
│ └─ index.htm
└─ webconfig.json
you will get the following new files:
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ │ ├─ common-min780.css
│ │ ├─ common-min1160.css
│ │ └─ common.min.css ⤆ new file
│ └─ javascript/
│ ├─ modernizr.js
│ ├─ yepnot.js
│ ├─ html5Shiv.js
│ ├─ jquery.js
│ ├─ jquery-ui.js
│ ├─ prettify.js
│ ├─ prettify/
│ │ └─ run_prettify.js
│ ├─ components/
│ │ └─ extended-format-date.js
│ ├─ common.js
│ ├─ boot.min.js ⤆ new file
│ ├─ framework.min.js ⤆ new file
│ └─ common.min.js ⤆ new file
├─ templates/
│ └─ index.htm
└─ webconfig.json
Bundles in a shared file
In order to not re-write a long Bundles configuration list in webconfig.json
file to your development environment andwebconfig.prod.json
to your production environment, you can group routes in a file of your choice. By convention, the name is bundles.json
file.
For example:
The following set of file
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ │ ├─ common-min780.css
│ │ └─ common-min1160.css
│ └─ javascript/
│ ├─ modernizr.js
│ ├─ yepnot.js
│ ├─ html5Shiv.js
│ ├─ jquery.js
│ ├─ jquery-ui.js
│ ├─ prettify.js
│ ├─ prettify/
│ │ └─ run_prettify.js
│ ├─ components/
│ │ └─ extended-format-date.js
│ └─ common.js
├─ templates/
│ └─ index.htm
├─ webconfig.json
└─ webconfig.prod.json
with webconfig.json
{
"httpPort": 7777,
"bundles": {
"javascript": {
"javascript/boot.min.js": [
"javascript/modernizr.js",
"javascript/yepnot.js",
"javascript/html5Shiv.js"
],
"javascript/framework.min.js": [
"javascript/jquery.js",
"javascript/jquery-ui.js",
"javascript/prettify.js",
"javascript/prettify/run_prettify.js"
],
"javascript/common.min.js": [
"javascript/components/extended-format-date.js",
"javascript/common.js"
]
},
"stylesheets": {
"stylesheets/common.min.css": [
"stylesheets/common.css",
"stylesheets/common-min780.css",
"stylesheets/common-min1160.css"
]
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
and with webconfig.prod.json
{
"httpPort": 7776,
"httpHostname": "blog.lesieur.name",
"urlPort": 80,
"bundles": {
"javascript": {
"javascript/boot.min.js": [
"javascript/modernizr.js",
"javascript/yepnot.js",
"javascript/html5Shiv.js"
],
"javascript/framework.min.js": [
"javascript/jquery.js",
"javascript/jquery-ui.js",
"javascript/prettify.js",
"javascript/prettify/run_prettify.js"
],
"javascript/common.min.js": [
"javascript/components/extended-format-date.js",
"javascript/common.js"
]
},
"stylesheets": {
"stylesheets/common.min.css": [
"stylesheets/common.css",
"stylesheets/common-min780.css",
"stylesheets/common-min1160.css"
]
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
could be the following set of file
├─ assets/
│ ├─ stylesheets/
│ │ ├─ common.css
│ │ ├─ common-min780.css
│ │ └─ common-min1160.css
│ └─ javascript/
│ ├─ modernizr.js
│ ├─ yepnot.js
│ ├─ html5Shiv.js
│ ├─ jquery.js
│ ├─ jquery-ui.js
│ ├─ prettify.js
│ ├─ prettify/
│ │ └─ run_prettify.js
│ ├─ components/
│ │ └─ extended-format-date.js
│ └─ common.js
├─ templates/
│ └─ index.htm
├─ bundles.json ⤆ new file
├─ webconfig.json
└─ webconfig.prod.json
with webconfig.json
{
"httpPort": 7777,
"bundles": "bundles.json",
"routes": {
"/": {
"template": "index.htm"
}
}
}
with webconfig.prod.json
{
"httpPort": 7776,
"httpHostname": "blog.lesieur.name",
"urlPort": 80,
"bundles": "bundles.json",
"routes": {
"/": {
"template": "index.htm"
}
}
}
and bundles.json
{
"javascript": {
"javascript/boot.min.js": [
"javascript/modernizr.js",
"javascript/yepnot.js",
"javascript/html5Shiv.js"
],
"javascript/framework.min.js": [
"javascript/jquery.js",
"javascript/jquery-ui.js",
"javascript/prettify.js",
"javascript/prettify/run_prettify.js"
],
"javascript/common.min.js": [
"javascript/components/extended-format-date.js",
"javascript/common.js"
]
},
"stylesheets": {
"stylesheets/common.min.css": [
"stylesheets/common.css",
"stylesheets/common-min780.css",
"stylesheets/common-min1160.css"
]
}
}
Note : it is possible to disable Bundles by not including them in the webconfig
.
Disable Bundles
It is also possible to not execute the minification when run a website with NodeAtlas with "stylesheetsBundlesEnable": false
et `"javascriptBundlesEnable": false`` for each type of Bundle.
{
"stylesheetsBundlesEnable": false,
"javascriptBundlesEnable": false,
"bundles": {
"javascript": {
"javascript/boot.min.js": [
"javascript/modernizr.js",
"javascript/yepnot.js",
"javascript/html5Shiv.js"
],
"javascript/framework.min.js": [
"javascript/jquery.js",
"javascript/jquery-ui.js",
"javascript/prettify.js",
"javascript/prettify/run_prettify.js"
],
"javascript/common.min.js": [
"javascript/components/extended-format-date.js",
"javascript/common.js"
]
},
"stylesheets": {
"stylesheets/common.min.css": [
"stylesheets/common.css",
"stylesheets/common-min780.css",
"stylesheets/common-min1160.css"
]
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
Note : if your bundle is in shared file, you could desactivated it also without the "bundles": "bundles.json"
. Just remove it.
Re-generate Bundles before each Page Response
For test your page with minified files, you can ask it to be regenerated before each page response with "stylesheetsBundlesBeforeResponse": false
et `"javascriptBundlesBeforeResponse": false`` for each type of Bundle.
{
"stylesheetsBundlesBeforeResponse": false,
"javascriptBundlesBeforeResponse": false,
"bundles": {
"javascript": {
"javascript/boot.min.js": [
"javascript/modernizr.js",
"javascript/yepnot.js",
"javascript/html5Shiv.js"
],
"javascript/framework.min.js": [
"javascript/jquery.js",
"javascript/jquery-ui.js",
"javascript/prettify.js",
"javascript/prettify/run_prettify.js"
],
"javascript/common.min.js": [
"javascript/components/extended-format-date.js",
"javascript/common.js"
]
},
"stylesheets": {
"stylesheets/common.min.css": [
"stylesheets/common.css",
"stylesheets/common-min780.css",
"stylesheets/common-min1160.css"
]
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
Note : this is not recommanded for production environment because it's slowed responses pages.
CSS generation with Less
You can use the preprocessor Less to create your CSS. The operation is as follows: whenever a CSS request is made, if a Less equivalent exists it is read and it generates the CSS. Once done, the new CSS is responded.
With the following structure:
├─ assets/
│ └─ stylesheets
│ └─ common.less
├─ templates/
│ └─ index.htm
└─ webconfig.json
and the following webconfig:
{
"enableLess": true,
"routes": {
"/": "index.htm"
}
}
and the following content in:
templates/index.htm
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Less Test</title>
<link rel="stylesheet" href="stylesheets/common.css">
</head>
<body>
<p>This line is red.</p>
</body>
</html>
assets/stylesheets/common.less
p {
color: #f00;
}
you will build the assets/stylesheets/common.css
by calling the url http://localhost/
or http://localhost/stylesheets/common.css
.
Source Map and Minification
By default, in the above example, a common.css.map
file will be generated. This allows your browser to indicated you that line in .less
file has generated the CSS property of the item you have selected in your debugger.
Disable this with enableLess.sourceMap
to false
:
"enableLess": {
"sourceMap": false
},
"routes": {
"/": "index.htm"
}
You can also generate CSS files already minify with:
"enableLess": {
"compress": true
},
"routes": {
"/": "index.htm"
}
Compile Less files with --generate
Because of Less are compilated on the fly, when a file is requested in http(s), modification needed running website for generate CSS output. Then you can use CSS. It's possible to skip running step and directly complated Less before minify CSS with enableLess.less
.
With the following webconfig.json
:
{
"enableLess": {
"less": [
"stylesheets/common.less",
"stylesheets/component-1.less",
"stylesheets/component-2.less",
"stylesheets/component-3.less"
]
},
"routes": {
"/": "index.htm"
}
}
or with the following webconfig.json
:
{
"enableLess": {
"less": "less.json"
},
"routes": {
"/": "index.htm"
}
}
with less.json
containing :
[
"stylesheets/common.less",
"stylesheets/component-1.less",
"stylesheets/component-2.less",
"stylesheets/component-3.less"
]
The @import
used by Less will be capable to walk into subdirectories : styles
, stylesheets
or css
. It's possible to change that with :
{
"enableLess": {
"paths": [
"subdirectory/styles-files",
],
"less": "less.json"
},
"routes": {
"/": "index.htm"
}
}
CSS generation with Stylus
You can use the preprocessor Stylus to create your CSS. The operation is as follows: whenever a CSS request is made, if a Stylus equivalent exists it is read and it generates the CSS. Once done, the new CSS is responded.
With the following structure:
├─ assets/
│ └─ stylesheets
│ └─ common.styl
├─ templates/
│ └─ index.htm
└─ webconfig.json
and the following webconfig:
{
"enableStylus": true,
"routes": {
"/": "index.htm"
}
}
and the following content in:
templates/index.htm
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Stylus Test</title>
<link rel="stylesheet" href="stylesheets/common.css">
</head>
<body>
<p>This line is red.</p>
</body>
</html>
assets/stylesheets/common.styl
p
color: #f00
you will build the assets/stylesheets/common.css
by calling the url http://localhost/
or http://localhost/stylesheets/common.css
.
Source Map and Minification
By default, in the above example, a common.css.map
file will be generated. This allows your browser to indicated you that line in .styl
file has generated the CSS property of the item you have selected in your debugger.
Disable this with enableLess.sourceMap
to false
:
"enableStylus": {
"sourceMap": false
},
"routes": {
"/": "index.htm"
}
You can also generate CSS files already minify with:
"enableStylus": {
"compress": true
},
"routes": {
"/": "index.htm"
}
Note: More options on stylus documentation for module.
Compile Stylus files with --generate
Because of Stylus are compilated on the fly, when a file is requested in http(s), modification needed running website for generate CSS output. Then you can use CSS. It's possible to skip running step and directly complated Stylus before minify CSS with enableLess.stylus
.
With the following webconfig.json
:
{
"enableLess": {
"stylus": [
"stylesheets/common.styl",
"stylesheets/component-1.styl",
"stylesheets/component-2.styl",
"stylesheets/component-3.styl"
]
},
"routes": {
"/": "index.htm"
}
}
or with the following webconfig.json
:
{
"enableLess": {
"stylus": "stylus.json"
},
"routes": {
"/": "index.htm"
}
}
with stylus.json
containing :
[
"stylesheets/common.styl",
"stylesheets/component-1.styl",
"stylesheets/component-2.styl",
"stylesheets/component-3.styl"
]
The @import
used by Less will be capable to walk into subdirectories : styles
, stylesheets
or css
. It's possible to change that with :
{
"enableLess": {
"paths": [
"subdirectory/styles-files",
],
"stylus": "stylus.json"
},
"routes": {
"/": "index.htm"
}
}
Optimize Images files
You can automatically generate optimized images files by creating Optimizations by referencing the file by input and output path. Of course you can do as much as you want. The optimization files is execute every time you start NodeAtlas either as a server or via the --generate
command if an Optimization exists in the Webconfig.
Creating Optimizations
With the following configuration:
{
"optimizations": {
"images": {
"media/images/example.png": "media/images/optimized/",
"media/images/example.jpg": "media/images/optimized/",
"media/images/example.gif": "media/images/optimized/",
"media/images/example.svg": "media/images/optimized/"
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
and the following set of file:
├─ assets/
│ └─ media/
│ └─ images/
│ ├─ example.png
│ ├─ example.jpg
│ ├─ example.gif
│ └─ example.svg
├─ templates/
│ └─ index.htm
└─ webconfig.json
you will get the following new files:
├─ assets/
│ └─ media/
│ └─ images/
│ ├─ example.png
│ ├─ example.jpg
│ ├─ example.gif
│ ├─ example.svg
│ └─ optimized/ ⤆ new folder
│ ├─ example.png ⤆ new file
│ ├─ example.jpg ⤆ new file
│ ├─ example.gif ⤆ new file
│ └─ example.svg ⤆ new file
├─ templates/
│ └─ index.htm
└─ webconfig.json
Create Optimizations by group of file
For example, not define file one by one, but in group:
{
"optimizations": {
"images": {
"media/images/*.{gif,jpg,png,svg}": "media/images/optimized/"
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
Add more options to Optimizations
It is possible to redefine default options used for optimizations via this 4 objects:
{
"optimizations": {
"jpg": { "progressive": false },
"gif": { "interlaced": false },
"png": { "optimizationLevel": 1 },
"svg": { "multipass": false },
"images": {
"media/images/*.{gif,jpg,png,svg}": "media/images/optimized/"
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
To know all options it is here:
Optimizations in a shared file
In order to not re-write a long Bundles configuration list in webconfig.json
file to your development environment andwebconfig.prod.json
to your production environment, you can group files in a file of your choice. By convention, the name is optimizations.json
file.
For example:
The following set of file
├─ assets/
│ └─ media/
│ └─ images/
│ ├─ example.png
│ ├─ example.jpg
│ ├─ example.gif
│ └─ example.svg
├─ templates/
│ └─ index.htm
├─ webconfig.json
└─ webconfig.prod.json
with webconfig.json
{
"httpPort": 7777,
"optimizations": {
"images": {
"media/images/example.png": "media/images/optimized/",
"media/images/example.jpg": "media/images/optimized/",
"media/images/example.gif": "media/images/optimized/",
"media/images/example.svg": "media/images/optimized/"
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
and with webconfig.prod.json
{
"httpPort": 7776,
"httpHostname": "blog.lesieur.name",
"urlPort": 80,
"optimizations": {
"images": {
"media/images/example.png": "media/images/optimized/",
"media/images/example.jpg": "media/images/optimized/",
"media/images/example.gif": "media/images/optimized/",
"media/images/example.svg": "media/images/optimized/"
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
could be the following set of file
├─ assets/
│ └─ media/
│ └─ images/
│ ├─ example.png
│ ├─ example.jpg
│ ├─ example.gif
│ └─ example.svg
├─ templates/
│ └─ index.htm
├─ bundles.json
├─ webconfig.json
└─ webconfig.prod.json
with webconfig.json
{
"httpPort": 7777,
"optimizations": "optimizations.json",
"routes": {
"/": {
"template": "index.htm"
}
}
}
with webconfig.prod.json
{
"httpPort": 7776,
"httpHostname": "blog.lesieur.name",
"urlPort": 80,
"optimizations": "optimizations.json",
"routes": {
"/": {
"template": "index.htm"
}
}
}
and optimizations.json
{
"images": {
"media/images/example.png": "media/images/optimized/",
"media/images/example.jpg": "media/images/optimized/",
"media/images/example.gif": "media/images/optimized/",
"media/images/example.svg": "media/images/optimized/"
}
}
Note : it is possible to disable Optimizations by not including them in the webconfig
.
Disable Optimizations
It is also possible to not execute the optimization when run a website with NodeAtlas with "imagesOptimizationsEnable": false
.
{
"imagesOptimizationsEnable": false,
"optimizations": {
"images": {
"media/images/example.png": "media/images/optimized/",
"media/images/example.jpg": "media/images/optimized/",
"media/images/example.gif": "media/images/optimized/",
"media/images/example.svg": "media/images/optimized/"
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
Note : if your optimizations is in shared file, you could desactivated it also without the "optimizations": "optimizations.json"
. Just remove it.
Re-generate Optimizations before each Page Response
You can ask files to be regenerated before each page response with "stylesheetsBundlesBeforeResponse": false
et `"javascriptBundlesBeforeResponse": false`` for each type of Bundle.
{
"imagesOptimizationsBeforeResponse": false,
"optimizations": {
"images": {
"media/images/example.png": "media/images/optimized/",
"media/images/example.jpg": "media/images/optimized/",
"media/images/example.gif": "media/images/optimized/",
"media/images/example.svg": "media/images/optimized/"
}
},
"routes": {
"/": {
"template": "index.htm"
}
}
}
Note : this is not recommanded for production environment because it's slowed responses pages.
CSS Inline Injection for Manage Email Assets
When you create templates for sending email newsletters, or even simple message, you can not attach stylesheet. The only way is to write the CSS instructions in the template within the style
markup attribute.
Specific Injection
With injectCss
, simply design your template as usual via a stylesheet and NodeAtlas inject each rendering styles in the attribute style
. It will do more than generate templates.
With for example the following configuration:
{
"routes": {
"/": {
"template": "email.htm",
"generate": "welcome.html",
"injectCss": "stylesheets/email.css"
}
}
}
and the following set of files:
├─ generates/
├─ assets/
│ └─ stylesheets/
│ └─ email.css
├─ templates/
│ └─ email.htm
└─ webconfig.json
whose contents are :
stylesheets/common.css
body {
color: #f00;
}
templates/email.htm*
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Email</title>
</head>
<body>
<p>This is a template email.</p>
</body>
</html>
output will be, with the command node </path/to/>node-atlas/ --generate
, all following file:
├─ generates/
│ └─ bienvenue.html <= template email generate !
├─ assets/
│ └─ stylesheets/
│ └─ email.css
├─ templates/
│ └─ email.htm
└─ webconfig.json
with as content for generates/welcome.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Email</title>
</head>
<body style="color: #f00;">
<p>This is a template email.</p>
</body>
</html>
This mechanism also works if you do not intend to generate anything but a site that is running. Convenient to change your live models before generating.
Test : From
./tests/examples/css-injection
runnode "../../../" --generate
. Result are intogenerates
.
Global Injection
It is possible to use injectCss
as global mechanism for all pages.
{
"injectCss": "stylesheets/email.css",
"routes": {
"/welcome/": {
"template": "email-a.htm",
"generate": "welcome.html"
},
"/good-bye/": {
"template": "email-b.htm",
"generate": "good-bye.html"
}
}
}
ainsi les deux pages welcome
et good-bye
contiendront chacune <body style="color: #f00;">
.
Multiple Injection
It's possible to :
- Attach global and specific files in same time.
- Attach more one CSS file by
injectCss
property.
{
"injectCss": ["stylesheets/reset.css", "stylesheets/email.css"],
"routes": {
"/welcome/": {
"template": "email-a.htm",
"generate": "welcome.html",
"injectCss": "/stylesheets/welcome.css"
},
"/good-bye/": {
"template": "email-b.htm",
"generate": "good-bye.html",
"injectCss": ["stylesheets/good-bye.css", "/stylesheets/others.css"]
}
}
}
Test : From
./tests/examples/css-injection
runnode "../../../" --generate --webconfig webconfig.multiple.json
. Result are intogenerates
.
Allow / Disallow GET / POST requests
You can also manager how the server will respond to requests GET/POST to a given page. For example, we will allow access to pages only GET for the whole site and allow a POST to one page only (and prohibited him GET).
{
"getSupport": true,
"postSupport": false,
"routes": {
"/": {
"template": "index.htm"
},
"/list-of-members/": {
"template": "members.htm"
},
"/write-comment/": {
"template": "write-com.htm"
},
"/save-comment/": {
"template": "save-com.htm",
"getSupport": false,
"postSupport": true
}
}
}
Note : If nothing is set, getSupport and postSupport are set to true in global webconfig and by route.
Allow / Disallow PUT / DELETE requests
Fonctionnant exactement de la même manière que getSupport
et postSupport
, les deux actions HTTP PUT et DELETE qui part défaut ne sont pas activé peuvent être activé avec putSupport
et deleteSupport
.
{
"getSupport": false,
"postSupport": false,
"putSupport": true,
"routes": {
"/read-all-entry/": {
"template": "display-json.htm",
"variation": "all-entry.json",
"getSupport": true,
"putSupport": false
},
"/read-entry/:id/": {
"template": "display-json.htm",
"variation": "entry.json",
"getSupport": true,
"putSupport": false
},
"/create-entry/:id/": {
"template": "display-json.htm",
"variation": "entry.json",
"postSupport": true,
"putSupport": false
},
"/update-entry/:id/": {
"template": "display-json.htm",
"variation": "entry.json"
},
"/delete-entry/:id/": {
"template": "display-json.htm",
"variation": "entry.json",
"deleteSupport": true,
"putSupport": false
}
}
}
With the configuration below, only one HTTP action is possible by route, this is a great way to create APIs REST easily with NodeAtlas.
Change settings of Sessions
Key and Secret
NodeAtlas itself manages sessions stored on the server as initial settings:
- Key :
nodeatlas.sid
- Secret :
1234567890bépo
that allow customers to stay connected through the pages to a single set of personal server side variable.
It is possible to change the default settings (and even compulsory for productions sites) with the parameters of webconfig.json
following:
{
sessionKey: "personal key",
sessionSecret: "personal secret"
}
NodeAtlas also employs a memory storage object (MemoryStore) stoques that the information in the RAM of the server.
Other Parameters
It is possible to change all the parameters of the sessions (except MemoryStore) using the configuration of next webconfig.json
:
{
"session": {
"key": "personal key",
"secret": "personal secret",
"cookie": {
"path": '/',
"httpOnly": true,
"secure": false,
"maxAge": null
},
...,
...,
...
}
}
The entirety of the possible configuration is located on the module documentation express-session.
External Storage Sessions
By default, this is NodeAtlas server that stores sessions in the RAM of the server application. This does not allow users to share sessions across multiple applications NodeAtlas (or other) and erases all current sessions for an application if you restart it.
To address this concern, it should support the recording sessions via a base No SQL such as Redis
or MongoBD
.
You just have to use the setSessions
function incontrollers/common.js
of Back-end part.
Session managed with Redis
Implement the following code in controllers/common.js
to store your sessions in a local Redis.
var website = {};
(function (publics) {
"use strict";
publics.loadModules = function (NA) {
var NA = this;
NA.modules.RedisStore = require('connect-redis');
};
publics.setSessions = function (next) {
var NA = this,
session = NA.modules.session,
RedisStore = NA.modules.RedisStore(session);
NA.sessionStore = new RedisStore();
next();
};
}(website));
exports.loadModules = website.loadModules;
exports.setSessions = website.setSessions;
More information to connect-redis page.
Session managed with MongoDB
Implement the following code in controllers/common.js
to store sessions in the database sessions
of a local MongoDB.
var website = {};
(function (publics) {
"use strict";
publics.loadModules = function () {
var NA = this;
NA.modules.MongoStore = require('connect-mongo');
};
publics.setSessions = function (next) {
var NA = this,
session = NA.modules.session,
MongoStore = NA.modules.MongoStore(session);
NA.sessionStore = new MongoStore({
db: 'sessions'
});
next();
};
}(website));
exports.loadModules = website.loadModules;
exports.setSessions = website.setSessions;
More information to connect-redis page.
Changing the template engine brackets <% %>
For example, to include part of a file instruction is used <%- include('head.htm') %>. It would be possible to do it with <?- include('head.htm') ?> with the configuration below:
{
"templateEngineDelimiter": "?",
"routes": {
"/": {
"template": "index.htm"
}
}
}
See the exemple in files below:
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') ?>
Learn all about the possibilities of the template engine consult the documentation ejs
Note : If nothing is set, templateEngineDelimiter is set to %.
Change the url hostname and listening port
It is possible to generate a different url listening other port with urlHostname and urlPort*. For example, the local loop listens on port 80 for a script makes the Reverse Proxy from the port 7777 on the 80 with the "http-proxy" module as below:
{
"httpPort": 7777,
"httpHostname": "127.0.0.1",
"urlPort": 80,
"urlHostname": "localhost",
"routes": {
"/": {
"template": "index.htm"
}
}
}
It's also possible to avoid other enter url. Also if www.localhost
or localhost:7777
are enter into url area, it's localhost
for the user :
{
"enableForceDomain": true,
"httpPort": 7777,
"httpHostname": "127.0.0.1",
"urlPort": 80,
"urlHostname": "localhost",
"routes": {
"/": {
"template": "index.htm"
}
}
}
Generate urls dynamically
Relative paths in absolute
It is possible that the paths created from your url to be interpreted as subfolders that have actually no real existence. This has the effect the address media/images/example.jpg
initially accessible from template displayed to address http://localhost impossible to reach when the template is displayed to address http://localhost/sub-directory/ (because the path should be ../media/images/example.jpg
).
To no longer have to worry about access to resources regardless of the URL that is requested, simply turn on all the urls such as:
<link rel="stylesheet" type="text/css" href="stylesheets/common.css" />
<!-- ... -->
<img src="media/images/example.jpg" />
<!-- ... -->
<script type="text/javascript" src="javascript/common.js"></script>
in absolute urls with variable urlBasePath
as below:
<link rel="stylesheet" type="text/css" href="<%= urlBasePath %>stylesheets/common.css" />
<!-- ... -->
<img src="<%= urlBasePath %>media/images/example.jpg" />
<!-- ... -->
<script type="text/javascript" src="<%= urlBasePath %>javascript/common.js"></script>
Note that in the case of the following configuration:
{
"routes": {
"/": {
"template": "index.htm"
}
}
}
urlBasePath
return http://localhost/
while in this configuration:
{
"httpPort": 7777,
"urlRelativeSubPath": "sub/folder",
"routes": {
"/": {
"template": "index.htm"
}
}
}
urlBasePath
return http://localhost:7777/sub/folder/
.
The paths of templates
Using the following webconfig:
{
"routes": {
"/index.html": {
"template": "index.htm"
},
"/contact.html": {
"template": "contact.htm"
}
}
}
and the corresponding template
<!-- ... -->
<a href="http://localhost/index.html">Link to home</a>
<a href="http://localhost/contact.html">Link to contact</a>
<!-- ... -->
I'd have to change my link in the template if I change the listening port or if I change the path of the url. The following configuration changes:
{
"httpPort": 7777,
"routes": {
"/home.html": {
"template": "index.htm"
},
"/contact-us.html": {
"template": "contact.htm"
}
}
}
me contraindrait à modifier le template précédent comme suit :
<!-- ... -->
<a href="http://localhost:7777/home.html">Link to home</a>
<a href="http://localhost:7777/contact-us.html">Link to contact</a>
<!-- ... -->
You can solve this problem by giving a key to a specific path and deporting are way in the url
property.
With the followinh webconfig:
{
"routes": {
"index": {
"url": "/index.html",
"template": "index.htm"
},
"contact": {
"url": "/contact.html",
"template": "contact.htm"
}
}
}
I can now write the link in the dynamic template:
as follows
<!-- ... --> <a href="<%= urlBasePath %><%= webconfig.routes.home.url.slice(1) %>">Link to home</a> <a href="<%= urlBasePath %><%= webconfig.routes.contact.url.slice(1) %>">Link to contact</a> <!-- ... -->
Note :
.slice(1)
makes it easy to remove the dual/
for standard url.or as follows
<!-- ... --> <a href="<%= urlBasePath %>.<%= webconfig.routes.home.url %>">Link to home</a> <a href="<%= urlBasePath %>.<%= webconfig.routes.contact.url %>">Link to contact</a> <!-- ... -->
Note : This would, for example
http://localhost/./home.html
, which is a standard url.ou comme suit
<!-- ... --> <a href="<%= urlBasePathSlice + webconfig.routes.home.url %>">Link to home</a> <a href="<%= urlBasePathSlice + webconfig.routes.contact.url %>">Link to contact</a> <!-- ... -->
Note :
urlBasePathSlice
returnhttp://localhost
in place ofhttp://localhost/
orhttp://localhost:7777/sub/folder
in place ofhttp://localhost:7777/sub/folder/
.
Utilisation de la clé pour mapper les pages
It's maybe useful to know the key used for the current page displayed for find the equivalent page in an other language.
With the following webconfig :
{
"languageCode": "en-us",
"routes": {
"index_en-us": {
"url": "/",
"template": "/index.htm"
},
"index_fr-fr": {
"url": "/francais/",
"template": "index.htm",
"languageCode": "fr-fr"
},
"cv_en-us": {
"url": "/resume/",
"template": "cv.htm"
},
"cv_fr-fr": {
"url": "/francais/cv/",
"template": "index.htm",
"languageCode": "fr-fr"
}
}
}
and the common variation following :
{
"language": [{
"name": "English",
"code": "en-us"
}, {
"name": "French",
"code": "fr-fr"
}]
}
in fr :
{
"language": [{
"name": "Anglais",
"code": "en-us"
}, {
"name": "Français",
"code": "fr-fr"
}]
}
we could create link between each page as following :
<ul>
<% for (var i = 0; i < common.language.length; i++) { %>
<li><a href="<%= urlBasePathSlice + webconfig.routes[currentRouteName.split('_')[0] + '_' + common.language[i].code].url %>"><%- common.language[i].name %></a></li>
<% } %>
</ul>