loading...
Cover image for Creating a basic website with Express.js

Creating a basic website with Express.js

aurelkurtula profile image aurel kurtula ・6 min read

Express is described as a light-weight web framework which means we can use it to create websites. Today I am going to walk through the very basics. The website will have just few static pages which we'll be able to navigate through.

As with most frameworks nowadays, Express has its own generator. At least in the beginning it might be great to start with the generator, you'll see one way of structuring your project. It's important to keep in mind express is un-opinionated. Whilst the boilerplate is structured in a particular way, you can structure your express project which ever way makes sense to you.

In this tutorial I'll cover the very basics. By the end we'll have a website with three pages.

Lets get started.

Create your project folder. Then run the following two lines in the terminal

npm init
npm install --save express

The first line creates the package.json file, it basically initiates the project. The second installs express. Note, the --save flag simply adds express to the packages file so that if we need to reinstall the packages again, package.json knows/remembers which packages the project needs

Now create a server.js file. This is where we'll write our code.

Let's start with the very basic structure.

import express from 'express';
const app = express()
app.get('/', (req, res) => {
    res.send('Hello World')
})
app.listen(5656, () => {
    console.log('http://localhost:5656')
})

There we have created a basic website that runs at localhost port 5656.

We can give ourself the option of changing the port number from the terminal. We do this by changing the above code with something like this:

const port = process.env.PORT || 5656;
app.listen(port, () => {
    console.log(`http://localhost:${port}`)
})

With that, you can run PORT=8081 npm start which changes the port number, of course, running npm run defaults to the port number being 5656

Rendering HTML in the browser.

So far our website is boring as hell. We are unable to create a website this way. Instead of sending a string of text to the browser (all though that string can be html), we would rather send html pages to the browser instead.

Express gives us the option of using template engines instead of html. This ability becomes very helpful as we start using dynamic content.

There are many template engines to choose from, my favorite is pug. Granted, it's not the most beginer friendly out of all the other options but I love it. We do not need to open and close any tags. Let's set things up so that express knows what we intend to use.

pug is a package in of itself, so first let's install that in the terminal npm --save pug. Now let's let express know that's what we are using.

app.set('view engine', 'pug');

That's it, we set the template engine to be pug. Now instead of sending Hello world to the browser. Lets render a pug page instead.

app.get('/', (req, res) => {
    res.render('index')
})

When setting the view engine, express expects the pug pages to be in a directory called views so let's create that directory and add the index file: views/index.pug. There we add the code we would like to display on the browser. Let's give it a pug version of hello world:

    #message
        h1 Hello World 
        h3 pug's in the house

I'm sure you can guess how the above translates to html

    <div id="message">
        <h1>Hello World</h1>
        <h3>pug's in the house</h3>
    </div>

And that's basically it! For a basic usage of express.

Lets create a website

To demonstrate the basic usage of express I created the following website. It's a website with few pages. Each page tells us something about the given artist. It illustrates the use of resources (images, css, js) within a react app and a more detailed use of routers.

Lets work with routing

As it can be seen from the screenshot above, this website is going to have three simple pages. This is how the routes could be created

    app.get('/charles', (req, res) => {
        res.render('chaplin')
    })
    app.get('/marilyn', (req, res) => {
        res.render('monroe')
    })
    app.get('/jean', (req, res) => {
        res.render('jimmons')
    })

There we have them. If users navigate to /charles a chaplin.pug template would render on the page.

In our case, the structure for each artist is going to be exactly the same, so the routers are going to render the same pug template!

    app.get('/charles', (req, res) => {
        res.render('index')
    })
    app.get('/marilyn', (req, res) => {
        res.render('index')
    })
    app.get('/jean', (req, res) => {
        res.render('index')
    })

Finally, with the above configuration, if users navigate to the root of the website, they'd get an error of Cannot GET / because we have removed the root router (app.get('/', (req, res) => {})). To fix this problem we can redirect users to another page we desire.

    app.get('/', (req,res) =>{
        res.redirect('/charles')
    })

Working with dynamic data

We have the ability to pass data to the pug templates from routes. Here's an example:

    app.get('/charles', (req, res) => {
        res.render('index', {
            firstname: 'Charles',
            lastname: 'Chaplin',
            tag: 'The Little Tramp',
            content: '...',
            movies: [...]
        })
    })
    app.get('/marilyn', (req, res) => {
        res.render('index', {
            firstname: 'Marilyn',
            lastname: 'Monroe',
            tag: 'Being normal is boring',
            content: '...',
            movies: [...]
        })
    })

We're still asking to render the index.pug page but we're also passing an object to it. Then the index.pug page would look partly something like this

    body
        .wrap
            .profile.hide
                a(href='#').menu
                    span Movies
            .information
                .information__heading
                    span.information__heading__tag= tag
                h1.information__name 
                    small=firstname  
                    | #{lastname}
                p.information__description= content         

See how the information from the json we passed in the routing is used. Pug can read all the data variables we pass by either using the equals sign if we need to render only one variable or by wrapping the variable like so my name is #{name}.

resource files

