Journal Générateur de site web statique

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes : aucune
24
5
juil.
2019

Il semblerait qu'il y a une mode autour des générateurs de code statique, qui aurait été lancé par Jekyll issue de github écrit en ruby. L'idée de base est : pourquoi s’embêter avec une base de donnée et du code serveur pour du contenu statique ? De plus, du joli code HTML simple est bien plus rapide et mieux indexé par Google. Cela permet aussi d'utiliser Git pour gérer son site web et d'éviter les mises à jour live ou par ftp de Wordpress. Bien sûr les fonctionalités avancées ne sont pas les mêmes (pas d'édition en ligne, par exemple).

La hype se tourne vers hugo écrit en go qui est très rapide à la génération. J'ai essayé pour mon site ( https://www.macropaiement.com/blog/ pour les curieux), un blog se fait en quelques minutes (un fichier de config yaml + un fichier par post). La mise en place est rapide. L'organisation se base sur un système de "thème" qui traduit des fichiers en site web. La partie contenue est très simple à écrire et à comprendre. Le code des thèmes ressemble encore à nouveau langage de template bof. On dirait du jsx (de React) en plus moche.

Il y a d'autres générateurs dont un qui repose sur React (Gastby), j'imagine que pour faire des sites plus complexes, cela sera plus facile qu'avec Hugo.

Pour en lire plus :
https://www.techiediaries.com/jekyll-hugo-hexo/
https://opensource.com/article/17/5/hugo-vs-jekyll

  • # Site de référence

    Posté par  . Évalué à 8.

    Le site de référence des générateurs statiques: https://www.staticgen.com/

    (Perso., je commence également, mais je me suis tourné vers Nikola, qui a le bon goût de comprendre reStructuredText…)

    • [^] # Re: Site de référence

      Posté par  . Évalué à 9.

      qui a le bon goût de comprendre reStructuredText…

      Il y a aussi pelican.

      • [^] # Re: Site de référence

        Posté par  . Évalué à 2.

        J'utilise aussi Pelican, mais à partir de MarkDown. Le système d'extension est assez pratique, j'ai pu rajouter un module pour remplir une tâche spécifique assez facilement.

      • [^] # Re: Site de référence

        Posté par  . Évalué à 3. Dernière modification le 05 juillet 2019 à 12:37.

        J'ai essayé les deux, et c'est clair qu'Hugo est bien plus rapide !

      • [^] # Re: Site de référence

        Posté par  (Mastodon) . Évalué à 5.

        Pour mes projets en python:
        + pelican pour le doc utilisateurs
        + sphinx pour le doc technique

        Les deux sont construites dans des projets différents, via gitlab-ci:
        + <app>/docs pour la doc technique, construite via une directive pages dans gitlab-ci
        + <app-docs> pour la doc utilisateurs, construite via une directive pages dans gitlab-ci

        Bien à vous

  • # templates hugo

    Posté par  (site web personnel) . Évalué à 1.

    Le code des thèmes ressemble encore à nouveau langage de template bof.

    C'est le langage de templates standard de go…

    • [^] # Re: templates hugo

      Posté par  (site web personnel) . Évalué à 7.

      En effet, et c'est moche.

      {{ $script := .Site.Data.webpack_assets.app }}
      {{ with $script.js }}
      <script src="{{ relURL (printf "%s%s" "dist/" .) }}"></script>
      {{ end }}

      "La première sécurité est la liberté"

      • [^] # Re: templates hugo

        Posté par  . Évalué à 9.

        Beurk, encore pire que Templeet ;-)

        BeOS le faisait il y a 20 ans !

  • # Retour rapide sur Hugo

    Posté par  (site web personnel, Mastodon) . Évalué à 6.

    J'utilise Hugo depuis la version 0.15 (avril 2016). Globalement ça fait bien le job.

    J'ai customisé pas mal de templates à l'époque, et il y avait de sérieuses limitations dès qu'on voulait utiliser une autre langue que l'anglais, notamment avec la gestion des dates qui est l'exemple type de la fausse bonne idée.

    Si je n'ai jamais eu de souci à la mise à jour du moteur d'exécution (les incompatibilités nécessitant une mise à jour des templates étaient systématiquement documentées), ça fait presque un an que je ne l'ai plus mis à jour (la version actuelle du site est générée avec Hugo 0.47.1 d'après les métadonnées).

    Si ça intéresse quelqu'un de voir les templates de ce site, faites-moi signe et je les extrairai dans un dépôt public :) (ça n'a jamais été fait par pure flemme).

    La connaissance libre : https://zestedesavoir.com

  • # pour les pythonistes

    Posté par  . Évalué à 7. Dernière modification le 05 juillet 2019 à 11:54.

    La doc python utilise cela aussi depuis pas mal d'année avec Sphinx.

    Qui lui utilise reStructuredText et Markdown

  • # Hakyll

    Posté par  (site web personnel) . Évalué à 4.

    Voir aussi Hakyll qui utilise Pandoc, donc n'importe quel format d'entrée.

    • [^] # Re: Hakyll

      Posté par  (site web personnel) . Évalué à 2.

      Perso, je suis un grand fan de Hakyll : je le trouve très puissant et très performant. Mais il faut quand même préciser qu'il est plus compliqué à utiliser : ce n'est pas un générateur de blog mais une bibliothèque Haskell qui permet de coder son propre générateur de blog.

  • # Pas d'édition en ligne, vraiment ?

    Posté par  . Évalué à 4.

    Si, c'est ce qu'amène https://www.netlifycms.org/ Le contenu est stocké sur Github ou Gitlab.

    Editors get a friendly UI and intuitive workflow that meets their content management requirements.

    Netlify CMS is built as a single-page React app. Create custom-styled previews, UI widgets, and editor plugins or add backends to support different Git platform APIs.

    Content is stored in your Git repository alongside your code for easier versioning, multi-channel publishing, and the option to handle content updates directly in Git.

    Pas testé.

  • # Genshi

    Posté par  . Évalué à 1.

    A priori pas cité auparavant, il y a Genshi.
    J'ai fais sa connaissance indirectement par Lazygal : un générateur de galeries photo en HTML "statique" (un zeste de JS, c'est tout. Thèmes personnalisables)

    • [^] # Re: Genshi

      Posté par  . Évalué à 3.

      Heu, sauf erreur de ma part: non!
      Genshi est un moteur de template en Python, au même titre que Jinja2, mais ce n'est pas un générateur de site statique. Un tel outil utilisera généralement un moteur de template, cela dit.

      • [^] # Re: Genshi

        Posté par  . Évalué à 2.

        D'ailleurs, créé initialement par Edgewall pour Trac, Genshi est en passe d'être abandonné par ce dernier pour le bien plus véloce Jinja2 (source).

  • # C'est vendredi ...

    Posté par  (site web personnel) . Évalué à 2.

    Il y a quelques mois j'ai voulu mettre mon CV en ligne, coté plateforme style indeed ou linkedin c'est pas top ou alors c'est fait pour des personnes rentrant dans un moule "classique"

    Alors je me suis mis au HTML et comme tout informaticien qui se respecte j'ai commencé par chercher du minerai de fer, pour ensuite fabriquer une forge, ce qui m'a permis de créer … l'équivalent d'un pioche logicielle, que j'aurais pu trouver dans toute les bonnes quincailleries …

    Pour finir par utiliser HTML + BOOTSTRAP + PUG (ex Jade) et comme outil vim, git et quelques scripts python qui vont chercher les données dans … des fichiers textes le tout orchestré par … un Makefile

    un simple make en ligne de commande, lance les scripts puis lance la génération des pages à partir des templates, pour finir par déposer ces fichiers Htmls (et donc statiques ) sur le serveur distant.

    La simplicité c'est bien souvent ce qui nous fait le plus défaut.

    Il y a très longtemps, j'avais lu dans un manuel le principe de base du codeur : think - edit - make

    Or trop souvent on oubli la première partie pour se lancer sur son éditeur ou sur l'outil, le framework à la mode ou la dernière version d'une application.

    • [^] # Re: C'est vendredi ...

      Posté par  . Évalué à 10.

      Donc tu nous expliques que tu as réinventé quelque chose qui existe déjà, mais qu’il faut toujours chercher à faire simple et que « OMG, l’informatique et ses nouveaux frameworks à la mode, tout se perd ma petite dame, avant on faisait ça avec ed » ?

      Pelican et Hugo (je ne connais que ces deux là), font exactement ce que tu dis : tu as d’un côté des fichiers de templates, de l’autre des fichiers de contenu (en Markdown ou RST) et avec un coup de make, ça compile et ça envoie le résultat où ils doit aller.

      • [^] # Re: C'est vendredi ...

        Posté par  . Évalué à 3.

        Tu as raté le titre de son message je pense ;-)

        ⚓ À g'Auch TOUTE! http://afdgauch.online.fr

      • [^] # Re: C'est vendredi ...

        Posté par  (site web personnel) . Évalué à 3.

        Le week end arrive au bon moment dis donc …

        Non je pensais illustrer le fait que la dernière version, le framework à la mode c'est bien … et si cela
        a été développé c'est que cela répondait à un besoin.

        L'attrait de la nouveauté, plus le réflexe que l'on a de faire de la "veille techno" nous font perdre le fil du but initial.

        mais parfois pour des besoins basiques (une demi douzaine de page HTML …) rien ne vaut les choses simples qui existent déjà.

        De plus dans ce cas précis, j'aurais perdu moins de temps à les taper directement à la main, mais c'est quand même plus fun de le faire avec python et make …

        Tu sais, avec l'expérience et l'age, on évite les révolutions et de réinventer en fin de semaine … :)

        Bon Week end

        • [^] # Re: C'est vendredi ...

          Posté par  (site web personnel) . Évalué à 2.

          Je te conseille de lire cette page:
          http://wtbarnes.github.io/2016/08/28/cv-howto/

          1. créer un fichier structurée contenant les donnée à mettre en forme (en JSON, en YAML…)
          2. créer des templates Jinja2 vers différents formats (HTML, Markdown, etc.).
          3. injecter les données dans le template de ton choix avec Jinja2
          4. Profit.

          Avec secretary tu peux même utiliser un fichier au format odt pour générer ton CV…

          Note que je parle de CV, mais ça marche aussi pour générer des release notes ;)

          • [^] # Re: C'est vendredi ...

            Posté par  (site web personnel) . Évalué à 3.

            1- créer un fichier structurée contenant les donnée à mettre en forme (en JSON, en YAML…)

            Fait : mais avec un format texte simple \t separateur de champ \n comme séparateur de ligne …
            j'aurais du partir en YAML c'est plus lisible

            2- créer des templates Jinja2 vers différents formats (HTML, Markdown, etc.).

            Fait : J'ai pris pug/jade au lieu jinja2 c'est bon quand même ?

            3- injecter les données dans le template de ton choix avec Jinja2

            Fait : quelques scripts python pour générer du pug et make pour automatiser le tout

            par contre grâce à ton lien je viens de découvrir jinja2+pdfkit pour générer du PDF, merci beaucoup

            alors que j'ai du coder en php pour utiliser les données et faire une version PDF de mon CV

            Le résultat => Mon CV j'en profite pour diffuser mon CV … des fois que …

            L'ensemble est sur Framagit mais bon pour l'instant je suis l'unique utilisateur alors soyez indulgent …

          • [^] # Re: C'est vendredi ...

            Posté par  (site web personnel) . Évalué à 3. Dernière modification le 09 juillet 2019 à 15:36.

            C'est noël !!!

            je connaissais pas secretary mais cela m'intéresse fortement
            Cela fais longtemps que je cherche à générer de l'ODT de manière simple et avec les styles qui me conviennent

            A étudier (je pose sur la pile des trucs a étudier … )

            Merci beaucoup pour la 2eme fois … trop bien LinuxFr.org

          • [^] # Re: C'est vendredi ...

            Posté par  . Évalué à 2.

            Celui qui est ultra simple super souple et carrément en train de décoller c'est 11ty:
            https://www.11ty.io/

            • Il mange une pléthore de langages de markup,
            • JS donc s'intègre avec toute les technos du Web
            • Presqu'aussi rapide qu'Hugo
            • Tu crées ton arbo comme tu veux. Tu colles des fichiers JSON pour lier tes métadonnées à tes templates , tu écris ton contenu comme tu veux en markdown pour du blog, json pour des données, …
            • c'est parti

            Un tuto pour un blog
            https://www.filamentgroup.com/lab/build-a-blog/

            Et un exemple sous github avec du JSON
            https://github.com/medienlampe/aethel

            Et plein d'autres exemples sourcés:
            https://www.11ty.io/docs/sites/

  • # hexo

    Posté par  (site web personnel) . Évalué à 4.

    J'utilise hexo pour mon blog. Il est simple à utiliser pour qui veut un site rapidos.

    Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

  • # Jamstack ?

    Posté par  . Évalué à 4. Dernière modification le 05 juillet 2019 à 17:09.

    Apparemment le nouveau terme à la mode c'est "Jamstack" ?

    N.B. sur le Markdown comme je le disais je n'ai toujours pas compris en quoi taper du HTML pur comme <h1>truc</h1> ou <b>bidule</b> ou <ul><li>...</li></ul> était tellement plus compliqué que les 50 variantes de syntaxe wiki incompatibles… (et avec des libs comme Mathjax ou jqmath on peut même taper des équations de manière sympa en HTML…)

    • [^] # Re: Jamstack ?

      Posté par  . Évalué à 6.

      Pour mon usage, je vois au moins trois différences majeures qui justifient, l'une ou l'autre, l'usage de tels outils plutôt que du HTML pur:

      • écriture/modification de tableaux;
      • lisibilité des changements/diffs quand tu versionnes ton projet;
      • insertion telle quelle d'exemples/extraits de code-source, avec coloration syntaxique d'office.

      Les langages dits "légers" gagnent haut la main!

      • [^] # Re: Jamstack ?

        Posté par  . Évalué à 2. Dernière modification le 09 juillet 2019 à 09:00.

        je suis d'accord. Mes sites sont soit dynamiques (php), soit statiques (html simple), mais à la base j'utilise toujours un langage de balisage léger (txt2tags) mais néanmoins expressif, qui permet d'avoir une visualisation claire du contenu.

        Ensuite, avec un makefile qui va bien, c'est rapide et pratique de générer le contenu final.

        Il y a d'ailleurs possibilité de l'utiliser dans Jekyll et beaucoup d'autres logiciels : https://github.com/txt2tags/plugins

        « Le pouvoir des Tripodes dépendait de la résignation des hommes à l'esclavage. » -- John Christopher

    • [^] # Re: Jamstack ?

      Posté par  (site web personnel) . Évalué à 2.

      D'accord pour toutes ces syntaxes wiki incompatibles, parfois tu peu même pas faire un copier coller de l'un à l'autre …

      par contre taper du HML directement cela pique un peu quand même surtout quand le contenant est plus important que le contenu.

      C'est pour cela que j'ai bien pug/jade

         table(class="table")
            thead(class="thead-light")
                tr  
                   th Document / lien
                   th Description / Explications
             tbody
                tr  
                   td  
                     a(class="btn btn-default btn-info" href="/truc/machin.php" role="button") Infos

      Tu utilises l'indentation (comme en python) et c'est quand même plus lisible
      mais cet avis n'engage que moi bien entendu

    • [^] # Re: Jamstack ?

      Posté par  (site web personnel) . Évalué à 0.

      Je suis un peu d'accord sur l'utilisation du markdown et du html mais pas tout à fait !
      Pour moi, le markdown, c'est fait pour les informaticiens faignants (dont je fais parti) mais sinon, tu tu veux proposer un vrai produit fini, même pour les informaticiens (parce que tout le monde ne connaît pas le Html ou le markdown), c'est quand même mieux d'avoir un vrai éditeur où on peut faire toutes les mises en formes voulues. Surtout que maintenant avec les TinyMCE et consorts il ne manque pas d'éditeur.
      Du coup, je ne comprends pas tous ces projets qui utilisent le markdown (dont mon chouchou Joplin) alors qu'un éditeur permettrait à tout le monde de prendre l'outil sans se prendre la tête.

    • [^] # Re: Jamstack ?

      Posté par  (site web personnel) . Évalué à 10.

      Apparemment le nouveau terme à la mode c'est "Jamstack" ?

      Ça consiste à écrire 10mo de js qui génèrent 8mo d'html mis en forme via 9mo de CSS à partir de d'appels API² avec des payloads de 5mo de JSON pour afficher 144 caractères de contenus utiles.

      Le nom tas de confiture est particulièrement bien choisi!

      ²: à travers une API gateway pour atteindre 123 microservices hébergés sur un cluster Kubernetes avec des bases NoSQL derrière, mais le dos fin, c'est un autre débat !

      Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

      • [^] # Re: Jamstack ?

        Posté par  (site web personnel) . Évalué à 2.

        Excellent résumé !

        Après, au-delà du poids des données chargées par le client, je pense qu'une caractéristique fondamentale de la JAMSTACK est de faire répéter la construction du DOM à chaque client, ce qui d'une part rend obligatoire l'utilisation de Javascript/WASM côté client, et d'autre part fait que la puissance de calcul nécessaire pour afficher une page pour N personnes est bien plus grande que lorsque le DOM est généré côté serveur (chaque personne devant regénérer la page).

        C'est un gâchis énergétique à grande échelle ! On a besoin de prendre en compte des considérations d'écologie numérique dans nos projets informatiques, c'est à dire d'une part de gestion des ressources numériques (comme tu le suggérais), mais également la prise en compte de la complexité des opérations mises en oeuvre pour parvenir à nos fins.

        • [^] # Re: Jamstack ?

          Posté par  (site web personnel) . Évalué à 3.

          non pas du tout efface.

          Sur mon blog généré par Hugo, le morceau de js fait 600 octets. Le principe même d'un générateur est de directement générer du pur HTML qui est mis sur le serveur, pas de générer dynamiquement le contenu en js. Cela serait mauvais pour le référencement par exemple.

          "La première sécurité est la liberté"

    • [^] # Re: Jamstack ?

      Posté par  (site web personnel) . Évalué à 4. Dernière modification le 05 juillet 2019 à 23:11.

      Parce qu'il y aura toujours un moment où il faudra un peu plus que les balises de base du HTML. Du coup, on va commencer à utiliser des classes CSS pour spécialiser un peu certaines balises de base (comme distinguer liens internes et liens externes, ou mettre des paragraphes avec un fond orange pour des avertissements, comme ici ). Puis on se rend compte que pour avoir un beau rendu, il va falloir encapsuler tout ça d'un div supplémentaire, ou mettre le titre de la bulle en gras (donc ajouter un strong).

      Et comme on aura déjà fait plusieurs pages de HTML, il faut tout revérifier à la main, en oubliant bien sûr la moitié.

      Et imaginons qu'on veuille avoir un lien sur tous les titres ? Pourquoi devoir les faire à la main quand on pourrait les générer à la main ? Idem, si on avoir un bête index.

      • [^] # Re: Jamstack ?

        Posté par  . Évalué à 2.

        pre-postum: il est tard, j'ai la flemme de tout relire pour vérifier la cohérence une nième fois. Bref, attendez-vous à un contenu mal écrit et redondant.

        TL;DR:

        Et imaginons qu'on veuille avoir un lien sur tous les titres ? Pourquoi devoir les faire à la main quand on pourrait les générer à la main ? Idem, si on avoir un bête index.

        En shell POSIX standard, à ma connaissance, c'est impossible. Alors j'ai écris un outil en C++ "light" destiné à remplir la fonctionnalité manquante.
        L'outil est pas packagé, le code est publié ici pour la 1ère fois, à la base je voulais le faire sur le blog que je compte monter, mais le CSS m'écoeure alors je galère…

        Le code source suit (amis codeurs, ne regardez pas: c'est sale):

        #include <stdlib.h>
        #include <stdio.h>
        #include <errno.h>
        #include <string.h>
        #include <assert.h>
        #include <stdint.h>
        #include <ctype.h>
        
        #include <algorithm>
        
        #include <vector>
        
        /**
         * This program reads stdin and when consecutive lines have specific fields all
         * containing the same value, prints them replacing the newline character by
         * the 1st character in FIELD_SEP.
         * Fields are delimited by the FIELD_SEP environment variable. If not defined,
         * " \\t" is used instead (see isblank(3)).
         * Fields to use are defined by the environment variable FIELDS, which only
         * use unsigned decimal integers separated by commas, other characters makes the
         * value invalid.
         * If FIELDS is not defined or invalid, exits with an error.
         * Empty field indexes ("1,,3") are ignored (will resolve in "1,3").
         * Do not work if input is not in line mode.
         * Line separator is defined by ENTRY_SEP, or "\\n" if not defined.
         *
         * TODO:
         * * check that ENTRY_SEP works as expected;
         * * fix the fact input needs a "\\n" at end of last line for it to be merged;
         * * UTF-8 support (field separators);
         * * providing FIELDS variable as command-line option;
         * * -v/--version option;
         * * -h/--help    option;
         * * remove bloated STL containers;
         * * allow to customize the memory allocation scheme at runtime;
         * * allow to not print twice merged fields;
         * * allow to set verbosity on stderr;
         * * remove hard-coded limit of UINT16_MAX - 1 for fields start/stop positions;
         * * print as many lines as there where duplicates?
         *
         * Coding rules:
         * * const affect what is before it, so it must follow the type;
         **/
        
        class field_marker
        {
            uint16_t m_start = UINT16_MAX, m_end = UINT16_MAX;
        
        public:
            bool ignore( void ) const
            {
                return m_start == m_end && m_start == UINT16_MAX;
            }
        
            void define( uint16_t start, uint16_t end )
            {
                assert( end >= start && start != UINT8_MAX && end != UINT8_MAX );
                m_start = start; m_end = end;
            }
        
            uint16_t start( void ) const
            {
                assert( !ignore() );
                return m_start;
            }
        
            uint16_t end( void ) const
            {
                assert( !ignore() );
                return m_end;
            }
        };
        
        bool allocate_markers(
                char const * const FIELDS,
                std::vector<field_marker>& field_cache
        );
        
        int main( void )
        {
            char const * const DEFAULT_FIELD_SEP = " \t";
            char const * const DEFAULT_ENTRY_SEP = "\n";
        
            char const * SEP_START = getenv( "FIELD_SEP" );
            if( !SEP_START )
            {
                SEP_START = DEFAULT_FIELD_SEP;
            }
            char const * SEP_ENTRY = getenv( "ENTRY_SEP" );
            if( !SEP_ENTRY )
            {
                SEP_ENTRY = DEFAULT_ENTRY_SEP;
            }
        
            char const * const FIELDS = getenv( "FIELDS" );
            if( !FIELDS )
            {
                fputs( "ERROR: FIELDS is not defined\n", stderr );
                return EXIT_FAILURE;
            }
        
            if( strlen( FIELDS ) == 0 )
            {
                fputs( "ERROR: FIELDS is empty\n", stderr );
                return EXIT_FAILURE;
            }
        
            std::vector<field_marker> field_cache;
            if( allocate_markers( FIELDS, field_cache ) )
            {
                return EXIT_FAILURE;
            }
        
            size_t buf_sz = 2048;
            char* buf = nullptr;
        
            // I don't see how merging lines smaller than 16 bytes can be useful
            // also, not even enough mem for that would indicate bigger problems...
            while( !buf && buf_sz >= 32 )
            {
                buf_sz /= 2;
                buf = static_cast<char*>( malloc( buf_sz ) );
            }
        
            if( !buf )
            {
                fprintf( stderr, "ERROR: malloc %s(%d)\n", strerror( errno ), errno );
                return EXIT_FAILURE;
            }
        
            bool fetch = true;
            typedef std::vector<char> line_cache;
            line_cache last_line;
            char const * const SEP_END = SEP_START + strlen( SEP_START );
            while( !feof( stdin ) )
            {
                if( !fgets( buf, static_cast<int>( buf_sz ), stdin ) )
                {
                    free( buf );
                    buf = nullptr;
                    buf_sz = 0;
                    if( !feof( stdin ) )
                    {
                        fprintf( stderr, "ERROR: fgets %s(%d)\n", strerror( errno ), errno );
                        return EXIT_FAILURE;
                    }
                    break;
                }
        
                size_t str_sz = strlen( buf );
                if( str_sz == buf_sz - 1 && buf[str_sz] != '\n' && !feof( stdin ) )
                {
                    fprintf( stderr, "ERROR: buffer too small for some lines\n" );
                    return EXIT_FAILURE;
                }
        
                if( !fetch )
                {
                    char const* dst_ptr = buf;
                    for( size_t i = 0; i < field_cache.size(); ++i )
                    {
                        field_marker const& src = field_cache[i];
                        if( src.ignore() )
                        {
                            char const *sep = SEP_END;
                            while( sep == SEP_END )
                            {
                                ++dst_ptr;
                                sep = SEP_START;
                                for( ; sep != SEP_END && *dst_ptr && *dst_ptr != *sep; ++sep ){}
                            }
                            ++dst_ptr;
                            continue;
                        }
                        char const * src_ptr = last_line.data() + src.start();
                        size_t len = src.end() - src.start();
                        if( len > buf_sz - static_cast<size_t>( dst_ptr - buf ) )
                        {
                            fetch = true;
                            break;
                        }
        
                        if( 0 != memcmp( dst_ptr, src_ptr, len ) )
                        {
                            fetch = true;
                            break;
                        }
        
                        char last = dst_ptr[len];
                        char const * sep_ = SEP_START;
                        assert( sep_ != nullptr );
                        while( 0 != *sep_ && *sep_ != last && *SEP_ENTRY != last )
                        {
                            ++sep_;
                        }
                        if( 0 == *sep_ )
                        {
                            fetch = true;
                            break;
                        }
                        dst_ptr += len;
                        assert( dst_ptr >= buf );
                    }
        
                    fputc( fetch ? *SEP_ENTRY : * SEP_START, stdout );
                }
        
                last_line.assign( buf, buf + str_sz );
                if( last_line.back() == *SEP_ENTRY )
                {
                    last_line.back() = 0;
                }
        
                if( fetch )
                {
                    line_cache::iterator start     = last_line.begin();
                    line_cache::iterator cache_end = last_line.end();
                    size_t field_index = 0;
                    while( start != cache_end && field_index < field_cache.size() )
                    {
                        auto end = last_line.end();
                        if( last_line.back() == 0 )
                        {
                            --end;
                        }
                        line_cache::iterator it = std::find_first_of
                            (
                             start, end,
                             SEP_START, SEP_END
                            );
                        if( !field_cache[field_index].ignore() )
                        {
                            field_cache[field_index].define(
                                    static_cast<uint16_t>( start - last_line.begin() ),
                                    static_cast<uint16_t>( it - last_line.begin() )
                                    );
                        }
                        start = it + 1;
                        ++field_index;
                    }
                    fetch = false;
                }
                fputs( last_line.data(), stdout );
            }
            fputc( *SEP_ENTRY, stdout );
            return EXIT_SUCCESS;
        }
        
        bool allocate_markers(
                char const * const FIELDS,
                std::vector<field_marker>& field_cache
        )
        {
            field_cache.reserve( UINT8_MAX ); //255 fields should fit most cases
            size_t last_field = 0;
        
            char const * fields = FIELDS - 1;
            do
            {
                ++fields;
                if( isdigit( *fields ) )
                {
                    last_field = last_field * 10 + static_cast<size_t>( *fields - '0' );
                }
                else if( *fields == ',' || *fields == 0 )
                {
                    size_t max = std::max( field_cache.size(), last_field );
                    field_cache.resize( max );
                    field_cache[last_field - 1].define( 0, 0 );
                    last_field = 0;
                }
                else
                {
                    fputs( "ERROR: FIELDS contains illegal characters\n", stderr );
                    return true;
                }
            }while( *fields );
            field_cache.shrink_to_fit();
            return false;
        }

        C'est pas génial, je l'ai pas mis sur une forge, et pour la licence, bah… CC-0, BSD-2, WTFPL ou toute autre compatible, au choix. De toute façon ce code est tellement simple que je vois pas comment on pourrait y coller une licence en étant honnête…
        Les lecteurs y trouverons des opinions techniques douteuses. Sincèrement: elles sont miennes, je veux bien en discuter, mais je souhaite généralement prouver que C++ peut être aussi léger que le C, avec des avantages nets en terme de code. Ce qui explique mon manque d'appréciation pour, notamment, la STL. Mais bref. Ce code est sale de toute façon, je le sais.

        De base, mon idée était de faire un générateur de blog en shell, mais j'ai trouvé aucun outil permettant de merger des lignes en fonction d'une clé, d'où le code précédent.
        Bref, j'ai codé cette fonction, elle marche avec mes scripts, et permets bien plus que faire un vulgaire blog: vu qu'elle fait quasi rien, des gens lui trouverons peut-être d'autres usages. Grand bien leur en fasse.

        Mon idée était d'utiliser les outils UNIX classiques: sed, awk, cat… afin de passer un fichier source au travers d'une moulinette (par exemple /usr/bin/markdown du paquet discount.deb) et de concaténer ces fichiers avec un header, un footer, etc… mais, ça ne permets pas de générer des index, sommaires ou autres, alors j'ai sorti mon clang++.
        Du coup, cet outil est quasiment un pré-compilateur: si ma mémoire est bonne, je récupère une liste de noms de champs de la 1ère ligne, considère que ces champs seront présents à la suite, et les utilise pour générer un texte greppable.

        Une fois le texte greppable, je peux revenir au shell. La principale raison pour laquelle je n'ai rien publié est que… bah, je suis une merde en CSS, au point que je meurs d'envie de faire un <table><line><bla><bla/><line/><table/> dans l'idée… bref, le code est pas assez testé, il est sale, il est largement améliorable, et je le mentionne juste parce que, je me dis que p'tet, quelqu'un le trouveras utile…

        • [^] # Re: Jamstack ?

          Posté par  . Évalué à 2. Dernière modification le 09 juillet 2019 à 13:43.

          Et imaginons qu'on veuille avoir un lien sur tous les titres ? Pourquoi devoir les faire à la main quand on pourrait les générer à la main ? Idem, si on avoir un bête index.
          (...) [code C++ de 280 lignes...] (...)

          Pour ma part j'insère le code suivant dans mes pages pour générer automatiquement la numérotation / table des matières

          <div id="toc">
          <script> // Génère le sommaire et la numérotation automatiquement à partir des balises h1...h9
          window.onload = function () {
              var toc = "";
              var level = 0;
              var levels = [];
              document.body.innerHTML = document.body.innerHTML.replace( /<h([\d])>([^<]+)<\/h([\d])>/gi,
                  function (str, openLevel, titleText, closeLevel) {
                      if (openLevel != closeLevel) { return str; }
          
                      if (openLevel > level) {
                          toc += (new Array(openLevel - level + 1)).join("<ul>");
                      } else if (openLevel < level) {
                          toc += (new Array(level - openLevel + 1)).join("</ul>");
                          levels.splice(openLevel,9);
                      }
          
                      level = parseInt(openLevel);
                      levels[level-1] = isNaN(levels[level-1]) ? 1 : levels[level-1]+1;
                      var levelstr = levels.slice(0,level).join('.') + ') '
          
                      var anchor = titleText.replace(/ /g, "_");
                      toc += "<li><a href=\"#" + anchor + "\">" + levelstr + titleText + "</a></li>";
          
                      return "<h" + openLevel + "><a name=\"" + anchor + "\">" + levelstr + titleText + "</a></h" + closeLevel + ">";
                  }
              );
          
              if (level) { toc += (new Array(level + 1)).join("</ul>"); }
          
              document.getElementById("toc").innerHTML += toc;
          };
          </script>
          <br><p style="font-size: 300%;"><b>Sommaire</b></p><br>
          </div>
          • [^] # Re: Jamstack ?

            Posté par  (site web personnel) . Évalué à 2.

            Je parle d’un sommaire de l’ensemble des pages, pas seulement au sein d’une seule page ;)

    • [^] # Re: Jamstack ?

      Posté par  (site web personnel) . Évalué à 1.

      Un des intérêts de markdown ou assimilé, c'est que c'est plus limité que le html donc c'est plus facile à parser pour générer ensuite du html sans souci de sécu.

      (Ok y'a des composants tout fait parser/nettoyer le HTML, mais ça reste plus compliqué)

      En passant, utiliser markdown n'empêche pas de mettre un éditeur de texte riche.

      • [^] # Re: Jamstack ?

        Posté par  (site web personnel) . Évalué à 5.

        Pour avoir testé ça récemment, je pense l'exact contraire.

        Il est très facile de sécuriser du HTML : tu le parses et tu le réécris tel quel, en ignorant toutes les balises et attributs qui ne sont pas dans une liste blanche. Par exemple, pour la balise a tu autorises l'attribut href uniquement.
        Au contraire, sécuriser du Markdown avant conversion en HTML est plus complexe : si tu protèges violemment les « < » et « > » (en les remplaçant par les entités HTML), ça va casser les citations Markdown (par exemple).

        Quant à passer du Markdown… en fait c'est également un sacré bazar avec les retours à la ligne, les listes imbriquées, les changements de paragraphe… Quand tu as des enchaînements de paragraphes dans un élément de liste, elle-même dans un second paragraphe d'un élément de liste, tu te retrouves à jouer à l'aveuglette sur le nombre d'espaces qu'il faut mettre en début de ligne.

        J'ai été beaucoup plus convaincu par un éditeur WISYWIG comme CKEditor5 dont la représentation est un sous-ensemble limité de HTML.

  • # une autre alternative...

    Posté par  . Évalué à 2.

    Je me suis intéressé un peu à ça, il y a quelques mois, sans rien trouver qui satisfasse mon égocentrisme, mais une connaissance m'a parlé de Wswsh qui est un générateur de blog écrit en ksh pur.

    Il n'est pas référencé sur staticgen, et j'ai trouvé l'idée intéressante, parce qu'après tout, j'ai du mal a voir pourquoi ce genre d'outils ne seraient pas écrits en shell: une bonne partie du taf, c'est parser un format pour générer du html, qui a vocation a se faire concaténer avec un header, un footer, et d'autres éléments (index, sommaire, menu, etc). Transformer, par exemple, du markown en html se fait très bien avec, par exemple, discount et le reste, de la concaténation de fichier, rechercher un truc, ce genre de chose, le shell sait faire.
    Jusqu'ici, à part perl, je ne suis pas sûr d'ailleurs de connaître un language qui gère mieux ce genre de tâches spécifiques, mais bon, je connais pas go.

  • # Cmsimple_xh

    Posté par  . Évalué à 1.

    En voilà un qui génère du statique… je ne sais pas si c'est que l'auteur du journal recherche.

  • # Commentaires

    Posté par  (site web personnel) . Évalué à 5.

    La génération de sites statiques a l'air de gagner en puissance en effet, ce qui n'est pas pour me déplaire. Il faudra que je m'y mette moi-même. Pour accepter des commentaires sur un blog, il faut toutefois une partie dynamique. Ce qui a été à la mode pour cela, c'est Disqus, mais en ce qui me concerne, et sans doute nombre d'entre nous, sous-traiter ainsi les commentaires à un tel système centralisé est évidemment hors de question. Vous connaissez de bonne alternatives auto-hébergeables ?

    Sinon, il doit y avoir moyen de gérer des commentaires reçus par courrier électronique et déclenchant leur agrégation à la page concernée. Ce serait amusant à mettre en place.

    • [^] # Re: Commentaires

      Posté par  (site web personnel) . Évalué à 2.

      Voici un post qui en parlait il y a un petit moment :
      https://linuxfr.org/forums/programmationautre/posts/existe-t-il-un-systeme-de-commentaires-libre-a-la-disqus

      Il y est fait mention de plusieurs systèmes basés sur les mails.

    • [^] # Re: Commentaires

      Posté par  . Évalué à 2.

      Sinon tu poste sur Reddit ou dans la section « liens » de DLFP (c’est à moitié sérieux).

    • [^] # Re: Commentaires

      Posté par  (Mastodon) . Évalué à 0.

      Je pense que Commento pourrait répondre à ton besoin. J'y ai un peu contribué au début. C'est assez simple à mettre en place.

    • [^] # Re: Commentaires

      Posté par  (site web personnel) . Évalué à 2.

      Perso, je suis fan de l'approche Indieweb qui fait de la fédération sur le web à base de microformats (classes CSS standardisées pour la sémantique) et de Webmention/Websub.

      Webmention est un standard d'endpoint dynamique à définir dans toutes les pages HTML de son blog:

          <link rel="webmention" href="ENDPOINT">
      

      Les endpoints communiquent des ping HTTP qui contiennent seulement deux paramètres, la page source et la page ciblée. Le principe est que quand tu publies un lien vers un autre site sur le tien, ton site doit aller pinger l'autre pour le prévenir qu'on a parlé de lui. Ensuite, le endpoint en face va télécharger et parser ta page pour comprendre la nature de l'interaction : a-t-on juste placé un lien vers une autre page? sommes-nous en train de répondre à un article/commentaire? etc..
      WebSub (précédemment PubSubHubHub) fait un peu la même chose mais en mode pub/sub.

      Les deux protocoles sont très faciles à implémenter et sont en quelque sorte les ancêtres de ActivityPub/ActivityStreams (le W3C Social WG qui a accouché du standard AP est né des efforts autour de Indieweb/Salmon/Linked Data).

      Donc si ton blog et mon blog avait un endpoint Webmention, je pourrais commenter un article sur ton blog en écrivant directement sur le mien:

      <article class="h-entry">
          <aside>En réponse à <a class="u-in-reply-to" href="https://ton.blog/ton-article">Un article très intéressant</a></aside>
          <h1 class="p-name">Mon titre de commentaire</h1>
          <div class="e-content">
              <p>Ceci est mon commentaire.</p>
          </div>
      </article>
      

      Les informations-clé à retenir ici sont les classes suivantes: h-entry (une entrée sur mon site), u-in-reply-to (l'entrée est en réponse au href joint), p-name (le nom de l'entrée est le contenu inline de la balise), e-content (le contenu de l'entrée est le contenu en block de la balise).

      Quand je publie l'article, mon endpoint doit contacter l'endpoint déclaré dans la page https://ton.blog/ton-article pour le prévenir que j'ai publié un contenu te concernant.

      Ensuite, il suffit d'intégrer un appel à l'API de ton endpoint dans ton script de build pour importer les nouveaux commentaires directement dans le dossier de contenu (ou dans le dossier data) de ton site statique.

      Il existe une installation clé-en-main de Webmention: webmention.io. Le code est libre même si ce n'est pas vraiment un projet communautaire pensé pour l'autohébergement.. mais il est très très simple de réimplémenter un tel endpoint. Et c'est un bon outil de transition pour comprendre comment intégrer de telles technologies dans sa pipeline.

      En conclusion, ce qu'on veut éviter c'est que les requêtes HTTP sur notre site servent de porte d'entrée directe sur le serveur web / la base de données. Recourir à un endpoint dynamique externe (dans un chroot/vm/container séparé) juste avant de compiler le site statique permet d'éviter certains problèmes de sécurité/performance au niveau du serveur web, tout en évitant l'approche JAMSTACK qui comme l'a rappelé devnewton fait porter sur le client toute la charge de construire la page.

      PS: Rien n'empêche, par dessus un tel setup, de rajouter de la modération ainsi qu'une boîte mail pour envoyer des commentaires sans passer par le web, mais mon commentaire était déjà bien assez long :)

  • # zim wiki et lektor

    Posté par  . Évalué à 3.

    Perso j'utilise zim pour lequel j'ai un petit script (très spécifique) qui me génère un site statique. J'avoue que j'aime bien le fait d'avoir une GUI pour éditer le site, ça me fait gagner du temps (dans ce cas notamment, j'ai pas mal de fichiers joint à chaque page, ce que zim gère très bien). Zim intègre très bien git pour versionner.

    Ceci dit je voulais aussi tester lektor qui offre plus de fonctionnalité, mais je ne l'ai pas encore fait !

  • # Zola

    Posté par  (site web personnel) . Évalué à 3.

    Zola (précédemment Gutenberg) est un petit générateur de site statique écrit en Rust. Il embarque des fonctionnalités avancées (SASS, traductions, traitement d'images) sans chercher à devenir une usine à gaz universelle comme Hugo.

    Par rapport à hugo, deux choix techniques marquant :
    - réimplémenter un moteur de templating basé sur Jinja2 (tera) au lieu d'utiliser l'horreur absolue que sont les templates go (je parle pas que de la syntaxe)
    - éviter la surcomplexité de Hugo pour faire des sites simples, notamment à cause des layout lookup rules

    Zola est en évolution perpétuelle et on peut pas dire que ça soit poli sur les angles ; il reste plein de choses à fignoler. Mais ça remplit mes besoins au quotidien pour le moment, c'est super rapide, et honnêtement, je n'ai jamais vu un code source de générateur de site statique aussi lisible (et du coup facile à bidouiller).

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.