[Tutorial] An Introduction to Node.js Servers (and Express.js)

This is great content, @Josh!

1 Like

The Handlebars templates get rendered on the server, and you can cache them with something like Redis (or similar tool). I could add an example of caching to my repo if you want.

If you want those variables to be available to JavaScript, then you could inject them into a global variable at the top so that the Handlebars template does something like this:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Some Page</title>
        <script>
            var pageData = {
                someKey: {{someValue}},
                listOfThings: {{someArrayOfThings}}
            };
        </script>
    </head>
    <body>
        <h1>{{title}}</h1>
    </body>
</html>

Then your JavaScript would be able to read them. I don’t know if that’s the best way, but it should work.

Hmm interesting! This is getting kind of overwhelming as I switch from LAMP stack. Another question: Is there a way to “protect” a node server from large requests and so on? From my understanding, Apache does a lot of that for me, though I am not sure.

It might help to build a few small test sites before trying to migrate a bigger site. The way I learn a framework is to do the quickstart tutorial from scratch a few times. Then I’ll look for tutorials on how to implement some feature, and I’ll build another sample site from scratch. I keep repeating it until I start to understand how everything is wired together.

It’s a lot of information to digest at once, so running through the process multiple times helps.

If there is a specific task you’re trying to do (caching, cookies, redirects, databases, etc.), let me know, and I could write a tutorial about it.

Express has a package called Helmet that can add some security. An Express site will be served with another server in front of it. So Apache or Nginx would proxy requests to the port of the Node server.

In production, you would start the Node server with a tool like forever (which restarts the app if it crashes), on a port like 3000.

I’m not sure of the exact syntax for Apache, but the Apache rules might look something like this:

ProxyRequests on
ProxyPass /some-path/ http://localhost:3000/

