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 mode standalone permet d'utiliser OpenPatch sans Vue, sans npm, sans build step — juste deux balises <script> dans n'importe quelle page HTML.
import { createApp } from 'vue'
import OpenPatch from './components/OpenPatch.vue'
import { loadConfig } from './utils/configLoader'
import './style.css'
async function initOpenPatch() {
const jsonUrl = window.OpenPatchConfig?.jsonUrl
const settings = await loadConfig({ jsonUrl })
if (!settings?.projectId || !settings.version || !settings.patchnotes) {
console.error('[OpenPatch] Configuration incomplète')
return
}
// Monter Vue dans un container créé dynamiquement
const container = document.createElement('div')
container.id = 'openpatch-widget-container'
document.body.appendChild(container)
const app = createApp(OpenPatch, {
projectId: settings.projectId,
version: settings.version,
patchnotes: settings.patchnotes,
title: settings.patchnotes.title,
closeButtonText: settings.options?.closeButtonText ?? 'Compris !',
forceShow: settings.options?.forceShow ?? false,
cssCustomization: settings.css,
})
const instance = app.mount(container) as any
// Exposer l'API sur window
window.OpenPatch = {
show: () => instance.show?.(),
hide: () => instance.hide?.(),
reset: () => instance.reset?.(),
}
}
// Attendre le DOM si nécessaire
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initOpenPatch)
} else {
initOpenPatch()
}Vue est bundlé dans ce build — c'est external: [] dans la config Vite standalone. Le fichier produit est autonome (~123 kB avec Vue inclus).
La séparation des responsabilités est le point le plus élégant du projet.
export async function loadConfig(options: { jsonUrl?: string } = {}): Promise<WindowSettings | null> {
let jsonConfig: JSONConfig | null = null
// Étape 1 — charger le JSON distant (version + patchnotes seulement)
if (options.jsonUrl) {
try {
const res = await fetch(options.jsonUrl)
jsonConfig = await res.json() as JSONConfig
} catch (error) {
console.error('[OpenPatch] Erreur chargement JSON:', error)
}
}
// Étape 2 — fusionner avec window.Settings (projectId + options + css)
if (jsonConfig && window.Settings) {
return {
projectId: window.Settings.projectId,
version: jsonConfig.version,
patchnotes: jsonConfig.patchnotes,
options: window.Settings.options,
css: window.Settings.css,
}
}
// Étape 3 — tout dans window.Settings (config inline)
if (window.Settings?.projectId && window.Settings.version && window.Settings.patchnotes) {
return window.Settings as WindowSettings
}
return null
}<script>
window.OpenPatchConfig = { jsonUrl: '/patchnotes.json' }
window.Settings = {
projectId: "mon-app",
options: { closeButtonText: "OK" },
css: { primaryColor: "#4CAF50" }
}
</script>
<script src="openpatch.es.js" type="module"></script>{
"version": "2.1.0",
"patchnotes": {
"title": "Nouveautés",
"sections": [{ "title": "Features", "items": ["Mode sombre"] }]
}
}Avantage clé : pour mettre à jour les patch notes, on modifie uniquement patchnotes.json. Pas de redéploiement de l'application.
<script>
window.Settings = {
projectId: "mon-app",
version: "2.1.0",
patchnotes: {
title: "Nouveautés",
sections: [{ title: "Features", items: ["Mode sombre"] }]
},
options: { closeButtonText: "Compris !" },
css: { primaryColor: "#0f172a" }
}
</script>
<script src="openpatch.es.js" type="module"></script>Tout dans l'HTML — plus simple, mais nécessite un déploiement pour chaque mise à jour.
Après l'init, le widget est contrôlable depuis n'importe quel script :
// Forcer l'affichage (bouton "Voir les nouveautés")
document.querySelector('#changelog-btn').addEventListener('click', () => {
window.OpenPatch.show()
})
// Réinitialiser pour retester
window.OpenPatch.reset()