Créer et publier une librairie Vue 3 — composant de patch notes avec mode Vue, composable, mode standalone CDN, personnalisation CSS et publication npm.
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.
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()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 }
}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.
<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é.