iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
Formations
TypeScript · Intermédiaire

OpenPatch

Créer et publier une librairie Vue 3 — composant de patch notes avec mode Vue, composable, mode standalone CDN, personnalisation CSS et publication npm.

Vue 3TypeScriptViteTailwind CSS v4
GitHub
01Setup Vite + Vue 3 + TypeScript02Types TypeScript et structure de données03Le composant OpenPatch.vue04Versioning avec localStorage05Le composable useOpenPatch06Mode standalone CDN07Build dual-mode et publication npm
Chapitre 4·20 min

Versioning avec localStorage

Le cœur de la valeur d'OpenPatch : afficher la modal une seule fois par version, automatiquement. Pas de backend, pas de cookies — juste localStorage.

Logique de persistance

src/components/OpenPatch.vue
const STORAGE_KEY_PREFIX = 'openpatch_last_seen_'
 
const getStorageKey = () => `${STORAGE_KEY_PREFIX}${props.projectId}`
 
const getLastSeenVersion = (): string | null => {
  try {
    return localStorage.getItem(getStorageKey())
  } catch {
    return null  // SSR, contexte sécurisé sans storage, etc.
  }
}
 
const saveLastSeenVersion = () => {
  try {
    localStorage.setItem(getStorageKey(), props.version)
  } catch (error) {
    console.error('[OpenPatch] Erreur sauvegarde localStorage:', error)
  }
}

Le try/catch n'est pas optionnel. localStorage peut lancer une exception dans les contextes où le storage est bloqué (mode privé strict sur certains navigateurs, iframes cross-origin, SSR).

Décision d'affichage

const shouldShowPatchNotes = (): boolean => {
  if (props.forceShow) return true      // toujours afficher (debug)
 
  const lastSeen = getLastSeenVersion()
  if (!lastSeen) return true            // première visite
 
  return lastSeen !== props.version     // nouvelle version détectée
}

Trois cas :

  1. forceShow: true → affichage systématique (utile pour tester le rendu)
  2. Aucune version en storage → première visite, on affiche
  3. Version différente → mise à jour, on affiche

Au montage

onMounted(() => {
  if (!props.manual && shouldShowPatchNotes()) {
    isVisible.value = true
    emit('shown')
  }
})

manual: false (défaut) → vérification automatique au montage. manual: true → l'utilisateur appelle show() lui-même depuis le parent.

Détection de changement de version en runtime

watch(() => props.version, (newVersion, oldVersion) => {
  if (!props.manual && newVersion !== oldVersion && shouldShowPatchNotes()) {
    isVisible.value = true
    emit('shown')
  }
})

Si la prop version change pendant la durée de vie du composant (hot reload en dev, ou SPA qui met à jour la config), la modal se réaffiche automatiquement.

Fermeture et sauvegarde

const handleClose = () => {
  isVisible.value = false
  saveLastSeenVersion()  // on sauvegarde APRÈS que l'utilisateur a fermé
  emit('close')
}

La version n'est sauvegardée qu'à la fermeture — pas à l'ouverture. Si l'utilisateur quitte la page sans fermer la modal, elle se réaffichera à la prochaine visite. C'est le comportement attendu.

Clé de storage par projet

Le préfixe openpatch_last_seen_ + projectId permet d'utiliser plusieurs instances sur le même domaine :

// App principale
<OpenPatch project-id="my-app" version="2.0.0" />
// → stocke dans "openpatch_last_seen_my-app"
 
// Admin panel
<OpenPatch project-id="admin-panel" version="1.3.0" />
// → stocke dans "openpatch_last_seen_admin-panel"

Deux projets, deux clés, zéro collision.

Précédent
Le composant OpenPatch.vue
Suivant
Le composable useOpenPatch

Développeur fullstack passionné. J'apprends en construisant et je documente tout — front, back, outils. Le code s'apprend mieux en public.

Naviguer

IndexTous les articlesFormationsProfilOutilsBibliothech

Ailleurs

GitHub RSS

Newsletter

Les articles, libs et découvertes. Une fois par semaine, pas plus.

© 2026 William LoreeConçu & codé à la main