I am looking into interesting ways to reduce CPU utilization
on a NodeJS server.
During my research I have found the following article:
http://engineering.linkedin.com/nodejs/blazing-fast-nodejs-10-performance-tips-linkedin-mobile
These are all excellent tips but I have a question regarding
hint#4.
Does this really mean a user is requesting “JavaScriptTemplate.html”
and then all the JSON is requested subsequently (which is not implemented here)?
Assuming that all the dynamic content should be available without user
interaction (e.g. requesting JSON on a button click event) what is
the best way to achive this? I can think of loading additional JS dependencies
(requirejs) where functions are executed to request the JSON stuff.
Since I never see big websites to call static html files but
instead requesting routes to their application servers how common
is the solution suggested by the link above? Do they really
use server side templates to waste CPU utilization on
mostly static text content???
For Node (expressJS) this must be a suboptimal way especially
if the HTML to be produced is fairly complex… ideally
Node should just operate as an API server providing JSON data.
Do you have some ideas to share?
It is not the most common approach but it is still pretty common nowadays. There are many web frameworks (angularjs by google, knockout, moustache, etc) that work fine with this idea of templates in the client side.
The model is requested to the server (i.e. json) and mapped into a static view (template).
I think it fits really well when you have an API server providing JSON data. This way you can develop just another API client, in this case a web client (RIA). But I don’t think the main reason behind this approach is to save CPU.
Thanks for sharing the post – it is a great one (and very timely for me).
You’re actually asking two questions – 1) how to load data to render html client-side without client interaction and 2) how to send a static file to a browser when user actually requests a route.
Rendering page without user interaction and my ¢2 on client MVC
1) You need to run all the initialisation/data-loading/rendering code to render the page after the page has been loaded. If you use jQuery in the client (as most web applications do):
$(document).ready(function(){
// Your code here
});
It’s just copied from jQuery docs.
Most folks use backbone/underscore to build MVC layer in the client. Although there are a lot of much fancier (and seemingly more powerful) client-side frameworks to do so, this couple gives you just enough power without limiting your options or reducing your flexibility you will definitely need at some point. Underscore (which is backbone dependency anyway) in addition to many very useful functions (you will be surprised what’s possible with JavaScript if you spend one hour to read through the whole one page manual) has its own templates which are deceptively simple and at the same time extremely powerful as they just run all javascript inside templates.
Although it is usually a bad thing to have the application logic in templates (as underscore allows and most fancier and “more powerful” templating engines don’t), it is often very handy and much better to be able to add some logic in template when you discover yourself in some tight corner (as you often will) than to redesign a lot of application logic or add additional templates.
Also, my opinion is to avoid using require.js or any other module loader (until you really must use them) as I wrote here.
Serving static html for any route and nginx config for node-as-api
2) You need to rewrite requests to all routes to respond with the same static html file (or several route-dependent html files). Depending on your preferences or application requirements it can be the file with an empty body (in which case users will see a blank page until your data is loaded and page is rendered/inserted in body), some welcome page or even some template page where instead of data a spinning wheel is shown.
The way you rewrite requests depends on the web server you use to serve static content and to proxy requests. If you use Apache (an unlikely choice with Node, as it is synchronous) you need to use .htaccess files. If you use Nginx as most folks using node do, you need to use rewrite directive inside server block in config file like it is done in example below:
server {
listen 80;
server_name example.com;
root html/example;
access_log logs/example.log;
# location block below sends specific static assets from inside your app's
# public directory when routes /img, /js, /css, /views are requested
location ~ /(img|js|css|views)/ {
rewrite ^(.*)$ /public/$1 break;
}
# location block below proxies all data requests (/api route) to your node app
location /api {
proxy_pass http://localhost:3000/;
proxy_redirect http://localhost:3000/ http://example.com;
proxy_connect_timeout 30s;
proxy_read_timeout 30s;
proxy_cookie_domain localhost example.com;
#proxy_http_version 1.1;
}
# location block below rewrites all other routes to a specific html file
# that is sent to the client and that is supposed to load all JS and
# static assets to render a page
location / {
rewrite ^(.*)$ /public/app.html;
}
}
The way you render a page in the client (and the data you request from the server to do so) will depend on the route the user requested (which you can access/change in javascript as well as you can set/access/change cookies). All the navigation inside application (when the user clicks any buttons or internal links – you need to catch all click events) happens without additional requests for pages or static assets that are already loaded, only data requests are sent to the server.
I hope it helps.
SEO Update
The suggested configuration for nginx is suitable only if you don’t need any pages indexed by robots and visible to other web apps that need your static htmls, like facebook, e.g. For pages that you want to be indexed, you need to add conditions to route requests from robots differently (based on $http_user_agent) and also render some static htmls for those routes. But it can be a different purely semantic html (smaller, without design images, layout divs/classes, UI elements and javascript to reduce requests from crawling robots and web apps).