Yet another blog

  • Written on: Su Feb 2019
  • Last update: Su Feb 2019

Ceci est un autre blog. Encore un autre blog parmi une multitude de blogs de développeurs. Et ceci est le premier article de ce blog.

Si tu lis ce blog c'est que tu es sans doute intéressé par ce que je fais, ce que je pense ou par les projets que j'ai pu réaliser.

Sache que ce blog relatera beaucoup de ce que je fais, de ce que je pense et principalement des projets que je réalise.

C'est un blog personnel mais aussi éducatif. J'aime beaucoup aider les gens sur les forums donc pourquoi ne pas le faire à travers des articles de blog. Qui-sait, vous apprendrez sans doute des choses en me lisant.

Et vous savez quoi? Je vais vous expliquer comment j'ai concu ce blog from scratch.

Tech

Tout ce site est fait en VueJS, en utilisant le framework NuxtJS pour le server side rendering.

Pour le blog, je voulais quelque chose de très simple pour pouvoir vite le déployer en production. C'est pour quoi j'ai fait un petit back-end en NodeJS qui expose une API grâce à Express.

Tous les articles sont écris en markdown. L'API récupère le contenu de ce markdown et le front n'a plus qu'à décoder ce markdown et le transformer en balises HTML que je peux réutiliser avec Nuxt.

Simple non? Voyons ça étape par étape.

Création d'un backend

Nous allons commencer par créer notre backend. Pour ça, dans mon projet, j'ai crée un dossier /back.

Docker

Dans ce dossier, je vais créer une image Docker. Si vous ne savez pas ce qu'est Docker et comment on l'utilise, vous pouvez vous renseigner par ici: Tout le projet est sous Docker que ce soit le front ou le backend donc je vous conseille vivement à vous renseigner dessus pour tout comprendre par la suite.

Dans mon image Docker j'ai:

FROM node:10

WORKDIR /usr/src/back

COPY package-lock.json .

COPY package.json .

RUN npm ci

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

Tout d'abord, la première ligne:

FROM node:10

Cette ligne indique que je vais avoir besoin de NodeJS 10. Il ira donc télécharger cette version de NodeJS depuis Dockerhub. Pourquoi Node 10? Car c'est la dernière version stable à l'heure où j'écris cet article. Elle permet d'écrire de l'ES6 sans trop se casser la tête avec les transpilations de Javascript.

Nous avons ensuite:

WORKDIR /usr/src/back

On dit à docker que notre projet sera stocké dans le dossier /usr/src/back DANS Docker. Attention, ce n'est pas là où est stocké NOTRE code.

COPY package-lock.json .

COPY package.json .

RUN npm ci

Nous copions ensuite deux fichiers (package.json et package-lock.json). Ces deux fichiers contiennt les dépendences de notre back-end. On lance juste après la commande npm ci. Cette commande va nous permettre d'installer toute nos dépendences (un peu comme npm install) mais en se baseant sur le package-lock.json! Vous pouvez en savoir plus sur npm ci ici:

COPY . .

EXPOSE 3000

On copie le reste du projet depuis notre machine vers Docker et on expose le port 3000 qui sera utilisé par l'API.

API Express

Je suis partie sur une API avec Express. Express est un petit framework qui nous permet de faire des APIs en NodeJS très rapidement et sans prise de tête. C'est donc parfait pour notre cas.

Voilà la bête:

const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const app = express()

// Import the articles list, see later in the article.
const articles = require('./articles')

const PORT = process.env.PORT || 3000
const HOST = process.env.HOST || 'localhost'

// Use a JSON body
app.use(bodyParser.json())

// Allow CORS rules
app.use(cors())

// Expose a GET /articles API to retrive all the
// articles
app.get('/articles', (req, res) => {
  res
    .status(200)
    .send(articles.map((article) => {
      const a = Object.assign({}, article)
      delete a.content
      return a
    }))
})


// Expose a GET /articles/:slug to retrive
// a sigle article based on his slug
app.get('/articles/:slug', (req, res) => {
  if (req.params.slug) {
    const article = articles.find(a => a.slug === req.params.slug)
    if (article) {
      res
        .status(200)
        .send(article)
    } else {
      res
        .status(404)
        .send({
          error: 'The article was not found'
        })
    }
  } else {
    res 
      .status(400)
      .send({
        error: 'The slug parameter is missing'
      })
  }
})

app.listen(PORT, HOST, () => {
  console.log(`Server started on port ${HOST}:${PORT}`)
})

Pour découper ça très rapidement:

const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const app = express()

// Import the articles list, see later in the article.
const articles = require('./articles')

const PORT = process.env.PORT || 3000
const HOST = process.env.HOST || 'localhost'

// Use a JSON body
app.use(bodyParser.json())

// Allow CORS rules
app.use(cors())

Grossièrement, on importe nos dépendences et les articles qu'on aura; on défini le HOST et PORT à utiliser par notre API. Ces deux données pourront être spécifiés par Docker. On a aussi un middleware pour bodyParser et cors qui nous permettent de régler les règles de cross-origin et d'exposer une API en JSON par défaut.

// Import the articles list, see later in the article.
const articles = require('./articles')

J'importe un fichier qui se trouve dans /articles/index.js. Dans ce fichier, j'expose tous les articles qui sont en ligne sous forme d'un tableau comme ceci:

const fs = require('fs')
const path = require('path')

module.exports = [
  {
    slug: 'another-blog',
    title: 'Yet another blog',
    tags: ['Tutorial'],
    created_at: '2019-02-10',
    updated_at: '2019-02-10',
    caption: 'Just launched my website with a brand new blog. Learn how I set up this blog with a simple Express API, some markdown files and NuxtJS.',
    content: fs.readFileSync(path.resolve(__dirname, './another-blog.md'), 'utf8')
  }
]

When the server is started, this file will read the another-blog.md file and write it's content in the content key.

Là est le plus intéressant:

app.get('/articles', (req, res) => {
  res
    .status(200)
    .send(articles.map((article) => {
      const a = Object.assign({}, article)
      delete a.content
      return a
    }))
})

On crée un endpoint GET /articles où on retourne tous les articles, sous le format d'une liste.

Si vous souhaitez y jeter un coup d'oeil, sachez que ce site est entièrement open-source. Vous pouvez bien-sûr le forker, le personnaliser à votre goût et le réutiliser pour vos besoins!

Si vous êtes intéressés par ce que je vais dire ici, n'hésitez pas à me suivre sur Twitter !