← Retour au site Chargement…

notabene

Publier un site public

Guide

Généré le 1 août 2026

Publier un site public

Publier un site public

L’app de revue est un outil local de dev — mais les docs qu’elle rend méritent souvent un foyer public. build --public produit un artefact purement statique, en lecture seule fait pour ça :

notabene build --public --site https://you.github.io --base /your-repo --out ./_site

Ce site même est construit ainsi — les docs de notabene, rendues et publiées par notabene.

Ce qui reste, ce qui part

  • Tout l’interactif disparaît — structurellement. Pas d’UI de commentaires, pas d’invite d’identité, pas de /comments / /review / /journal, pas d’API, et rien du store .notabene. Les routes ne sont pas verrouillées ; elles ne sont pas construites.
  • Ce qui reste est l’expérience de lecture complète : nav, recherche, Mermaid + lightbox d’images, mode sombre, i18n (pages par locale, sélecteur, hreflang), routes print/PDF, 404.
  • Né lisible par les agents. Chaque page embarque un double Markdown à <page>/index.md (annoncé via <link rel="alternate" type="text/markdown">), le site embarque /llms.txt (un index machine de chaque page, par locale) et /llms-full.txt (la doc entière en un seul document Markdown dans l’ordre de lecture), plus robots.txt, un sitemap, des URL canoniques, des meta OpenGraph/Twitter et du JSON-LD. Essayez ici : /llms.txt.

Recherche plein texte (optionnelle)

Le site public hérite de la recherche intégrée telle quelle. Installez Pagefind en dépendance de dev et build --public la promeut en recherche plein texte statique :

npm i -D pagefind

Le build indexe l’artefact final : stemming par langue (un visiteur de /fr/ cherche dans un index français, avec les formes fléchies du français), extraits surlignés sous chaque résultat, et un poids réseau qui reste faible quand la doc grandit — le navigateur ne télécharge que les morceaux d’index utiles à la requête. Zéro configuration, même champ de recherche. Non installé → le site public garde la recherche JSON intégrée. Et le contenu privé ne peut pas fuiter dans l’index : l’indexation s’exécute sur l’artefact, où les pages hors périmètre n’existent pas.

La même dépendance améliore aussi l’app de revue notabene dev : son index est construit en direct depuis vos sources Markdown et rafraîchi quand elles changent — aucun build en jeu. Deux différences propres au dev : le site de dev (donc son index) inclut vos pages privées, et les résultats profonds par section (ancres de titres) restent réservés au public.

Où aller ensuite

La boucle de dev est intacte : notabene dev et le simple notabene build se comportent exactement comme avant — la publication est opt-in, par build.

Configurer publish

Configurer publish

Tout vit sous une seule clé de config optionnelle — les flags CLI (--site/--base) la surchargent, et --out copie l’artefact vers un chemin stable (il refuse d’écraser quoi que ce soit qu’il n’a pas généré) :

// notabene.config.mjs
export default {
  // …
  publish: {
    // ORIGINE déployée. Grave des URL absolues dans canonical, og:url, JSON-LD,
    // hreflang, llms.txt, le sitemap et la ligne Sitemap de robots.txt.
    // OPTIONNELLE — omettez-la pour garder le domaine hors du repo (voir
    // « Domaine géré côté serveur »). Origine seule, sans chemin : un sous-chemin va dans `base`.
    site: "https://you.github.io",

    // Sous-chemin quand le site est servi sous un préfixe (site de projet
    // GitHub Pages → "/<repo>"). Préfixe chaque lien et URL d'asset — contrairement
    // au domaine, un sous-chemin affecte toujours le rendu, il ne peut pas être côté serveur.
    base: "/your-repo",

    // Sous-arborescences à garder hors des builds publics — globs comparés à
    // `<space key>/<page id>` (indépendant de la locale : un motif masque chaque
    // traduction d'une page). `*` = un segment de chemin, `**` = toute profondeur.
    exclude: ["docs/internal/**", "docs/*/draft"],
  },
};

Trois configurations typiques

publish: { site: "https://you.github.io", base: "/my-repo" }  // GitHub Pages, site de projet
publish: { site: "https://docs.example.com" }                 // domaine personnalisé à la racine
publish: { exclude: ["docs/internal/**"] }                    // domaine gardé hors du repo

La troisième est le mode agnostique à l’origine — le même artefact derrière n’importe quel domaine.

Métadonnées par page

Deux clés de frontmatter alimentent les surfaces publiques (voir la référence complète du frontmatter) :

---
description: One-line summary — becomes the meta description / OpenGraph.
publish: false   # cette page ne part jamais dans un build public
---

Exclure du contenu du build a sa propre page : garder du contenu privé.

Garder du contenu privé

Garder du contenu privé

Trois niveaux, du plus grossier au plus fin — chacun vit là où vit ce qu’il délimite.

Un espace entier — marquez l’entrée roots[] :

