ITSkillsCenter
Développement Web

Mode RPC Hono avec SvelteKit dans un monorepo : guide 2026

13 min de lecture

📍 Article principal : Hono framework TypeScript en production 2026

Introduction

Une équipe de quatre développeurs à Abidjan maintenait deux dépôts Git : le front SvelteKit et l’API Hono. Chaque modification d’un endpoint déclenchait une cascade fastidieuse — modifier le serveur, attendre la synchronisation OpenAPI, mettre à jour le client TypeScript, tester. Trois fois par mois, un mismatch de type passait en production. Migration vers un monorepo pnpm workspace avec Hono RPC : la même PR contient désormais le changement serveur, les types client, et les composants SvelteKit qui les consomment. Les mismatches ont disparu, et la vélocité de l’équipe a augmenté de 30 % mesurée sur trois sprints. Ce tutoriel décrit la structure de monorepo qui rend ce gain accessible, le mécanisme RPC sous-jacent, le partage de schémas Zod entre client et serveur, le déploiement séparé du front et de l’API, et les pièges spécifiques aux projets ouest-africains avec connectivité limitée.

Le pattern présenté n’est pas réservé aux grosses équipes. Pour un freelance qui livre des projets clients à Dakar ou Cotonou, le monorepo permet de capitaliser le code commun (validation, types métier, helpers) entre projets. Pour une startup qui démarre, c’est la structure qui supporte la croissance de un à dix développeurs sans réorganisation majeure.

Prérequis

  • Node 22 LTS et pnpm 9+ installés
  • Connaissance de base SvelteKit 2 et Hono
  • Compte GitHub pour le dépôt (privé ou public)
  • Niveau : intermédiaire — Temps : 2 heures

Étape 1 — Structure du monorepo

L’arborescence cible est minimaliste mais évolutive. Trois dossiers principaux : apps/web pour le front SvelteKit, apps/api pour le serveur Hono, et packages/shared pour le code commun (schémas Zod, types métier, helpers purs). Cette séparation est intentionnelle. Les apps consomment des packages, jamais l’inverse. Aucune dépendance circulaire ne peut se créer.

mon-projet/
├── apps/
│   ├── web/                  # SvelteKit 2
│   │   ├── src/
│   │   ├── package.json
│   │   └── svelte.config.js
│   └── api/                  # Hono
│       ├── src/
│       └── package.json
├── packages/
│   └── shared/               # Zod schemas, types métier
│       ├── src/
│       └── package.json
├── pnpm-workspace.yaml
├── package.json
└── tsconfig.base.json

Le fichier pnpm-workspace.yaml à la racine déclare les sous-projets : packages: ['apps/*', 'packages/*']. Le tsconfig.base.json centralise les options TypeScript communes (target ES2022, strict, paths). Chaque sous-projet étend cette base via "extends": "../../tsconfig.base.json".

Étape 2 — Le package shared

Le rôle du package shared est crucial : il contient tout ce qui doit être identique entre client et serveur. Schémas Zod de validation, types TypeScript métier, constantes (codes pays UEMOA, taux de TVA par pays, formats de téléphone), helpers purs (calculs de prix, formatage de dates en français). Ce qui ne va PAS dans shared : le code lié à un runtime (DOM, fs, fetch spécifique), les secrets, les variables d’environnement.

Les conventions d’export sont strictes. Chaque fichier exporte explicitement ce qu’il publie via un index.ts qui réexporte. Pas d’imports profonds depuis les apps consommatrices : on importe toujours depuis @itskills/shared, jamais @itskills/shared/dist/internal/.... Cette discipline garantit qu’on peut refactorer la structure interne du package sans casser les apps.

Pour le build, deux options. La plus simple : pas de build, on utilise le package en mode source (main: "./src/index.ts"), TypeScript résout les imports via les paths du monorepo. Cette approche fonctionne en dev et au build des apps qui font leur propre transpilation. Plus propre mais plus complexe : compiler vers dist/ avec tsc et publier ce dossier. Pour 95 % des projets, le mode source suffit.

Étape 3 — Configurer Hono RPC

Le mode RPC de Hono fonctionne en exportant le type du routeur côté serveur, et en l’important côté client. Le client devient automatiquement type-safe : tous les endpoints, leurs paramètres, leurs body schemas, et leurs réponses sont connus du compilateur TypeScript. Toute modification serveur invalide instantanément les usages client incorrects.

Côté apps/api, on structure les routes pour que la chaîne fluide soit conservée jusqu’à l’export. Si on appelle app.get(...) dans une fonction séparée et qu’on perd la chaîne, le typage RPC se dégrade en any. La règle pratique : déclarer toutes les routes dans le fichier d’export, ou regrouper par domaine en sous-routers chaînés intentionnellement.

Côté apps/web, on importe le type via import type { AppType } from '@itskills/api'. Cette syntaxe import type garantit que le client n’embarque AUCUN code serveur dans son bundle — seuls les types sont consommés à la compilation, le bundle final ne contient que la lib hono/client qui pèse moins de 3 Ko gzippés.

