@arcpkg/meta
v0.0.1-beta.0.1
Published
META est une bibliothèque React/TypeScript/Javascript légère et performante pour la gestion dynamique des métadonnées HTML (title, description, keywords, author, etc.) dans les applications SPA. Elle permet de mettre à jour les métadonnées de la page de m
Readme
@arcpkg/meta
@arcpkg/meta est une bibliothèque React/TypeScript/Javascript légère et performante pour la gestion dynamique des métadonnées HTML (title, description, keywords, author, etc.) dans les applications SPA. Elle permet de mettre à jour les métadonnées de la page de manière déclarative et impérative, avec un support complet de TypeScript, Javascript.
✨ Fonctionnalités Principales
📄 Gestion Complète des Métadonnées
- Mise à jour dynamique du titre de la page (
<title>) - Gestion des métadonnées HTML standards : description, keywords, author, etc.
- Support des métadonnées HTTP-EQUIV (Content-Type, etc.)
- Mise à jour en temps réel lors des changements de route ou d'état
🎯 Deux Approches d'Utilisation
- Composant déclaratif
<Metadata />pour une utilisation simple - Hook impératif
useMetaActions()pour un contrôle avancé - API flexible permettant les deux approches dans la même application
⚡ Performance Optimisée
- Mises à jour ciblées uniquement des métadonnées modifiées
- Aucune dépendance lourde
- Bundle size minimal (< 3KB gzipped)
- Zéro impact sur le rendu React
🔧 Intégration Facile
- Installation en une commande
- Configuration minimale requise
- Compatibilité totale avec TypeScript
- Intégration transparente avec Vite et React Router
📦 Installation
Via npm/yarn/pnpm
npm install @arcpkg/meta
# ou
yarn add @arcpkg/meta
# ou
pnpm add @arcpkg/metaDépendances requises
- React 19+
- TypeScript 5.0+ (recommandé)
- Vite (optionnel, mais recommandé)
🚀 Démarrage Rapide
Utilisation avec le composant déclaratif
// App.tsx
import React from 'react';
import Metadata from '@arcpkg/meta/components';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const HomePage = () => (
<>
<Metadata
title="Page d'Accueil - Mon Application"
description="Bienvenue sur notre application révolutionnaire"
keywords={['accueil', 'application', 'révolutionnaire']}
author="INICODE Team"
/>
<h1>Bienvenue !</h1>
</>
);
const AboutPage = () => (
<>
<Metadata
title="À Propos - Mon Application"
description="Découvrez notre histoire et notre équipe"
keywords={['à propos', 'équipe', 'histoire']}
author="INICODE Team"
/>
<h1>À Propos</h1>
</>
);
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
</Routes>
</BrowserRouter>
);
};
export default App;Utilisation avec le hook impératif
// ProductPage.tsx
import React, { useEffect } from 'react';
import { useMetaActions } from '@arcpkg/meta/hooks';
const ProductPage = ({ product }) => {
const { setHeader } = useMetaActions();
useEffect(() => {
setHeader({
title: `\${product.name} - Boutique en ligne`,
description: product.description,
keywords: ['produit', product.category, 'achat'],
author: 'INICODE Shop',
});
}, [product]);
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
</div>
);
};
export default ProductPage;📚 Documentation API
Composant Metadata
import Metadata from '@arcpkg/meta/components';
// Props disponibles
interface ParamsMetadata {
title?: string; // Titre de la page (<title>)
description?: string; // Meta description
keywords?: string[]; // Mots-clés (seront joints par ', ')
author?: string; // Auteur de la page
// ... autres métadonnées supportées
}
// Utilisation
<Metadata
title="Mon Titre"
description="Ma description"
keywords={['mot1', 'mot2']}
author="John Doe"
/>Hook useMetaActions
import { useMetaActions } from '@arcpkg/meta/hooks';
const MyComponent = () => {
const { setHeader } = useMetaActions();
// Configuration possible
interface ConfigSetHeader {
title?: string;
description?: string;
keywords?: string[];
author?: string;
subject?: string;
language?: string;
// ... toutes les métadonnées HTML standard
}
// Exemple d'utilisation
const updateMetadata = () => {
setHeader({
title: 'Nouveau Titre',
description: 'Nouvelle description',
keywords: ['react', 'metadata'],
author: 'INICODE',
language: 'fr-FR'
});
};
return (
<button onClick={updateMetadata}>
Mettre à jour les métadonnées
</button>
);
};🔧 Utilisation Avancée
Métadonnées personnalisées
// Le système supporte de nombreuses métadonnées HTML
setHeader({
title: 'Titre de la page',
description: 'Description pour les moteurs de recherche',
keywords: ['technologie', 'react', 'typescript'],
author: 'Équipe de développement',
subject: 'Développement Web',
copyright: '© 2024 INICODE',
language: 'fr-FR',
abstract: 'Résumé de la page',
topic: 'Programmation',
summary: 'Sommaire du contenu',
designer: 'Jean Dupont',
'reply-to': '[email protected]',
owner: 'INICODE SAS',
url: 'https://example.com',
'identifier-URL': 'https://example.com/page-id'
});Intégration avec React Router
// routes/MetaRoute.tsx
import { useEffect } from 'react';
import { useMetaActions } from '@arcpkg/meta/hooks';
interface MetaRouteProps {
children: React.ReactNode;
title?: string;
description?: string;
keywords?: string[];
}
const MetaRoute = ({ children, title, description, keywords }: MetaRouteProps) => {
const { setHeader } = useMetaActions();
useEffect(() => {
if (title || description || keywords) {
setHeader({
title,
description,
keywords,
});
}
}, [title, description, keywords]);
return <>{children}</>;
};
// Utilisation dans votre router
<Route
path="/products/:id"
element={
<MetaRoute
title="Détails du Produit"
description="Consultez les détails complets de notre produit"
keywords={['produit', 'détails', 'spécifications']}
>
<ProductDetails />
</MetaRoute>
}
/>Gestion des métadonnées HTTP-EQUIV
// Le système met automatiquement à jour certaines métadonnées HTTP-EQUIV
// Par défaut : Content-Type: text/html; charset=UTF-8
// Extension possible pour supporter d'autres en-têtes
// Exemple d'extension personnalisée
const setCustomHttpEquiv = () => {
// Le système peut être étendu pour gérer d'autres en-têtes
// comme refresh, content-security-policy, etc.
};🎯 Exemples Complets
Exemple 1 : Blog avec métadonnées dynamiques
// BlogPost.tsx
import React, { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { useMetaActions } from '@arcpkg/meta/hooks';
import { blogPosts } from '../data/blogPosts';
const BlogPost = () => {
const { id } = useParams();
const { setHeader } = useMetaActions();
const post = blogPosts.find(p => p.id === id);
useEffect(() => {
if (post) {
setHeader({
title: `\${post.title} - Mon Blog`,
description: post.excerpt,
keywords: [...post.tags, 'blog', 'article'],
author: post.author,
subject: post.category,
});
}
}, [post]);
if (!post) return <div>Article non trouvé</div>;
return (
<article>
<h1>{post.title}</h1>
<div>Par {post.author} • {post.date}</div>
<div>{post.content}</div>
</article>
);
};Exemple 2 : E-commerce avec métadonnées SEO
// CategoryPage.tsx
import React, { useEffect } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useMetaActions } from '@arcpkg/meta/hooks';
import ProductGrid from '../components/ProductGrid';
import { getCategoryInfo } from '../api/categories';
const CategoryPage = () => {
const [searchParams] = useSearchParams();
const categoryId = searchParams.get('category');
const { setHeader } = useMetaActions();
const [category, setCategory] = React.useState(null);
useEffect(() => {
const loadCategory = async () => {
const data = await getCategoryInfo(categoryId);
setCategory(data);
// Mettre à jour les métadonnées
setHeader({
title: `\${data.name} - Boutique en ligne`,
description: `Découvrez notre sélection de \${data.name.toLowerCase()}. \${data.description}`,
keywords: [data.name, 'achat', 'boutique', ...data.keywords],
author: 'INICODE E-commerce',
});
};
if (categoryId) {
loadCategory();
}
}, [categoryId]);
return (
<div>
{category && (
<>
<h1>{category.name}</h1>
<p>{category.description}</p>
<ProductGrid categoryId={categoryId} />
</>
)}
</div>
);
};Exemple 3 : Application multi-langues
// LocalizedPage.tsx
import React, { useEffect } from 'react';
import { useTranslation } from '@arcpkg/intl'; // Intégration avec @arcpkg/intl
import { useMetaActions } from '@arcpkg/meta/hooks';
const LocalizedPage = () => {
const { t, currentLocale } = useTranslation();
const { setHeader } = useMetaActions();
useEffect(() => {
// Utiliser les traductions pour les métadonnées
setHeader({
title: t('page.title'),
description: t('page.description'),
keywords: t('page.keywords', { returnObjects: true }),
author: t('common.author'),
language: currentLocale,
});
}, [currentLocale, t]);
return (
<div>
<h1>{t('page.title')}</h1>
<p>{t('page.content')}</p>
</div>
);
};🔧 Configuration
Variables d'environnement
# .env
VITE_APP_TITLE="Mon Application"
VITE_DEFAULT_AUTHOR="Équipe de développement"Configuration TypeScript
{
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "DOM.Iterable", "ES2020"],
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"types": ["vite/client"]
}
}🛡️ Gestion des Erreurs
Fallback automatique
// En cas d'erreur, le système utilise des valeurs par défaut
const ErrorExample = () => {
const { setHeader } = useMetaActions();
const trySetHeader = () => {
try {
setHeader({
title: undefined, // Sera ignoré
description: 'Description valide',
});
} catch (error) {
// En mode debug, les erreurs sont loggées
if (import.meta.env.MODE === 'debug') {
console.error('Erreur de métadonnées:', error);
}
// Fallback au titre de l'application
setHeader({
title: import.meta.env.VITE_APP_TITLE,
});
}
};
return <button onClick={trySetHeader}>Tester</button>;
};Validation des métadonnées
// Fonction utilitaire de validation
const validateMetadata = (metadata: any) => {
const errors: string[] = [];
if (metadata.title && metadata.title.length > 60) {
errors.push('Le titre ne doit pas dépasser 60 caractères pour le SEO');
}
if (metadata.description && metadata.description.length > 160) {
errors.push('La description ne doit pas dépasser 160 caractères pour le SEO');
}
if (metadata.keywords && metadata.keywords.length > 10) {
errors.push('Il est recommandé de ne pas dépasser 10 mots-clés');
}
return errors;
};
// Utilisation
const setValidatedHeader = (config: any) => {
const errors = validateMetadata(config);
if (errors.length > 0) {
console.warn('Avertissements SEO:', errors);
}
setHeader(config);
};📋 Table des Métadonnées Supportées
Métadonnées standard
| Nom | Description | Exemple |
|-----|-------------|---------|
| title | Titre de la page (balise <title>) | Page d'Accueil |
| description | Description pour le SEO | Bienvenue sur notre site... |
| keywords | Mots-clés pour le SEO | ['react', 'typescript', 'vite'] |
| author | Auteur de la page | INICODE Team |
| subject | Sujet de la page | Technologie |
| language | Langue de la page | fr-FR |
| copyright | Droits d'auteur | © 2024 |
| abstract | Résumé | Résumé du contenu... |
| topic | Thème principal | Développement Web |
| summary | Sommaire | Sommaire détaillé... |
Métadonnées HTTP-EQUIV
| Nom | Description | Valeur par défaut |
|-----|-------------|-------------------|
| Content-Type | Type de contenu et encodage | text/html; charset=UTF-8 |
🔧 Build et Développement
Scripts recommandés
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"type-check": "tsc --noEmit"
}
}Structure de projet recommandée
src/
├── components/
│ ├── MetadataWrapper.tsx # Wrapper personnalisé
│ └── SeoManager.tsx # Gestionnaire SEO avancé
├── hooks/
│ └── useMetadata.ts # Hook personnalisé étendu
├── utils/
│ └── metadata-validator.ts # Validateur de métadonnées
└── main.tsx📄 Licence
MIT License - Voir le fichier LICENSE pour plus de détails.
🐛 Signaler un Bug
Envoyez-nous un mail à l'adresse [email protected] pour :
- Signaler un bug
- Proposer une amélioration
- Poser une question sur l'utilisation
- Demander une nouvelle fonctionnalité
@arcpkg/meta - La solution simple et efficace pour gérer les métadonnées dans React.
Développé par l'équipe INICODE
