mail

valettearnaud

Comment fonctionne ce site ?

Cela fait longtemps que je souhaite trouver un moyen basique de publier sur le web, sans avoir à gérer de dépendances et/ou de services spécifiques autres que:

  • Un éditeur de texte
  • Un soft basique (Ngynx, Apache)
  • Une machine distante
  • Emacs
  • Org-mode

Elisp

Dans un dossier www/org/, le site est structuré comme une arborescence récursive de fichiers org. Lors de la publication, org-publish se charge de publier récursivement à partir de la racine vers www/out/. J'ai des articles en cours de rédaction, ils sont préfixés du mot clé TODO.

(setq org-publish-project-alist
      '(("site-content"
         :base-directory "~/www/org/"    
         :publishing-directory "~/www/out/" 
         :exclude "TODO.*\\.org"
         :recursive t
         :publishing-function org-html-publish-to-html
         :headline-levels 3   
         :section-numbers nil 
         :with-toc nil        
         :auto-preamble t
        )

        ("site-static"
         :base-directory "~/www/org/"
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|webp"
         :publishing-directory "~/www/out/"
         :recursive t
         :publishing-function org-publish-attachment)

        ("site" :components ("site-content" "site-static"))))

L'aspect CI/CD est géré très simplement. Le serveur sert directement ce qui se situe sur /var/www/html, j'ai décidé de réaliser une pipeline brutale :

  • rsync pour envoyer le site via ssh au serveur.
  • ssh et script bash basique pour déplacer le site vers le dossier servi.
  • J'utilise evil-mode donc <espace> s p publie mon site directement sur le serveur, en appuyant successivement sur ces trois touches, je lance org-publish, je lance rsync et je lance le script bash sur le serveur, cela me prend environ 150ms, mais j'arrive parfois aux alentours des 90ms.

Vous pouvez mesurer par vous même à l'aide de cette fonction:

(defun measure-spc-s-p-time ()
  (interactive)
  (message "Press SPC...")
  (while (not (equal (read-key) ?\s)))
  (let ((start-time (float-time)))
    (message "Now press 's'!")
    (while (not (equal (read-key) ?s)))
    (message "Now press 'p'!")
    (while (not (equal (read-key) ?p)))
    (let* ((end-time (float-time))
           (elapsed-ms (* 1000 (- end-time start-time))))
      (message "Score: %.2f ms" elapsed-ms))))

La fonction publish :

(defun publish-website ()
  (interactive)
  (org-publish-all t)
  (shell-command "zsh -i -c 'rsync -avz -e \"ssh -i ~/.ssh/<KEY>\" ~/www/out <SERVER>:~/'")
  (shell-command
   "ssh -i ~/.ssh/<KEY> <SERVER> 'sudo rm -rf /var/www/html/* && sudo cp -r ~/out/* /var/www/html/' && echo 'DONE :)'"))

(evil-define-key 'normal 'global
  (kbd "SPC s p") 'publish-website)

Org

En utilisant intelligemment l'attribut INCLUDE, on peut obtenir un site structuré qui dispose d'une sitemap. Chaque article est un fichier org, chaque sous chemin de l'arborescence est un dossier contenant un fichier index.org, lequel inclue le header du site et un menu de navigation arborescent.

Parfois, l'utilisation de macros peuvent rendre la tâche plus agréable.

#+MACRO: quote (eval (format "#+begin_export html \n<blockquote><p>%s</p><div class='quote-author'>— %s</div></blockquote>\n#+end_export" $1 $2))
#+HTML_HEAD: <script src="static/solver.js"/></script>
#+INCLUDE: index.org

Utilisation directe d'une macro:
,{{{quote({contenu}, <a href="{lien}">{description}</a> )}}}

Grâce au template structurel begin_export (html). Il est même possible de rédiger du html directement (et donc du javascript).

(Note: il est possible d'importer des scripts (cf. attribut HTML_HEAD exposé au-dessus).

#+begin_export html
<div class="chess" id="chess_example_2"></div>
<script>
  const ex2 = new Explanation(document.getElementById("chess_example_2"), "canvas_chess_2", new Solver("SOLVE"));
</script>
#+end_export

Created: 2026-07-14 Tue 10:05

Validate