Node.js® is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
Sails is a NodeJS framework for the backend server. Based on a Model-View-Controller pattern, it allows for rapid development of applications. Sails has built-in integration for web sockets for realtime push messages. It uses Waterline ORM as the default ORM, making it database-agnostic. In other words, it allows for database operations across a spectrum of SQL as well as non-SQL databases. Most importantly, Sails provides a proper structure to your application.
Dust is a JavaScript template engine. It inherits its look from the ctemplate family of languages and is designed to run asynchronously on both the server and the browser.
SPA stands for Single Page Application. These are applications that fit on a single webpage. Once the site opens, the page does not reload thereafter. The goal of such an application is to provide a fluid user experience by cutting down page load time and providing easy transitions to different pages, just like desktop apps.
In this tutorial, we will set up a NodeJS server with SailsJS as the framework to manage our code. We will use DustJS for isomorphic templates used on both the client and the server.
Our main aim is to use Isomorphic (or same) templates on the client as well as on the server. This is awesome because
This tutorial assumes that you have created an Ubuntu 14.04 x64 Droplet. It was tested with 512 MB of RAM. You will also need a user with sudo access to install the packages.
First, to compile and install native addons from npm you need to install build tools:
- sudo apt-get install python-software-properties python g++ make
Then, install NodeJs and NPM using the following commands (from Chris Lea’s PPA):
- sudo add-apt-repository ppa:chris-lea/node.js
- sudo apt-get update
- sudo apt-get install nodejs
Note: This also installs the Node Package Manager or npm
.
NPM is used to install node packages. Its like the apt-get
for NodeJs.
We’ll use it to install node modules like Sails, dust-compiler
, and other requirements.
Next, install SailsJs
:
- sudo npm -g install sails
Note: This installs the latest version of Sails. You can read more about Sails.js on their website.
Create a new application:
- sails new dustspa
- cd dustspa
Sails will create the dustspa
directory with the following structure:
--config
--views
---api
--tasks
--assets
README
.gitignore
package.json
.sailsrc
app.js
Gruntfile.js
Find the following lines in the package.json
file:
"dependencies": {
"sails": "~0.11.0",
Change them to the following:
"dependencies": {
"dustjs-linkedin": "^2.5.1",
"sails": "~0.11.0",
The dust compiler is used to compile dust templates to dust JavaScript templates.
Next, install the dustjs
packages as well as the other package dependencies in the package.json
file:
- sudo npm install
Now, we use sails lift
to lift the server:
- sails lift
Visit your_server_ip:1337
to view the default home page. Stop the server using Ctrl+C
when done.
First, we set the View Engine to dust
:
In config/views.js
, change engine: 'ejs'
to engine: 'dust'
:
- nano ./config/views.js
Go to line:
engine: 'ejs',
and change it to:
engine: 'dust',
After the changes are done, press Ctrl+X
(save), Y (confirm file name), and ENTER (save and exit).
We will use the above method to edit all the files in future.
The content from layout.dust
will be our landing page. All requests will come to this page for the first page. After that, requests will be handled at the frontend.
Create file layout.dust
in the views
folder:
- touch views/layout.dust
Copy the following HTML code into layout.dust
:
<!DOCTYPE html>
<html>
<head>
<title>Dust SPA</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="header">
<nav>
<ul class="nav nav-pills pull-right">
<li role="presentation" class="active"><a href="#" class="links" data-template="home">Home</a></li>
<li role="presentation"><a href="#" class="links" data-template="about">About</a></li>
<li role="presentation"><a href="#" class="links" data-template="contact">Contact</a></li>
</ul>
</nav>
<h3 class="text-muted">SPA - DustJS Templates, SailsJS Architecture</h3>
</div>
<br/>
<div id="template">
<h1>Partial Goes Here</h1>
</div>
<footer class="footer">
<p>Styled by Bootstrap©</p>
</footer>
</div>
</body>
</html>
The HTML is pretty simple. It uses:
<div id="template">...</div>
where our templates will loadNext, we need to set the view for /
in routes.js
. Open config/routes.js
and edit it to:
'/': {
view: 'layout'
}
Now, let’s lift the server (If the server is already up, press Ctrl+C to stop it.), and check our progress. Run this command from the dustspa
directory (which is our currect directory) :
- sails lift
And point your browser to the following location: droplet_ip:1337
If you can see the page, then let’s proceed. If not, please review previous steps. Also, the links will not work at this point.
Note: Partials (or templates) are a part of a page. In SPA, we do not replace the whole page, just the partial.
Create the directory partials
in views
directory, and change to this new directory:
- mkdir views/partials
- cd views/partials
Create the home.dust
, about.dust
, and contact.dust
files in the partials
directory with the following content:
<div class="jumbotron">
<h1>Home Page
{?home}<small class="pull-right">Visit Count: {home}</small>{/home}
</h1>
<p class="lead">This is the home page. Its actually a dust partial which will be replaced when we navigate away from the page. Only this partial will change while the rest of the page will not be reloaded. SPA Magic!</p>
<p>
<a class="btn btn-lg btn-success" href="http://linkedin.github.io/dustjs/" target="_blank" role="button">Check out DustJS</a>
<a class="btn btn-lg btn-warning pull-right" href="http://sailsjs.org" target="_blank" role="button">Check out SailsJS</a>
</p>
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h1 class="panel-title">About Us
{?about}<kbd class="pull-right">Visit Count: {about}</kbd>{/about}
</h1>
</div>
<div class="panel-body">
<h4>This is the About Us template. Its actually a dust partial which will be replaced when we navigate away from the page. Only this partial will change while the rest of the page will not be reloaded. SPA Magic!</h4>
<br>
<p>
<a class="btn btn-lg btn-success" href="http://linkedin.github.io/dustjs/" target="_blank" role="button">Check out DustJS</a>
<a class="btn btn-lg btn-warning pull-right" href="http://sailsjs.org" target="_blank" role="button">Check out SailsJS</a>
</p>
</div>
</div>
<div class="well">
<h1 class="align-center">Show us some love and we'll get back to you !
{?contact}<small class="pull-right">Visit Count: {contact}</small>{/contact}
</h1>
<hr/>
<div class="input-group input-group-lg">
<span class="input-group-addon" id="basic-addon1">@</span>
<input type="text" class="form-control" placeholder="Email" aria-describedby="basic-addon1">
</div>
<br/>
<p>
<a class="btn btn-lg btn-success" href="#" role="button">Send Contact</a>
</p>
</div>
Dust templates need to be compiled before they can be used on the frontend.
Let’s install the dust compiler
:
- sudo npm install -g dust-compiler
We will keep all our compiled templates in assets/templates
. Change to the main dusts
directory:
- cd ../..
Now, compile the dust templates
:
- dust-compiler -s views/partials/ -d assets/templates/ --bootstrap --nonotify
Now, you should have three files in your assets/templates
folder:
home.js
about.js
contact.js
Now, we have all the required files.
First, in views/layout.dust
, add the dust-js
libraries and template files inside the <body>
tags at the very end:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/dustjs-linkedin/2.5.1/dust-core.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/dustjs-helpers/1.5.0/dust-helpers.min.js"></script>
<script type="text/javascript" src="/templates/home.js"></script>
<script type="text/javascript" src="/templates/about.js"></script>
<script type="text/javascript" src="/templates/contact.js"></script>
Having done that, we need to add a script to capture link clicks and render the required template. Create assets/js/clickHandler.js
with the following content:
(function () {
var links = document.getElementsByClassName("links"),
templateDiv = document.getElementById("template"),
nav = document.querySelector('nav > ul'),
clicked = false, viewCount = { home: 2, about: 1, contact: 1 };
function clickHandler(e) {
var target = event.target,
templateName = this.getAttribute("data-template");
if(clicked) {
clicked.removeAttribute('class');
}
else {
nav.querySelector('.active').removeAttribute('class');
}
target.parentElement.setAttribute('class','active');
clicked = target.parentElement;
dust.render(templateName, viewCount, function (err, out) {
if(err) console.log('Error:',err);
else {
viewCount[templateName]++;
templateDiv.innerHTML = out;
}
});
};
for(var i = 0; i < links.length; i++){
links[i].addEventListener('click', clickHandler, false);
}
})();
The above script is very simple. It does the following:
data-template
attributedust.render
function and pass an object viewCount
(could contain anything, here it contains the count of view access)Reference this new clickHandler.js
file by editing the views/layout.dust
and adding the following inside the <body>
tags at the very end:
<script type="text/javascript" src="/js/clickHandler.js"></script>
Finally, we need to edit layout.dust
in the views
directory.
Change the <div id="template">...</div>
in views/layout.dust
to:
<div id="template">
{> "partials/home"/}
</div>
What does the above change do?! This is Template Reuse. The dust.js
view engine will replace {> "partials/home"/}
with the contents of the file view/partials/home.dust
.
How will this template be reused? A compiled version of this template (that we compiled using dust-compiler
) resides in assets/templates/home.js
. This compiled template will be included in a script tag later on. Once a template is included using a <script src="/templates/home.js"/>
tag, it (the template) is automatically added to the dust.cache
object in the frontend
. Now, to re-render this template, we use dust.render("home", obj, callbackFunction)
. You can check the code in the assets/js/clickHandler.js
for a better understanding of the code.
A Dust template named xxx
is authored in a file named xxx.dust
. You can have multiple .dust
files and reference one dust.js template as part of another one. This is the basis for “components” or reusable templates for tasks like a common header and footer on multiple pages. Note that the .dust
file extension is used here in examples, but .tl
is also commonly seen. Since it only matters to the build process, you can use whatever extension works for you.
The partial reference syntax {> name /}
also supports paths so you can have a template at a path like shared/header.dust
and reference it as {> "shared/header" /}
. This allows partials to be organized into library-like structures using directories.
Read more about Partials on github.
Your final layout.dust
should look like this:
<!DOCTYPE html>
<html>
<head>
<title>Dust SPA</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="header">
<nav>
<ul class="nav nav-pills pull-right">
<li role="presentation" class="active"><a href="#" class="links" data-template="home">Home</a></li>
<li role="presentation"><a href="#" class="links" data-template="about">About</a></li>
<li role="presentation"><a href="#" class="links" data-template="contact">Contact</a></li>
</ul>
</nav>
<h3 class="text-muted">SPA - DustJS Templates, SailsJS Architecture</h3>
</div>
<br/>
<div id="template">
{> "partials/home"/}
</div>
<footer class="footer">
<p>Styled by Bootstrap©</p>
</footer>
</div>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/dustjs-linkedin/2.5.1/dust-core.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/dustjs-helpers/1.5.0/dust-helpers.min.js"></script>
<script type="text/javascript" src="/templates/home.js"></script>
<script type="text/javascript" src="/templates/about.js"></script>
<script type="text/javascript" src="/templates/contact.js"></script>
<script type="text/javascript" src="/js/clickHandler.js"></script>
</body>
</html>
Lift the server:
- sails lift
Point your browser to the following: your_server_ip:1337
Test SPA by clicking the top 3 links: Home, About, Contact
Awesome ! We successfully built an isomorphic website that allowed same template use on both client and server. We built a Single Page Application (SPA) Website and also got an understanding of using the SailsJS framework.
If you want to read more about the technologies used, you could visit the links listed below.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
With 0.12 I get a log “info: Could not find module: dust in path:” whenever i lift the sails app. Do you have a solve for this?
Can use pug for the templates?
Love the article. I’ve just started to learn sails as I’ve come from a c# mvc background and wanted to try node. Single page applications seem like fun to work with. As suggested an article showing links to a db utilising sails and updating the templates would be good. Infact I’d be really interested to see how Web sockets come into play with dust and sails.
Great article! I would love to see a ‘Part II’ with MongoDB included, and examples on how to transfer and modify data from backend to frontend and vice versa, in this particular context.
In my views/partials/home.js I got an error … dust is not defined; please fix or add /global dust/ Adding …
var dust = require(‘dustjs-linkedin’);
before the function(){ … }
ref this http://www.dustjs.com/guides/setup/
Wanted to post in case someone else comes up with this issue.
Hello myusuf91, Please can you help me to installing node.js and writting an apllication with node from scratch with ubuntu OS, i am completely new to nodejs.
How install project to folder /var/www/example.com/public_html ?