← Blog

notre site et notre app étaient deux produits. ils n'en font plus qu'un.

On savait où on était sur notre produit en regardant le bas de la page. Le site marketing avait un footer à cinq colonnes ; le dashboard, une seule rangée de liens. Navbars différentes, espacements différents, polices différentes par endroits. La divergence de deux équipes, produite par une seule personne, parce que c'étaient deux bases de code.

C'est désormais une seule application Aurelia. La home, le catalogue, le blog, cette base de connaissances et le dashboard sont des routes de la même app, partageant navbar, footer, tokens et composants.

la partie vraiment difficile

Une single-page app est invisible pour tout ce qui n'exécute pas JavaScript. Y déplacer un site marketing est un bon moyen de perdre tous ses classements.

Donc le build prerend. Il démarre la vraie application dans un DOM headless, navigue vers chaque route publique, attend qu'elle se pose, et écrit le document résultant. Un crawler reçoit du HTML complet — titre, description, canonical, données structurées — produit par le même code que le navigateur exécute. Il n'y a pas de seconde implémentation des pages qui pourrait dériver.

Le prerenderer refuse aussi d'expédier de mauvaises pages. Un titre manquant, une description sous quarante caractères, ou autre chose qu'exactement un <h1> fait échouer le build. Ce contrôle a attrapé quatre pages légales rendant deux titres chacune, dans la minute qui a suivi son écriture.

deux bugs qu'on n'aurait pas trouvés en raisonnant

L'URL canonique redirigeait. Écrire les pages en models/index.html faisait faire à nginx un 301 de /models vers /models/ — chaque URL de notre sitemap rebondissait avant de répondre. Les pages sont désormais écrites en models.html et servies par try_files $uri $uri.html, exactement à l'adresse que nous annonçons.

Le fallback servait la mauvaise page. Les routes purement clientes retombaient sur index.html, qui après prerendering est la home. Donc /login montrait le hero marketing le temps que le routeur rattrape, et un crawler atteignant une URL privée aurait indexé la home dessous. Le fallback est désormais une coquille neutre.

Les deux ont été trouvés en requêtant les pages et en lisant ce qui revenait. Aucun ne serait apparu dans un build vert.

ce que vous y gagnez

Un seul design, honnêtement. Le sélecteur de thème est parti dans le footer, là où vit une préférence ; le sélecteur de langue a pris sa place dans la barre. Chaque table de données se replie en cartes lisibles sur téléphone au lieu de défiler de côté. Et chaque page — marketing ou produit — hérite d'un correctif à l'instant où on le fait, parce qu'il n'y a qu'un composant à corriger.

Comment tout le système fonctionne · Base de connaissances · Lire notre code

Read next

a GPU died mid-sentence. the sentence finished.

Consumer hardware disappears without notice — someone sits down at their PC, a breaker trips, Wi-Fi drops. Our streams now survive that: another machine picks the answer up mid-word, and the dead segment is billed to nobody.

one model, every card: how a 27b runs on 8 gb

Qwen3.8 27B ships in five builds, from Q5_K_M on a 24 GB card down to IQ2_XXS on 8 GB. Why we split models from builds, what quantization actually costs, and how a quantized KV cache doubled our context overnight.

Model catalogue · Knowledge base · Run a GPU