Exploring Vanilla JS / part 1

This is series of articles where I’m experimenting with Vanilla JS way of writing modern web applications. I’m trying to find a pattern, that would bring fast, fun and powerful development process without using libs.

This is the first article, where I’m creating a simple basis for old-fashioned server-side applications in pure Node.js.


Nowadays web applications are fat. I mean they consist of a lot of technologies. And you need to know a lot of technologies to write modern apps. But I’m a lazy guy, I don’t want to learn all of this stuff.

In this series of articles I will write modern full stack JavaScript web application using as less of technologies as possible.

I’m not sure about the idea of the future application, but it does not matter right now, let’s just start:

mkdir vanilla
cd vanilla
touch server.js

It turns out that start Node.js server is pretty simple. I don’t even need a framework for doing this:

const http = require('http');
const PORT = 4000;

http.createServer(server).listen(PORT);

function server(req, res) {
  res.end('Hello, dude');
}

Then I enter node server.js and server runs at localhost:4000.

What about routing? Our app is going to have several pages. Easy:

function server(req, res) {
  const { url } = req;

  res.end(
    url === '/' ? 'Main' :
    url === '/about' ? 'About' :
    '404'
  );
}

Ok, let’s create something real now. I like the idea of components. Components get some data and render this data into html. I will write components as functions:

function server(req, res) {
  return res.end(App({ url: req.url }));
}

function App({ url }) {
  return `
    <!doctype html>
    <html class="app">
      <head>
        <meta charset="utf-8" />
        <title>Vanilla JS Website</title>
      </head>
      <body class="app__body">
        ${Header()}
        ${(
          url === '/' ? 'This is MAIN page' :
          url === '/about' ? 'This is ABOUT page' :
          url === '/contacts' ? 'This is CONTACTS page' :
          'This is 404 page'
        )}
      </body>
    </html>
  `;
}

function Header() {
  return `
    <div class="header">
      <a class="header__link" href="/">Main</a>
      <a class="header__link" href="/about">About</a>
      <a class="header__link" href="/contacts">Contacts</a>
    </div>
  `;
}

Now we have two components, App and Header. App renders whole application and Header renders menu. OMG, they look like React stateless components!

Well, so far everything was super simple. Now I will add some styles to the application, create styles.css:

.app {
  margin: 0;
  padding: 0;
  background: #fff;
  font-family: sans-serif;
}

.app__body {
  margin: 0;
  padding: 0;
}

.header {
  padding: 10px;
  background: #efefef;
}

.header__link {
  margin-right: 10px;
}

Then I want our App to load styles.css, so I add <link />:

<head>
  <meta charset="utf-8" />
  <title>Vanilla JS Website</title>
  <link rel="stylesheet" href="/styles.css" />
</head>

But how do I make styles.css file be available at /styles.css path? Probably I need manually read this file and send all it’s content:

const fs = require('fs');

function server(req, res) {
  const { url } = req;

  if (url === '/styles.css') {
    res.end(fs.readFileSync('./styles.css'));
    return;
  }

  res.end(App({ url }));
}

But wait, every request to /styles.css will force out server to read from hard drive. Not very efficient. What if we will cache the content?

const fs = require('fs');
const styles = fs.readFileSync('./styles.css');

function server(req, res) {
  const { url } = req;

  if (url === '/styles.css') {
    res.end(styles);
    return;
  }

  res.end(App({ url }));
}

Phaha! I like the way I rule my application. I feel like a God whilst with express or any other framework I only felt like a king.

Here is our app in action:

app in action

Now we have a basis for developing old-fashioned server-side applications with static content. No framework is needed, Node.js does the job.

Next I will add client side JavaScript to bring some dynamics. Read PART 2 to see how.

Write your comment…