Configuration

Placez les options du plugin et les réglages Vite optionnels dans sitelo.config.js. Aucun vite.config.js n’est requis.

export default {
  site: 'https://example.com',
  rss: {
    site: 'https://example.com',
    title: 'Mon blog',
    description: 'Derniers articles',
    routePrefix: '/blog',
  },
  vite: {
    publicDir: 'static',
    build: {
      emptyOutDir: true,
      outDir: 'public',
    },
    server: {
      port: 8888,
    },
  },
}

Options du plugin

Barre d’outils de développement

Pendant que sitelo (dev) tourne, une petite barre en bas de chaque page affiche le fichier de la page, ses paramètres et le nombre d’îlots serveur présents. Le bouton viewport fait alterner les aperçus Desktop / Tablet / Mobile (dans une iframe, pour que les media queries correspondent), et Copy produit un bloc de débogage à joindre aux tickets. Elle n’apparaît jamais dans la sortie de sitelo build.

// sitelo.config.js
export default {
  devToolbar: false, // masquer pour tout le monde sur ce projet
}

Options Vite

Tout ce qui se trouve sous vite est fusionné dans la configuration de Vite. Les options de la CLI (par exemple --port) priment sur les deux.

Si vous avez déjà un vite.config.js

Toujours pris en charge — soit des options Vite uniquement, soit un contrôle complet du plugin :

// Options Vite uniquement ; sitelo injecte toujours le plugin
export default {
  publicDir: 'static',
  server: { port: 8888 },
}
// Enregistrer le plugin soi-même
import htmlPages from 'sitelo'

export default {
  plugins: [htmlPages({
    site: 'https://example.com',
  })],
}

Si le plugin est déjà dans votre configuration Vite, mettez-y les options du plugin — et pas aussi comme options de plugin dans sitelo.config.js (sitelo renverra une erreur).

Sitemap et RSS

Définissez site pour émettre dist/sitemap.xml.

RSS :

export default {
  rss: {
    site: 'https://example.com',
    title: 'Mon blog',
    description: 'Derniers articles',
    routePrefix: '/blog',
  },
}

Produit dist/rss.xml avec une entrée pour chaque page sous routePrefix.

Vérification des liens

Les <script src> et href de feuilles de style cassés font déjà échouer le build (voir missingAssets). linkCheck couvre l’autre moitié : les liens internes <a href> qui pointent vers une page inexistante.

export default {
  linkCheck: true,   // 'warn' (par défaut), 'error', ou un objet d’options
}

Après sitelo build, chaque lien interne de la sortie est résolu et tout ce qui n’a pas de page derrière lui est signalé, regroupé par page où il apparaît :

[sitelo] 3 liens internes cassés

  index.html
    ../escape           -> sort du répertoire de sortie
    /abuot              -> page inexistante
    /blog/missing-post  -> page inexistante

Comment les liens sont résolus

La vérification s’exécute sur le site émis, pas sur la table des routes : elle tient donc compte de cleanUrls, des groupes de routes, de mapOutputPath, des fichiers copiés depuis public/ et des pages produites par des routes dynamiques. Elle s’exécute aussi après l’optimisation des images et Pagefind, si bien qu’elle voit exactement ce qui est livré. Un lien est valide quand un vrai fichier y répond, essayé dans l’ordre qu’emploierait un hébergeur statique :

Les liens relatifs (../about) se résolvent par rapport à la page qui les contient, et ceux qui sortent du répertoire de sortie sont signalés. Les chaînes de requête sont ignorées lors de la résolution — /about?utm=x vérifie /about.

Les liens externes ne sont jamais récupérés. https://, les liens relatifs au protocole //cdn.example.com, mailto:, tel: et les autres schémas sont entièrement ignorés.

Options