roots: [
  { key: "docs",  label: "Docs",  path: "docs" },
  { key: "notes", label: "Notes", path: "notes", publish: false },  // l'espace entier reste privé
],

Une sous-arborescence — des globs publish.exclude sur <space key>/<page id> (c’est le chemin d’URL de la page sans préfixe de locale, donc un seul motif masque toutes les traductions) :

publish: { exclude: ["docs/internal/**", "docs/*/draft"] },

Une seule page — son propre frontmatter :

---
publish: false   # cette page n'apparaît jamais dans un build public
---

Un lien de navigation — pas du contenu, mais la même idée : une entrée nav marquée publish: false reste en dev et n’atteint jamais l’artefact (un dashboard, un wiki interne) :

nav: { header: [{ label: "Dashboard ops", href: "https://ops.internal", publish: false }] },

La garantie

Le contenu privé n’est pas caché, il n’est pas construit — pas de route (l’URL renvoie un 404), pas d’entrée dans la sidebar, pas de résultat de recherche, pas de ligne llms.txt, pas de double .md, pas d’entrée de sitemap, pas d’inclusion print/PDF, et le nom et le chemin de l’espace n’atteignent jamais le HTML public.

notabene dev et les builds normaux montrent toujours tout — vous passez en revue vos docs privées exactement comme le reste. La notion de publish n’existe que pour les builds publics.

Une réserve : les liens vers du contenu privé

Si une page publique pointe vers une page privée, ce lien renvoie un 404 dans l’artefact public — le build ne le réécrit pas et n’émet aucun avertissement. notabene lint attrape exactement cela : lancez-le après build --public et chaque lien d’une page publique vers du contenu exclu par le scoping est signalé (la vérité des routes publique ne contient tout simplement pas ces pages — voir la référence CLI).

Domaine géré côté serveur

Domaine géré côté serveur ? Omettez site

Quand le domaine public est l’affaire du serveur — un vhost ou un reverse proxy en frontal, plusieurs miroirs, ou un domaine pas encore choisi — ne définissez simplement pas site (et ne passez pas de --site). L’artefact devient agnostique de l’origine : pas une seule URL absolue n’y est embarquée, la même sortie fonctionne donc derrière n’importe quel domaine, et changer de domaine n’exige jamais de rebuild.

Ce qui change

SurfaceAvec siteSans
llms.txt / llms-full.txt / doubles .mdURL absolueschemins relatifs à la racine (les agents les résolvent contre l’origine depuis laquelle ils les ont récupérés)
alternates hreflangabsoluespar chemins
canonical, og:url, JSON-LDémisnon émis — ils n’ont de sens qu’avec une origine
sitemap + ligne Sitemap: de robots.txtémisnon émis — les spécifications exigent des URL absolues

Ce que cela coûte, concrètement

La visibilité dans les moteurs de recherche — rien d’autre. Sans sitemap, URL canoniques ni hreflang valide, les crawlers ne découvrent les pages qu’en suivant les liens, rien ne consolide les doublons si la doc répond sur plusieurs domaines, et les pages multilingues n’envoient aucun signal de langue aux moteurs de recherche. Les aperçus de liens sociaux gardent leur titre/description mais perdent la carte d’URL. Les lecteurs humains et les agents IA ne perdent rien — chaque page, double et fichier llms fonctionne à l’identique.

Règle simple : hébergement interne, miroir, ou domaine pas encore arrêté → omettez site ; un site public dont le référencement compte → définissez site.

base reste indépendant

Définissez base dès que le site vit sous un sous-chemin, avec ou sans domaine — un sous-chemin affecte toujours les liens rendus, il ne peut donc pas être laissé au serveur.

Déployer via GitHub Pages

Déployer via GitHub Pages

Déployez sur n’importe quel hébergement statique. Pour GitHub Pages : Settings → Pages → Source = GitHub Actions, puis :

# .github/workflows/docs.yml
name: docs
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
concurrency:
  group: pages
  cancel-in-progress: false
jobs:
  publish:
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      - run: npx notabene build --public
          --site https://${{ github.repository_owner }}.github.io
          --base /${{ github.event.repository.name }}
          --out ./_site
      - uses: actions/upload-pages-artifact@v3
        with: { path: ./_site }
      - id: deployment
        uses: actions/deploy-pages@v4

Notes :

  • Avec publish: { site, base } défini dans votre config, les flags --site/--base peuvent être omis entièrement.
  • Hébergement sur un domaine personnalisé ou un site racine utilisateur/organisation ? Retirez --base et pointez --site vers votre domaine.
  • L’artefact embarque un .nojekyll, donc les assets _astro/ survivent même à l’hébergement classique par branche gh-pages.
  • npm i -D pagefind dans votre repo et ce même workflow embarque aussi la recherche plein textenpm ci l’installe, le build la détecte. Rien à changer ici.
  • Ce site de documentation est déployé par exactement ce workflow — voyez-le dans le repo.