Apache (or Nginx) would listen on port 80, and whenever a request came in for /some-path/* it would proxy the request to the Node server that is listening on port 3000. The Node server would send the result of the request back to Apache, and Apache would send the request to the user.

2 Likes

Yeah, agreed. This is a lot more than I though. On the one hand, a switch feels easy since I have written all the Javascript, but with routing and configuring a server, it is not easy to be comfortable.
I will only make new projects in Node from now on though. :slight_smile:

1 Like

You can also build things with PHP is nearly the same way as Express. If you want to see an example, I could write a quick tutorial on it.

If you use a PHP framework you wouldn’t have to deal with a different environment or proxies but could just upload some PHP files and everything should work. Once the PHP part is incrementally restructured in this style, then it would be pretty easy to translate the code to Node (or another language) if you wanted to do that. It would almost be a line-by-line translation, since the frameworks are similar.

Hmm, yeah, I am going back to Node now, just because I want the initial load to be server side rendered and subsequent loads to be client side.

I may not use handlebars for now, just to get started.

I have a question now.
I created a file index.html
It has the following code:

<!doctype html>
    <html lang="en">
    <head>
    <title>Hello, world!</title>
    </head>
    <body>
    <h1>Hello, world Again!</h1>
    <p id="JStest"></p>
    </body>
     </html>

    <script>
    document.getElementById("JStest").innerHTML='Javascript rendered here';
    </script>

That I load using express with the following code.

app.get('/', function(request, response) {
    response.sendFile(path.join(__dirname + '/index.html'));
});

My question is, does the javascript at the bottom of index.html render server side or client side? If client side, how to make it render server side?

That would render content on the client site. To render it on the server, you would use templates (either Handlebars or another templating engine).

Here is your code that renders on the client:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Hello, world!</title>
    </head>
    <body>
        <h1>Hello, world Again!</h1>
        <p id="JStest"></p>
    </body>
</html>

<script>
    document.getElementById("JStest").innerHTML = "Javascript rendered here";
</script>

Here is the same thing in Handlebars:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{{title}}</title>
    </head>
    <body>
        <h1>{{title}}</h1>
        <div class="body-content">{{{body}}}</div>
    </body>
</html>

Then, in your router, where you wrote this:

app.get('/', function(request, response) {
    response.sendFile(path.join(__dirname + '/index.html'));
});

change that to this (assuming that the template is named page.hbs):

app.get('/', function(request, response) {
    // You can fetch things from the database here, but this will hard-code
    // a `pageData` object to send to the template.
    const pageData = {
        title: "Some Page", // this matches {{title}} in the template
        body: "<p>Some HTML from the database or wherever</p>" // {{{body}}}
    };

    // Send the `pageData` object into the template and render the HTML
    // on the server.
    response.render("page", pageData);
});

That way of sending a file to the frontend with sendFile might look easier at first glance, but it will probably lead to spaghetti code.

My examples above are set up for an “MVC” (Model, View, Controller) pattern:

  • router (maps routes to controller functions)
  • controller (functions that contain most of the logic)
  • model (the controller accesses the data through these files)
  • view (the templates get data injected into them by the controller)

That’s pretty complicated to get working from scratch. Gatsby does it out of the box though. If you want to replace the PHP, you might want to try Gatsby for all the content pages, and then build the API that serves the data in Express. Then Express wouldn’t render any templates but would just return JSON.

Gatsby would give you:

  • extremely fast loads, because it’s just serving static HTML files (you can test codeselfstudy.com)
  • great SEO
  • automatic inlined CSS, code minification, and image optimization
  • it becomes an SPA after the first page load
  • write dynamic React apps on any page
  • anti-spaghetti project structure

If you examine the page size of codeselfstudy.com it might look a couple hundred KB larger than necessary, but it’s loading the stuff that causes the next pages to load instantly. If you click the “About” link on top, it should load without waiting for another request to the server.

2 Likes

OK, that is really helpful! Thanks!

So I think for my situation I may try to render the pages on the server side with handlebars, and then just manipulate the DOM with vanilla JS on the client side.

This would be a smaller baby-step from PHP anyway.

I do appreciate the power of Gatsby, but it seems like the learning curve would be even higher than handlebars and Express, is that right?

One other question, what is the best way to deploy this server? Would I still use something like gulp? Or webpage?
Or would I just rsync to a remote server?

1 Like

Managed to recreate my homepage with Node and Handlebars thanks to this guide!

Now the question is where and how to deploy?

1 Like

Are you planning to use Express and PHP at the same time, or try to rebuild the whole site? Also, do you have access to the Apache config files or is root access disabled?

Hmm, right now I am thinking just to re-write everything and have it running on a new server and then once I know everything is working well in Node point the domain name to the new I.P. address.

I guess I should use AWS EC2? But I really hate all the hoops you have to jump through to use AWS.

So Digital Ocean?

I will probably then just cancel my VPS/LAMP stack…


Also, another side question. So is the advantage of handlebars over template literals directly, that you just write much less code? This example uses template literals…

Another question: How do I connect and load MySQL data with Node and Express? (This is probably a whole new tutorial)

AWS would work, but it’s probably twice as expensive as DigitalOcean.

I haven’t tried Nanobox yet, but it looks like an easy way to deploy apps to DigitalOcean.

You can set up the templating in many different ways, but the further you go from popular conventions, the more difficult it might be when something breaks.

Two other popular templating engines in Node are EJS and Pug. EJS requires more typing than Handlebars, and Pug sometimes creates subtle, annoying problems with the HTML output.

Handlebars is well tested and supported, so I think it’s a safe choice. Sites that use it include: LinkedIn, Square, Netflix, and this forum. :slight_smile:

I could write a quick tutorial for that if you want.

1 Like

Great, thanks for the answers.

Yes, tutorials on deploying and connecting to MySQL would be useful! :slight_smile:

1 Like

Here’s one on MySQL: [Tutorial] How to Use MySQL or MariaDB with Node.js and Express

I can write something on caching and deploying soon, if it helps.

1 Like

This looks awesome! Thanks Josh.

Yes, caching and deploying would be awesome. It would be nice to know what a deploy looks like as I develop. :slight_smile:

1 Like

A quick thing I want to note here, if changes to your handlebars templates are not updating automatically without needing to restart the server, you can fix this problem by adding some options to the “start” command in the package.json

Adding the following line will instruct nodemon to also track changes in the “view” folder and define extensions you want watched for updated

"start": "npx nodemon server.js --watch dist --watch views -e js,json,html,hbs"

You can add or change watched folders and extensions as needed. :slight_smile:

1 Like

Is there a way to route to subdomains?
I.E. myfooddata.com vs tools.myfooddata.com ?
How would that be set up in my routes using Express?

I haven’t used that feature in Express, but there is a vhost package. The page looks like it was generated from a README file that uses Connect.js instead of Express, but they are similar.

There’s also an npm package called express subdomain. I haven’t used either.

The packages don’t look like they are actively maintained, but there isn’t much code there, so it doesn’t look very complex.

I found a video tutorial, but it’s in Portuguese. If the code doesn’t make sense, I could look more closely tomorrow and write a tutorial.

1 Like