OptionPar défautDescription
mode'warn''warn' journalise et continue ; 'error' fait échouer le build — utile en CI
exclude[]Globs ou expressions régulières de href à ignorer
checkFragmentsfalseVérifie aussi que les cibles #fragment existent dans la page liée
export default {
  linkCheck: {
    mode: 'error',                    // fait échouer le build sur un lien mort
    checkFragments: true,             // vérifie aussi les cibles #fragment
    exclude: ['/api/**', /^\/legacy\//],
  },
}

checkFragments est désactivé par défaut car les identifiants ajoutés par du JavaScript client ne figurent pas dans le HTML construit et seraient signalés comme manquants. Les attributs id comme les anciens name d’ancre comptent comme cibles de fragment.

Sites servis depuis une base

Si votre site est déployé sous une base (un site de projet GitHub Pages, par exemple), tout lien relatif à la racine qui ne porte pas cette base est signalé. Un /about sur un site servi depuis /repo/ envoie le navigateur à la racine de l’hôte, pas dans votre site — le résoudre malgré tout contre la sortie masquerait précisément l’erreur qu’il vaut la peine d’attraper. Utilisez exclude quand c’est délibéré.

Audits Lighthouse

sitelo lighthouse audite le build final avec Lighthouse. C’est une dépendance pair optionnelle :

npm install -D lighthouse

sitelo sert dist/ comme le fait sitelo preview, lance un Chrome headless sur chaque page et affiche les scores :

[sitelo] lighthouse mobile - 3 pages

  page           perf  a11y  best   seo
  /                98   100   100   100
  /docs            95   100   100   100
  /docs/routing    97   100   100   100

[sitelo] lighthouse audited 3 pages in 31.4s

Chaque page est auditée à l’URL que le site utilise réellement — /docs, jamais dist/docs.html —, donc cleanUrls, les groupes de routes et un base sont pris en compte. Avec des seuils, le rapport devient un contrôle : tout score en dessous fait échouer la commande.

export default {
  lighthouse: {
    exclude: ['404.html'],   // la page 404 mérite rarement un audit
    thresholds: {
      performance: 90,
      accessibility: 100,
      'best-practices': 95,
      seo: 100,
    },
  },
}

Les scores s’écrivent comme Lighthouse les affiche (0100) ; ses fractions de 0 à 1 fonctionnent aussi. Utilisez mode: 'warn' pour journaliser sans échouer.

export default {
  lighthouse: {
    formFactor: 'desktop',   // préréglage desktop de Lighthouse
    runs: 3,                 // trois passages par page, score médian
    output: true,            // rapports complets dans .sitelo/lighthouse/
    onBuild: true,           // audite aussi à la fin de sitelo build
    flags: { throttlingMethod: 'provided' },
  },
}

Lighthouse pilote un vrai Chrome : installez-en un là où l’audit tourne, ou faites pointer CHROME_PATH vers un binaire. Les scores de performance varient d’un passage à l’autre : utilisez runs: 3 avant d’y attacher un seuil.

Recherche Pagefind

Recherche statique optionnelle propulsée par Pagefind, une dépendance peer optionnelle. Installez-la quand vous voulez la recherche, puis activez l’indexation, marquez le contenu, montez l’interface et lancez sitelo build.

npm install -D pagefind

1. Activer l’indexation

Mettez pagefind: true. Après sitelo build vous obtenez dist/pagefind/, et par défaut une copie dans public/pagefind/ pour que le prochain sitelo (dev) ou sitelo preview puisse servir /pagefind/ sans reconstruire.

export default {
  pagefind: true,
}

2. Marquer le contenu et ajouter un point de montage

Placez data-pagefind-body sur le contenu principal pour que la navigation et le pied de page ne soient pas indexés. Laissez un élément vide pour l’interface de recherche :

import {
  html, head, title, link, script, body, header, a, div, main, h1, p,
} from 'javascript-to-html'

export default () =>
  html({ lang: 'fr' },
    head(
      title('Mon site'),
      link({ rel: 'stylesheet', href: '/styles.css' }),
      script({ type: 'module', src: '/main.js' }),
    ),
    body(
      header(
        a({ href: '/' }, 'Accueil'),
        div({ id: 'search' }),
      ),
      main({ 'data-pagefind-body': '' },
        h1('Bonjour'),
        p('Seule cette zone est indexée.'),
      ),
    ),
  )

3. Monter l’interface Pagefind

Chargez /pagefind/pagefind-ui.js et pagefind-ui.css depuis votre script client (seulement après qu’un build a produit l’index) :

async function initSearch() {
  const mount = document.querySelector('#search')
  if (!mount) return

  // L’index n’existe qu’après `sitelo build` (synchronisé vers public/pagefind par défaut)
  try {
    const probe = await fetch('/pagefind/pagefind-ui.js', { method: 'HEAD' })
    if (!probe.ok) return
  } catch {
    return
  }

  const style = document.createElement('link')
  style.rel = 'stylesheet'
  style.href = '/pagefind/pagefind-ui.css'
  document.head.appendChild(style)

  await new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.src = '/pagefind/pagefind-ui.js'
    script.onload = resolve
    script.onerror = reject
    document.body.appendChild(script)
  })

  new window.PagefindUI({
    element: '#search',
    showImages: false,
  })
}

initSearch()

4. Construire et ignorer le bundle synchronisé

sitelo build
# ensuite : sitelo preview — ou sitelo (dev) avec public/pagefind
public/pagefind/

Les options avancées (syncPublic, glob, langue, sélecteurs, …) se placent dans un objet : pagefind: { syncPublic: false, glob: '**/*.html' }. Toutes les options de l’interface : pagefind.app.

404

Créez src/404.ht.js pour obtenir dist/404.html. Sinon, une page par défaut est générée.