Étape 4 — Usage typique côté SvelteKit

// apps/web/src/lib/api.ts
import { hc } from 'hono/client';
import type { AppType } from '@itskills/api';

export function createClient(fetch?: typeof globalThis.fetch) {
  return hc<AppType>(import.meta.env.VITE_API_URL, { fetch });
}

// apps/web/src/routes/clients/+page.server.ts
import { createClient } from '$lib/api';

export const load = async ({ fetch, cookies }) => {
  const api = createClient(fetch);
  const token = cookies.get('session');
  const r = await api.api.clients.$get({}, {
    headers: { Authorization: 'Bearer ' + token }
  });
  if (!r.ok) throw error(r.status);
  return { clients: await r.json() };
};

L’IDE complète api.api.clients.$get sans aucune configuration. Si le serveur retire l’endpoint /api/clients, la compilation du front échoue immédiatement, on voit l’erreur avant le merge — pas en production le lundi matin.

Étape 5 — Schémas Zod partagés

Le pattern le plus puissant du monorepo : un schéma Zod défini dans shared est utilisé côté serveur pour valider les inputs et côté client pour valider les formulaires en temps réel. Une seule source de vérité, jamais de divergence possible.

Côté packages/shared, on regroupe les schémas par domaine : shared/src/schemas/clients.ts, shared/src/schemas/factures.ts, shared/src/schemas/paiements.ts. Chaque fichier exporte le schéma et le type inféré. Côté serveur, on l’utilise dans zValidator('json', clientSchema). Côté SvelteKit, on l’utilise dans la validation côté navigateur avant soumission, et dans Superforms pour le binding bidirectionnel.

Quand un champ change (par exemple, le format du téléphone évolue pour accepter le Niger qui passe de 8 à 9 chiffres), une seule modification dans shared propage automatiquement la nouvelle règle au backend ET au frontend. Aucun risque que l’un valide alors que l’autre rejette.

Étape 6 — Workflow de développement

Pour développer en local, on lance les deux apps en parallèle. pnpm permet d’exécuter une commande dans tous les workspaces matchant un filtre :

# package.json racine
"scripts": {
  "dev": "pnpm --parallel --filter './apps/*' dev",
  "build": "pnpm --filter './apps/*' build",
  "test": "pnpm --recursive test"
}

Concrètement, pnpm dev démarre le front SvelteKit sur le port 5173 et l’API Hono sur le port 3000 simultanément. Les deux processus partagent la console, ce qui facilite le debug. Le hot reload fonctionne dans les deux directions : modifier un schéma Zod dans shared recompile à la fois le client TypeScript du front et le validateur du back en moins d’une seconde.

Pour les tests, la même approche. pnpm test lance les tests Vitest de tous les workspaces. Les tests unitaires du package shared tournent en premier, garantissant que les bases sont saines avant de tester les apps qui en dépendent.

Étape 7 — Déploiement séparé front et API

Le monorepo n’impose pas un déploiement unifié. Au contraire, chaque app a son propre cycle de déploiement, ses propres secrets, sa propre infrastructure. Le front SvelteKit se déploie sur Cloudflare Pages, Vercel, ou un VPS Hetzner. L’API Hono se déploie sur Cloudflare Workers, un autre VPS Hetzner, ou Bun chez Render. La frontière entre les deux est purement réseau : appel HTTPS authentifié.

Pour la CI GitHub Actions, on définit deux jobs distincts qui se déclenchent selon les chemins modifiés. Une PR qui ne touche que apps/api ne redéploie pas le front, et inversement. Cette granularité accélère les CI et limite le risque de régressions croisées.

Erreurs fréquentes

Erreur Cause Solution
Type RPC retourne any Chaîne app.get().post() cassée par variable intermédiaire Garder la chaîne fluide jusqu’à l’export
Bundle front contient code serveur Import sans type Utiliser import type pour les types
pnpm install lent Pas de cache pnpm Activer le cache CI : actions/setup-node avec cache: pnpm
Erreur « Cannot find module @itskills/shared » Workspace mal déclaré Vérifier pnpm-workspace.yaml et "workspace:*" dans deps
TypeScript ne trouve pas les paths baseUrl et paths mal configurés Référencer dans tsconfig.base et étendre dans chaque app
Production : erreur CORS API et front sur domaines différents Configurer CORS strict côté API avec liste explicite

Adaptation au contexte ouest-africain

Trois bénéfices spécifiques. Premièrement, pour les agences à Dakar ou Abidjan qui livrent des projets multiples, le monorepo permet de capitaliser le package shared entre clients : code de validation des numéros de téléphone UEMOA, helpers de formatage FCFA, types Mobile Money. Au bout de trois projets, on a une bibliothèque maison qui accélère significativement chaque nouvelle mission. Deuxièmement, pour les équipes distribuées entre plusieurs villes (un dev à Bamako, deux à Cotonou), la cohérence des types via RPC évite les bugs de communication asynchrone par Slack ou WhatsApp (« c’est quoi le format de la réponse ? »). Le code est l’autorité. Troisièmement, la connectivité variable favorise un mode de travail asynchrone : un développeur peut commiter ses changements API sans attendre que le développeur front soit en ligne, le RPC garantissant que le front saura instantanément ce qui a changé dès qu’il pull.

