Our app has been split into two: front-end and back-end.
-
The front-end requires a series of build steps to lint, test, and transpile our HTML/CSS/JS source code.
Location:
/frontend
-
The back-end is a web service that runs continuously and also serves the front-end assets from the dist folder.
Location:
/backend
We also have two environments: development and production.
- During development we want to make our lives easier by exposing a debugging interace and watching for source code file changes to automatically re-run the build, lint, and other steps.
- The production environment is deployed to our public web server. We want to create as lean an environment as possible to achieve optimal performance.
Using NPM and the scripts
field of the package.json
file, we have declared all the necessary command line instructions. This allows us to customise the build tool chain while maintaining a simple, consistent interface.
npm run dev
npm start
npm test
Note: The CI build runs on cloud services like Travis CI, CircleCI, Codeship, or Jenkins. They help teams collaborate and act as a final check to prevent deploying broken builds.
For this MVP we can simply load data from a JSON file.
import database from './database.json'
See: database.json
The database schema defines the structure of the database contents. Each Friend object has two properties of a specific type.
{
id: Number,
name: String
}
The Express framework builds upon Node.js' built-in http
module. It offers the routing capability we need to implement the RESTful APIs.
import express from 'express'
const app = express()
Then let's set up some routes. Listing out all friends:
app.get('/friends', (req, res) => {
res.json(database.friends)
})
Looking up a specific friend:
app.get('/friends/:id', (req, res) => {
const byId = ({id}) => id === +req.params.id
const result = database.friends.find(byId)
if (result) res.json(result)
else res.status(404).end()
})
And finally start listening to accept incoming requests.
const server = app.listen(3000, function () {
const {port} = server.address()
console.log(`Listening on port ${port}`)
})
Express can serve the built front-end HTML/CSS/JS assets from the dist
folder using the static
middleware.
app.use(express.static('dist'))
In frontend/index.html
let's set up some user interface elements for our front-end app.
<main>
<h1>Everyone's Friends</h1>
<ul id="friends"></ul>
<button id="reload">Reload</button>
</main>
Move the script
tag to the end of the HTML document. This ensures the DOM has been parsed and when the JavaScript code runs. It also improves load performance, an important factor in more complex web pages.
Then in frontend/app.js
let's implement the API call from the front-end to the back-end:
document.querySelector('#reload')
.addEventListener('click', async event => {
const response = await fetch('./friends')
const friends = await response.json()
for (const {id, name} of friends) {
const listItem = document.createElement('li')
listItem.innerText = name
listItem.dataset.id = id
document.querySelector('#friends')
.appendChild(listItem)
}
})
See: app.css
See: app.js
Tip: Use the fetch API instead of XML HTTP Request (XHR, aka AJAX).
- Log in to Travis CI with your GitHub account.
- Connect the
pfnp
repository to Travis CI. - Push some code to GitHub.
- Watch the live build progress on Travis CI!
Demo: https://travis-ci.org/cbas/pfnp
- Create a Heroku account.
- Create an app on Heroku. This is the domain name where the app will run after a successful deployment.
- Connect the app to GitHub and enable automatic deployments with the Continuous Integration option.
- Push some code to GitHub.
- Enjoy your free, automated hosting!
Demo: https://pfnp.herokuapp.com/
- Download and install the Heroku Toolbelt.
- Use the Heroku CLI to authenticate and configure your local repository.
- Run
heroku logs --tail
to inspect any errors.