Markdown

Markdown permet de structurer un document en mode texte via quelques conventions.

Utiliser markdown c'est finalement dire au revoir aux traitements de texte grâce à pandoc qui permet des exports dans tout un tas de format, ainsi qu'aux logiciels de présentation de type powerpoint avec des outils comme reveal.js.

Structurer son contenu en mode texte représente un gain en productivité indéniable et permet de rester concentrer sur ce que l'on écrit sans se préoccuper de la mise en forme. Un bon éditor de texte de type sublime text ou atom.io pour plus de confort et markdown sera l'allié des toutes vos prises de notes, documents ou présentattions.

Si vous avez encore besoin d'arguments concernant tous les bienfaits de markdown (chance aux jeux, retour de l'être aimé, ...) lisez ça : You Should Probably Blog in Markdown

Le CMS statique

L'idée n'est pas neuve mais elle fait toujours sens au moins pour deux raisons:

  1. La sécurité: pour un blog qui, bien souvent, est alimenté par une et une seule personne, garder une partie /admin ouverte à la terre entière est une hérésie: c'est un appel aux attaques de tout type : brute force de mot de passe, exploitation de failles du CMS, etc ... C'est pourtant le cas des CMS les plus répandus.

  2. Les performances: les requêtes vers les bases de données ont un coup en temps. Chaque requête grignote un peu sur le temps de réponse d'une page web. Dans la plupart des cas ces requêtes sont multiples et souvent déconnectées les unes des autres. Il n'est pas rare d'effectuer plusieurs fois la même requête lors de la construction d'une même page ... On peut faire du cache me direz vous et bien justement si on pousse l'idée du cache jusqu'au bout on tombe sur l'idée du CMS statique.

Bien sûr ce n'est pas la bonne solution dans tous les contextes, mais pour un blog perso l'option me paraît à considérer!

Le moteur de blog statique

J'avais déjà testé jekyll sur github et l'idée d'écrire des posts en markdown en les versionant avec git me plaisait beaucoup.

L'excellent StaticGen Top Open-Source Static Site Generators donne un bon aperçu de ce qui existe dans cette idée.

sculpin.io est l'outil de génération statique qui simpose dans le monde PHP et je l'avais déjà repéré chez les copains

Sculpin

sculpin.io se prend vite en main, surtout si vous avez déjà joué avec jekyll, car son fonctionnement est tout à fait similaire. La documentation est plutôt bien faite et quelques plugins vous rendront service en même temps qu'ils vous permettront

Bootstrap & material

inspiré de Material Design de google, Bootstrap Material Design tend à mettre à disposition du designer un langage visuel permettant à la fois une mise en forme claire et une compréhension intuitive des interactions disponibles par l'utilisateur (en gros).

Dans le cas d'un design de blog, très honnêtement, c'est le marteau pilon pour écraser la mouche, mais bon c'est fun, joli et bien fait alors pouquoi s'en priver?

Gérer l'intégration de ce type de produits est devenu un vrai bonheur depuis bower.io

bower install bootstrap-material-design fontawesome
Voici le genre d'effet que vous permettra Bootstrap Material Design

le code pour cet effet de ouf !!

<div class="well">
Voici le genre d'effet que vous permettra <a href="https://fezvrasta.github.io/bootstrap-material-design/">Bootstrap Material Design</a>
</div>

Reste ensuite à peaufiner son design en changeant les couleurs du thème.

Le Pantone Bootstrap peut vous filer un coup de main sur la déclinaison des couleurs.

J'ai ensuite cherchée un affichage de date sympa en css3 pour les posts

Prism

Ensuite il me fallait un "code highlighter" javascript digne de ce nom. j'utilise highlight.js dans mes slides reveal.js et je voulais essayer autre chose.

J'ai donc tenté PRISM, d'autant qu'il est en parti écrit par @leaverou que je suis depuis longtemps sur twitter.

Avec ce genre de syntaxe au milieu de mon code markdown

~~~language-php
if ($fencedCodeBlock->syntax !== 'PHP') {
    throw new UnexpectedValueException("wat");
}
~~~

j'obtiens ce rendu

if ($fencedCodeBlock->syntax !== 'PHP') {
    throw new UnexpectedValueException("wat");
}

grunt

grunt est un outil JS et comme tous les outil JS est :

  • déjà dépassé (on lui préfèrera webpack ou un obscur projet de build dont le premier commit date de la semaine dernière)
  • multi fonction (il a des tasks pour tout)
  • très pratique

Basiquement j'aime me servir de grunt pour concaténer et minimiser mes js & css et avoir quelques taĉhes en ligne de commande. Voici le squelette de mon Gruntfile.js

module.exports = function(grunt) {
  grunt.initConfig({
    /* colossale feinte pour les fichiers font de font-awesome http://www.partage-it.com/fichiers-font-awesome-pas-dans-le-package-yo-angular/ */
    copy: {
      fonts: {
        expand: true,
        flatten: true,
        src: ['source/bower_components/fontawesome/fonts/*'],
        dest: 'source/fonts/'
      }
    },

    cssmin: {
      combine: {
        files: {
          'source/grunted/main.min.css': [
            // liste de tous vos fichiers css
          ]
        }
      }
    },

    concat: {
      dist: {
        src: [
          // liste de tous vos fichiers js
        ],
        dest: 'source/grunted/main.js'
      }
    },

    uglify: {
        build: {
            src: 'source/grunted/main.js',
            dest: 'source/grunted/main.min.js'
        }
    },

    shell: {
        deploy: {
            command: 'sculpin generate-search --env=prod',
            options: {
                execOptions: {
                    maxBuffer: Infinity
                }
            }
        },
        serve: {
            command: 'sculpin generate-search --server --watch --no-index --port 1337',
            options: {
                execOptions: {
                    maxBuffer: Infinity
                }
            }
        }
    }

  });

  // Dependencies
  grunt.loadNpmTasks( 'grunt-contrib-concat' );
  grunt.loadNpmTasks( 'grunt-contrib-uglify' );
  grunt.loadNpmTasks( 'grunt-contrib-cssmin' );
  grunt.loadNpmTasks( 'grunt-contrib-copy' );
  grunt.loadNpmTasks( 'grunt-shell' );

  // Clean thumb
  grunt.registerTask( 'default', [ 'copy:fonts', 'cssmin', 'concat', 'uglify' ] );
  grunt.registerTask( 'deploy', [ 'shell:deploy' ] );
  grunt.registerTask( 'serve', [ 'shell:serve' ] );

};

fabrik

fabrik est une lib d'abstraction minimaliste pour automatiser des commandes via ssh ce qui en fait un très bon outil pour le déploiement d'applications ou la configuration de nouvelle machine. dans le cas de sculpin voici mon fabfile.py qui me permet de mettre à jour ce blog avec un simple

fab deploy
#fabfile.py
from fabric.api import *
import os.path
import re
import time
from datetime import datetime

# source dir name
source_path = "."
# local project folder
source_project_path =  os.path.dirname(os.path.abspath(__file__))
# local project name
source_project_dirname = os.path.split(source_project_path)[1]
# parent project folder name
source_parent_project_dirname = os.path.split(source_project_path)[0]
# source dir name
source_output_dirname = "output_prod"

# the servers where the commands are executed
env.hosts = ['blog.mazenod.fr']
# the user to use for the remote commands
env.user = 'bloguser'
# remote deploy path
dist_path = "/var/www/clients/client0/web1"
# aliased web folder name
dist_web_dirname = "web"
# aliased home folder name
dist_home_dirname = "home/blog.mazenod.fr"
# number of saved versions
dist_retention = 3
# remote folder deploy path (home dir)
dist_deploy_path = dist_path + '/' + dist_home_dirname
# remote folder deploy name (current timestamp)
dist_deploy_dirname = datetime.now().strftime("%s") # time.strftime("%Y-%m-%d-%H-%M-%S")

def deploy():
    pack()
    put_files()
    clean()

def pack():
    # create a new source distribution as tarball
    local('/usr/local/bin/sculpin generate --env=prod')
    #local('cd ' + source_output_dirname)
    local('tar -zcvf /tmp/pack.tar.gz -C ' + source_project_path + ' ' + source_output_dirname)

def put_files():
    # put tarball
    put('/tmp/pack.tar.gz', dist_deploy_path + '/pack.tar.gz')
    # delete local tarball
    local('rm /tmp/pack.tar.gz')
    with cd(dist_deploy_path):
        # extract remote tarball
        run('tar -zxvf ' + dist_deploy_path + '/pack.tar.gz')
        # delete remote tarball
        run('rm ' + dist_deploy_path + '/pack.tar.gz')
        # rename with deploy folder name
        run('mv ' + dist_deploy_path + '/' + source_output_dirname + ' ' + dist_deploy_path + '/' + dist_deploy_dirname)
        with settings(warn_only=True):
            # delete staled symlink if exists
            run('rm ' + dist_path + '/' + dist_web_dirname)
        # symlink deploy folder
        run('ln -s ' + dist_deploy_path + '/' + dist_deploy_dirname + ' ' + dist_path + '/' + dist_web_dirname)

def clean():
    with cd(dist_deploy_path):
        dirs = sorted([n.strip() for n in re.split('[\s\r\n]+', run('ls -d */'))])
        for folder in dirs[:-dist_retention]:
            run('rm -rf ' + folder)

les paths sont induits par l'utilisation d'ispconfig mais doivent s'adapter assez simplement

Gitlab

Pour finir il me fallait un repo pour héberger tout ça et je n'avais pas envie de quelque chose de public ... plus pour le principe qu'autre chose d'ailleurs, parce que finalement je me fous un peu de cramer mes drafts ... Cette contrainte ne pouvait pas être satisfaite avec mon compte gratuit github qui ne me donne accès qu'à des repos privés. Il se trouve que Gitlab qui cherche visiblement à attirer les utilisateurs propose des repo privés et gratuits, illimités en nombre par utilisateurs et limités à 10 Go par projet ... ce qui laisse un peu de place pour bloguer ;)

Conclusion

Avec des outils simples et avec assez peu de modification la constitution de ce nouveau blog a été assez rapide sous tous les aspects. J'ai juste mis 6 mois à le déployer ... Et histoire de ne pas avoir fait ça pour rien je vais tenter de bloguer plus d'une fois par an.

DEV DIY SEC WEB php static generator