Côté hébergement, le pattern multi-déploiement permet d’optimiser par cible. Le front SvelteKit en SSR sur Hetzner FRA1 sert vite Dakar et Abidjan. L’API Hono sur Cloudflare Workers sert Lagos et Accra avec une latence quasi nulle. Le coût total reste sous 10 €/mois jusqu’à plusieurs milliers d’utilisateurs actifs, ce qui est imbattable pour les SaaS qui démarrent avec un budget contraint.

Tutoriels frères

Pour aller plus loin

FAQ

Pourquoi pnpm plutôt que npm workspaces ou yarn ?
pnpm gère les dépendances via un store central et des liens symboliques, ce qui évite la duplication massive des node_modules. Sur un monorepo de 5 apps, on passe de 2 Go (npm) à 200 Mo (pnpm) — gain énorme sur les CI bas-coût.

Faut-il TurboRepo ou Nx en plus ?
Non pour un monorepo de 2-5 apps. pnpm seul suffit avec quelques scripts npm bien faits. Ces outils deviennent pertinents au-delà de 10 packages avec dépendances complexes.

Comment versionner le package shared ?
En workspace:* tant qu’il n’est pas publié sur npm. Si on veut le publier (rendre public ou réutiliser entre monorepos), Changesets gère la version semver et le changelog.

Le RPC fonctionne-t-il avec WebSockets ?
Oui partiellement. Pour les WebSockets, Hono fournit un mécanisme typé séparé. Pour les flux de données complexes, regarder Server-Sent Events qui s’intègrent mieux au pattern RPC.

Évolution du monorepo dans le temps

Un monorepo qui démarre avec deux apps et un package partagé évolue naturellement vers une structure plus riche au fil des projets. Trois patterns d’évolution se rencontrent dans les équipes ouest-africaines accompagnées sur trois ans. D’abord, l’extraction d’un package ui qui contient les composants Svelte réutilisables (boutons, cartes, modales) avec leurs styles, dès que deux apps front coexistent. Ensuite, l’apparition d’un package db qui regroupe les schémas Drizzle et les fonctions d’accès, partagé entre l’API principale et un microservice annexe. Enfin, pour les agences, un package presets qui contient les configurations communes (ESLint, Prettier, tsconfig, GitHub Actions templates) factorisées entre projets clients.

Chaque ajout doit être justifié par un usage concret et avéré, pas par anticipation. Le piège classique : créer trop de packages trop tôt, générer une complexité de gestion qui ralentit chaque modification. La règle pragmatique : quand un code est dupliqué dans deux apps avec exactement le même comportement, on l’extrait. Tant que c’est dans une seule app, ça reste dans l’app. Cette discipline garde la structure aérée et compréhensible par tout nouveau développeur en moins d’une heure de tour du dépôt.

Performance des CI et caching

Un monorepo mal configuré peut paradoxalement ralentir les CI au lieu de les accélérer. Trois optimisations paient immédiatement. Premièrement, le cache pnpm via actions/setup-node avec cache: 'pnpm' évite de retélécharger les dépendances à chaque run, gain de 60-90 secondes sur un projet moyen. Deuxièmement, le filtrage des jobs par chemin modifié : un commit qui ne touche que la doc ne déclenche pas le job de tests, économisant minutes et impact CO2. Troisièmement, la parallélisation des tests de packages indépendants — Vitest peut lancer les suites en parallèle, et pnpm peut exécuter le linter sur tous les workspaces simultanément.

Sur un monorepo standard avec 3 apps et 2 packages, ces optimisations font passer le temps de CI complet de 8 minutes à 2 minutes 30. Pour une équipe qui pousse 30 PRs par semaine, c’est un gain de plusieurs heures cumulées hebdomadairement, et surtout une boucle de feedback courte qui change la culture d’équipe — on lance vite, on corrige vite, on déploie souvent.

Alternatives au monorepo et quand les choisir

Le monorepo n’est pas universel. Trois cas où la structure multi-dépôts reste préférable. D’abord, quand le front et le back sont maintenus par des équipes complètement séparées avec des cycles de release totalement décorrélés, la séparation des dépôts force une discipline de contrat API explicite (OpenAPI, GraphQL Schema) qui évite le couplage trop intime. Ensuite, pour les projets open-source où une partie est ouverte à la communauté et l’autre privée, deux dépôts permettent une frontière de licence claire. Enfin, pour les très grandes équipes (50+ développeurs) où la latence Git d’un monorepo géant devient pénalisante, des dépôts séparés tirent l’aiguille.

Pour les équipes ouest-africaines de 1 à 15 développeurs, le monorepo gagne presque toujours. La cohérence des types via RPC, le partage transparent du code, la simplicité des CI, et la facilité d’onboarding d’un nouveau développeur (un seul dépôt à cloner, une seule commande à lancer) font de cette structure un investissement rentable dès la première année.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité