-
Notifications
You must be signed in to change notification settings - Fork 1
Worked Example: Making the copyright year dynamic
So the CompSoc website copyright year needs to be updated every year... That's a pain. Let's automate it instead!
This guide assumes that you have successfully set up a development environment and can access the website at localhost:9000
without issues. This example may become out of date over time. As far as is possible, links to files at this specific commit have been given so that you can follow along online. To locally see the exact same files as the author did at the time of writing, you can use git checkout cefa6098fd45d48df3a94e07a8f2e4980ca3b913
.
Dynamic content in the context of a website is content the server has to process in some way to tailor to the client. On a website such as Facebook or Github, an example is your homepage which (hopefully) should only show you stuff related to your account. This example is a tad simpler but uses some of the same principles.
As of the latest commit at time of writing, the website year is hard baked into the code. It is a value shown on every page, so it should be included in one of the pug templates (located in views/templates/
). Sure enough, the file base.pug contains (on line 16-18):
block footer
.footer
div © 2016-2017 Durham University CompSoc
But how would I ever know this? Please don't be disheartened if you cannot find something immediately. It takes a while to get used to how the project is laid out (if you require proof of this, just look back at our early commits!).
Pug is a templating language. Every time a route (the bit after the compsoc.tech) is requested, Pug is compiled into HTML. For the CompSoc homepage, this route is simply /
. We can see how this route is handled (and where the Pug is compiled) by looking at app.js (located in the project's root directory).
Express is the webserver module that handles routes. An instance of an express "application" creatively called app
is created on line 26:
var app = express();
This is the main way of interacting with express. The express application variable has many functions attached to it. For an HTTP GET request to the homepage, the one we are interested in is imaginatively named get
. To see the full list of functions available via Express, consult the documentation (there are far too many functions to enumerate here, and their docs are pretty good!).
We can see app.get
in action on lines 63-65 of app.js
:
app.get('/', function (req, res) {
res.render('index');
});
From this we can see that if a GET request is made to /
, an anonymous function which is passed the request (req
) and response(res
) as parameters is called. This function in turn runs res.render('index')
which renders (~compiles) the index.pug
page into HTML and sends it as a response to the request.
Q: How does res.render('index')
know where to look for index.pug
? And why don't I need the .pug extension?!
A: On lines 32-33 of app.js an important function of app (our express application instance remember!) is called twice:
app.set('views', './views');
app.set('view engine', 'pug');
app.set(name, value)
assigns a setting, name
to value
(lifted straight from the express docs - I told you they were good!). So these two lines are setting up express to use pug as the view engine (line 33) and to use the directory named views as the directory that holds the page views (line 32). The whole concept of views is a bit much to explain here, but consider them the thing that is presented to the end user of the website. Without setting the view engine and the views directory, res.render
would take plain text as input and treat it as plain HTML.
Q: This is a lot of effort. Why not use plain HTML?
A: If we used plain HTML there would be no chance at all of displaying dynamic content. Pug on the other hand can be passed variables! Let's see that now!
Changing line 64 of app.js
to
res.render('index', {currentYear: 2018});
makes the currentYear
local available to index.pug
. If we want it to be displayed anywhere we'll also have to modify the pug directly. On line 18 of base.pug
let's change to:
div © 2016-#{currentYear} Durham University CompSoc
Taking a look at the website locally (by running npm start
) we should see the familiar message Example app listening on port 9000!
in the terminal, and at localhost:9000
in a web browser, the footer has changed to 2018. Hooray!
So that's job done right? Not so fast! If you navigate to another page (e.g. http://localhost:9000/about) you'll see that the "to" year is completely missing. What gives?
In breif, we only changed the res.render
of the homepage route! We need to update the res.render
s of all the routes to include {currentYear: 2018}
...
Yes. But do we really want to change every single res.render
call? This isn't very DRY and is extemely error prone. Express gives us a nice way to set this value for every route via res.locals
.
First let's remove the addition we made to line 64 of app.js
. Either remove the code directly or you can use git checkout app.js
on the command line to reset it.
Next we want to add the lines:
app.use(function(req, res, next) {
res.locals.currentYear = 2018;
next();
});
It doesn't matter too much where these lines are placed, so long as they are after app = express();
and before the app.listen
is called.
app.use
is another express application function. Essentially, for every route, the anonymous function will be called. So each time a request is made, the response (res
) local currentYear
will be set to 2018. For more information see how we use express middleware.
Reload the application (CTRL-C to stop if you ran npm start
in the foreground, kill the process via kill <PID>
if you ran it in the background somewhere and in both cases rerun npm start
). You should now see that any page you navigate to contains the correct copyright year!
Time to pop the champagne? Nearly! The issue is that we haven't changed much. Someone will still have to update the code every year to set res.locals.currentYear
to the correct year. But now we're setting the value via javascript and not pug we can use a function to calculate the year from the current time for us!
Changing the res.locals.currentYear = 2018;
line to
res.locals.currentYear = new Date().getFullYear();
does the trick! A new date (according to our webserver's current date) will be computed for every request. Anybody requesting the website at any time in the future will see the correct copyright year displayed with no manual intervention.
Stretch:Reloading the website application, there should be no difference in output. Can you prove the change to dynamic date was successful and it's not just working because you forgot to reload the application?
During the course of writing this documentation, there were some things I had to look up. The sources I used are listed below. References:https://pugjs.org/language/interpolation.htmlhttps://stackoverflow.com/questions/38044237/node-js-pass-a-variable-to-jade-pughttps://gist.github.com/joepie91/c0069ab0e0da40cc7b54b8c2203befe1https://www.w3schools.com/js/js_date_methods.asphttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Datehttps://expressjs.com/en/api.html#res.locals