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 5·20 min

Le composable useOpenPatch

Le composable offre une API programmatique alternative au composant. Utile quand on veut contrôler l'affichage depuis la logique métier, pas depuis le template.

Différence avec le composant

Avec le composant, l'affichage est déclaratif :

<OpenPatch project-id="app" version="2.0" :patchnotes="notes" />

Avec le composable, c'est impératif — on décide quand montrer :

const { show, shouldShow } = useOpenPatch({ projectId: 'app', version: '2.0', patchnotes: notes })
 
// Afficher uniquement après que l'utilisateur a chargé ses données
await fetchUserData()
if (shouldShow()) show()

Implémentation

src/composables/useOpenPatch.ts
import { ref, computed } from 'vue'
import type { PatchNotesConfig, CSSCustomization } from '../types/settings'
 
export interface OpenPatchConfig {
  projectId: string
  version: string
  patchnotes: PatchNotesConfig
  title?: string
  closeButtonText?: string
  forceShow?: boolean
  cssCustomization?: CSSCustomization
}
 
interface StoredVersion {
  version: string
  timestamp: number  // utile pour des expirations futures
}
 
export function useOpenPatch(config: OpenPatchConfig) {
  const isVisible = ref(false)
 
  const storageKey = computed(() => `openpatch_${config.projectId}_version`)
 
  const getLastSeenVersion = (): string | null => {
    try {
      const stored = localStorage.getItem(storageKey.value)
      if (!stored) return null
      const data: StoredVersion = JSON.parse(stored)
      return data.version ?? null
    } catch {
      return null
    }
  }
 
  const saveCurrentVersion = () => {
    try {
      localStorage.setItem(storageKey.value, JSON.stringify({
        version: config.version,
        timestamp: Date.now()
      }))
    } catch (error) {
      console.error('[OpenPatch] Erreur sauvegarde:', error)
    }
  }
 
  const shouldShow = (): boolean => {
    if (config.forceShow) return true
    const lastSeen = getLastSeenVersion()
    return !lastSeen || lastSeen !== config.version
  }
 
  const show = () => { isVisible.value = true }
 
  const hide = () => {
    isVisible.value = false
    saveCurrentVersion()  // sauvegarde à la fermeture
  }
 
  const reset = () => {
    try {
      localStorage.removeItem(storageKey.value)
    } catch (error) {
      console.error('[OpenPatch] Erreur reset:', error)
    }
  }
 
  const getLastSeen = (): StoredVersion | null => {
    try {
      const stored = localStorage.getItem(storageKey.value)
      return stored ? JSON.parse(stored) : null
    } catch {
      return null
    }
  }
 
  return { isVisible, show, hide, shouldShow, reset, getLastSeen, config }
}

Format de stockage enrichi

Le composable stocke un objet JSON au lieu d'une simple chaîne :

{
  "version": "2.0.0",
  "timestamp": 1718000000000
}

Le timestamp n'est pas utilisé dans la v1, mais ouvre la porte à une feature future : expirer les patch notes après X jours même si l'utilisateur les a déjà vus.

Utilisation dans un composant

<script setup lang="ts">
import { useOpenPatch } from 'open-patch'
import { onMounted } from 'vue'
 
const { show, hide, shouldShow, isVisible } = useOpenPatch({
  projectId: 'mon-app',
  version: '2.1.0',
  patchnotes: {
    title: "Nouveautés",
    sections: [{ title: "Features", items: ["Nouvelle UI"] }]
  }
})
 
onMounted(() => {
  if (shouldShow()) show()
})
</script>
 
<template>
  <div v-if="isVisible" class="modal">
    <!-- Contenu patch notes -->
    <button @click="hide">Fermer</button>
  </div>
</template>

Le composable retourne isVisible — un ref<boolean> réactif. Le template se met à jour automatiquement quand show() ou hide() est appelé.

Précédent
Versioning avec localStorage
Suivant
Mode standalone CDN

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