Every website needs styles and images. This is how I linked the stylesheet and the front end JavaScript.

    doctype html 
    html
        head
            title=title
            link(rel='stylesheet', href='/styles/style.css')
            meta(name='viewport' content='windth=device-width, initial-scale=1')
        body
            .wrap
                ...
        script(src='js/script.js')

Even if the /styles/style.css and js/script.js were correctly placed in their respective directories, express would not make them available to be used as we expect with the above setup.

We first need to tell express where these files are. Or in other words, we need to tell express where our static content lives. Static content refers to anything from stylesheets, javascript files and libraries and even fonts.

To set this up, we need to write the following line in server.js:

app.use(express.static(__dirname + '/public'));

With that in place, we need to create a public directory and within it, we would create the /styles/style.css and js/script.js files. Finally, as we saw from the pug snippet above, everything in the public folder can be accessed from the root, by which I mean, public/js/script.js is available at /js/script.js.

Getting content from a json file

Whilst it's outside of the scope of this tutorial, the content for these artists would be stored in a database and would not be hardcoded inside the routes as we did above. However, for today, we can store the content in a seperate JSON file and use that in the routes. Which would help us manage the data slightly better than we are doing now.

    import data from './data/artists.json'
    ...
    app.get('/charles', (req, res) => {
        res.render('index', data.artist[0])
    })
    app.get('/marilyn', (req, res) => {
        res.render('index', data.artist[1])
    })
    app.get('/jean', (req, res) => {
        res.render('index', data.artist[2])
    })

Now each route gets different data resulting in the following three pages:

Recap

That's it, we covered routers, templates and static files. This is the entire code we should have in server.js. Then the rest is just the usual front end code.

    import express from 'express';
    import data from './data/artists.json';
    const app = express();
    app.set('view engine', 'pug');
    app.use(express.static(__dirname + '/public'));
    const port = process.env.PORT || 5656;
    app.get('/', (req,res) =>{
        res.redirect('/charles')
    })
    app.get('/charles', (req, res) => {
        res.render('index', data.artist[0])
    })
    app.get('/marilyn', (req, res) => {
        res.render('index', data.artist[1])
    })
    app.get('/jean', (req, res) => {
        res.render('index', data.artist[2])
    })
    app.listen(port, () => {
        console.log(`http://localhost:${port}`)
    })

You can checkout the complete project over at github

Posted on by:

aurelkurtula profile

aurel kurtula

@aurelkurtula

I love JavaScript, reading books, drinking coffee and taking notes.

Discussion

pic
Editor guide
 

Hi Aurel, thanks for posting this great express example. I'm having some issues getting going with the import express from "express" command. When I switch it to a const express = require('express') it seems to work. I believe this is due to the fact that NodeJS does not currently support ES6 import statements, is that correct? Or am I out of date on that thinking? Love the simplicity of this first tutorial and glad I was introduced to pug. It's a pretty cool little module!

 

Patrick, if you are interested, I wrote a tutorial on how I quickly make use of babel (and webpack) to get ES6 working. You can read about it here

 

Yes you are right.

I use babel behind the scenes which allows me to use import. and other ES6 features.

Have you tried cloning the project, it is configured for ES6 features to work

 

I had not cloned it yet, but it makes sense now. Thanks for clarifying the 'issue' I was seeing.

 

Wow, this was great! I've been wanting to learn more about the MEAN stack forever and this seems like the most concise, straightforward tutorial I've seen!

Is there an easy way to support a large number of endpoints, say, a bunch of UserIDs that load their recent scores from a game?

 

Thanks

To be honest I don't understand the question (most likely my bad). Would something like this help /?userID=94564,5464,46464 then you take the number and split them.

If my tutorial on Building a RESTful API with Express and MongoDB doesn't answer it, then I'm happy to help if you could give me some more info!

 

I think that tutorial does answer it. Now I'm just trying to get this example to work on my Digital Ocean server :) Trying to figure out this Babel stuff to be able to run 'import' :) haha. Lots of fun and learning.

 

This is amongst the best guides I have seen. I used express quite some ago and restarted recently, this guide did just it’s purpose to get me refreshed.

Express is top-notch, clean, nothing quite like it, it’s almost in every piece of nodejs tech. But as it scales, this app.use invocations will start to form a heap of unnecessary code. So just yesterday I finally decided I have enough and wrote a module that handles this totally, and abstract away all this, true to what an express app should be, totally clean.

github.com/calvintwr/express-route...

 

This is a fantastic tutorial. I have one question: can we generate static pages for each of the three artists and deploy them in the public folder? That way, we could upload the content of the public folder to a hosting account and serve static pages. What would be the best way to do this? Thanks!

 

Unless I'm missing something I do not think you'd use this configuration (these tools) for static pages!

Unless you use static page generators (or create your own, kind of how I did here though my aim was to generate markdown files) I don't think there's any other way.

 

This is definitely one of the best intros to Express that I've read. I want to thank you so much for the time you invested on putting this together for us.

It did really clear some doubts that I had, I am about to read your next article Building a RESTful API with Express and MongoDB

Best,

Martin.

 

Thanks for sharing! For the sake of being explicit you should add "Pug" to the title ie; "Creating a basic website with Express.js and Pug.js"

 

Great intro to express, thanks for writing