Volt LogoVolt
Extension Development

Bonnes pratiques

Conseils et lignes directrices pour créer d'excellents plugins Volt

Bonnes pratiques pour les plugins

Créez des plugins de haute qualité

Suivez ces bonnes pratiques pour créer des plugins Volt performants, fiables et agréables à utiliser.

Performance

Implémentez un canHandle() efficace

La méthode canHandle() est appelée à chaque requête. Gardez-la rapide :

Évitez les regex complexes
canHandle(context: PluginContext): boolean {
  return /^(search|find|lookup)\s+.+$/i.test(context.query);
}
Utilisez des vérifications simples
canHandle(context: PluginContext): boolean {
  return context.query.startsWith('search ');
}

Utilisez le debouncing

Pour les plugins qui font des appels API, debounce les requêtes pour ne pas saturer l'API :

Appels API debouncés
import { debounce } from "lodash";

class MyPlugin implements Plugin {
  private debouncedMatch = debounce(this.match.bind(this), 300);

  async match(context: PluginContext): Promise<PluginResult[]> {
    // Votre implémentation
    return await this.fetchResults(context.query);
  }
}

300 ms est un bon équilibre entre réactivité et efficacité API.

Implémentez du cache

Mettez les résultats en cache pour améliorer les performances et réduire les appels API :

Mise en cache des résultats
class MyPlugin implements Plugin {
  private cache = new Map<string, PluginResult[]>();
  private cacheTimeout = 5000; // 5 secondes

  async match(context: PluginContext): Promise<PluginResult[]> {
    const cached = this.cache.get(context.query);
    if (cached) return cached;

    const results = await this.fetchResults(context.query);
    this.cache.set(context.query, results);

    setTimeout(() => this.cache.delete(context.query), this.cacheTimeout);

    return results;
  }
}

Respectez les timeouts

Les plugins frontend ont un timeout de 500 ms. Assurez-vous que votre plugin répond vite :

Gestion du timeout
async match(context: PluginContext): Promise<PluginResult[]> {
  const timeout = new Promise<PluginResult[]>((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), 450)
  );

  const results = this.fetchResults(context.query);

  return Promise.race([results, timeout]).catch(() => []);
}

Gérez toujours les erreurs de timeout proprement pour éviter les crashs.

Gestion des erreurs

Expérience utilisateur

Fournissez titres et sous-titres clairs

Rendez les résultats compréhensibles d'un coup d'œil :

Résultat vague
{
  title: 'Résultat',
  subtitle: 'Cliquez pour ouvrir',
}
Clair et descriptif
{
  title: 'Chercher « React hooks » sur Google',
  subtitle: 'Ouvre google.com dans votre navigateur',
}

Utilisez des icônes adaptées

Choisissez des icônes qui représentent clairement vos résultats :

Exemples d'icônes
// Utilisez des emojis pour la simplicité
icon: '🔍'  // Pour la recherche
icon: '📊'  // Pour données/analytics
icon: '⚙️'  // Pour les paramètres
icon: '📁'  // Pour les fichiers
icon: '🚀'  // Pour lancer/exécuter

// Ou des URL d'icônes personnalisées
icon: 'https://example.com/icon.png'

Les emojis sont parfaits pour le prototypage rapide. Utilisez des icônes custom pour les plugins pros.

Fournissez des raccourcis clavier

Ajoutez des raccourcis pour les actions courantes :

Raccourcis clavier
{
  id: '1',
  title: 'Chercher sur Google',
  subtitle: 'Appuyez sur Entrée pour ouvrir',
  shortcut: 'Enter',
  action: () => window.open(url),
}

Affichez les états de chargement

Indiquez le chargement pour donner du retour à l'utilisateur :

Indicateur de chargement
async match(context: PluginContext): Promise<PluginResult[]> {
  // Retourner immédiatement un état de chargement
  const loadingResult = {
    id: 'loading',
    title: 'Chargement…',
    icon: '⏳',
    type: PluginResultType.Info,
  };

  // Récupérer les vrais résultats
  const results = await this.fetchResults(context.query);
  return results.length > 0 ? results : [loadingResult];
}

Sécurité

La sécurité est critique

Suivez toujours les bonnes pratiques de sécurité pour protéger les utilisateurs et leurs données.

Qualité du code

Utilisez TypeScript

Utilisez toujours TypeScript pour la sécurité des types et un meilleur support IDE :

Plugin typé
interface MyPluginConfig {
  apiKey: string;
  endpoint: string;
  timeout: number;
}

class MyPlugin implements Plugin {
  constructor(private config: MyPluginConfig) {}
}

TypeScript aide à détecter les erreurs tôt et fournit une meilleure autocomplétion.

Suivez les conventions de nommage

Utilisez un nommage cohérent dans tout votre plugin :

Conventions de nommage
// ID de plugin : kebab-case
id = 'web-search';

// Noms de classe : PascalCase
class WebSearchPlugin implements Plugin {}

// Méthodes : camelCase
async match(context: PluginContext) {}

// Constantes : UPPER_SNAKE_CASE
const DEFAULT_TIMEOUT = 5000;

Documentez votre code

Ajoutez des commentaires JSDoc pour une meilleure maintenabilité :

Commentaires JSDoc
/**
 * Recherche sur le web via plusieurs moteurs
 * @param query - La requête de recherche
 * @returns Tableau de résultats
 */
async search(query: string): Promise<SearchResult[]> {
  // Implémentation
}

Gardez les fonctions petites

Découpez la logique complexe en fonctions plus petites et ciblées :

Fonction monolithique
async match(context: PluginContext): Promise<PluginResult[]> {
  // 100 lignes de code qui font tout
}
Approche modulaire
async match(context: PluginContext): Promise<PluginResult[]> {
  const query = this.parseQuery(context.query);
  const results = await this.fetchResults(query);
  return this.formatResults(results);
}

Tests

Testez vos plugins

Des tests complets garantissent la fiabilité et préviennent les régressions.

Testez les cas limites

Testez avec des entrées inhabituelles et aux limites :

Tests de cas limites
describe("CalculatorPlugin", () => {
  it("gère une entrée vide", () => {
    const result = plugin.canHandle({ query: "" });
    expect(result).toBe(false);
  });

  it("gère les expressions invalides", () => {
    const result = plugin.canHandle({ query: "1 / 0" });
    expect(result).toBe(true);
  });

  it("gère les entrées très longues", () => {
    const longQuery = "1+".repeat(1000) + "1";
    const result = plugin.canHandle({ query: longQuery });
    expect(result).toBeDefined();
  });
});

Mockez les dépendances externes

Utilisez des mocks pour les appels API afin d'avoir des tests cohérents :

Mock des dépendances
import { vi } from "vitest";

vi.mock("@tauri-apps/api/core", () => ({
  invoke: vi.fn().mockResolvedValue({ data: [] }),
}));

// Test avec données mockées
it("gère les réponses API", async () => {
  const results = await plugin.match({ query: "test" });
  expect(results).toHaveLength(0);
});

Testez la performance

Vérifiez que votre plugin respecte la limite de 500 ms :

Tests de performance
it("répond dans les délais", async () => {
  const start = Date.now();
  await plugin.match({ query: "test" });
  const duration = Date.now() - start;

  expect(duration).toBeLessThan(500);
});

Les plugins dépassant 500 ms seront terminés automatiquement.

Configuration

Accessibilité

Rendez les plugins accessibles à tous

L'accessibilité assure que tous les utilisateurs peuvent utiliser votre plugin efficacement.

Documentation

Une bonne documentation est essentielle

Les plugins bien documentés sont plus faciles à utiliser, maintenir et améliorer.

Communauté

📬 Soyez réactif

Répondez aux issues et pull requests rapidement. Une bonne communication construit la confiance.

🤝 Accueillez les contributions

Facilitez la contribution avec des guidelines claires et une attitude accueillante.

💜 Respectez le code de conduite

Soyez respectueux, inclusif et professionnel dans toutes les interactions.

Exemple de contribution

CONTRIBUTING.md
## Contribuer

Les contributions sont les bienvenues ! Merci de :

1. Forker le dépôt
2. Créer une branche de feature (`git checkout -b feature/amazing`)
3. Committer vos changements (`git commit -m 'Add amazing feature'`)
4. Pusher sur la branche (`git push origin feature/amazing`)
5. Ouvrir une Pull Request

Prêt à créer d'excellents plugins ?

En suivant ces bonnes pratiques vous créerez des plugins rapides, fiables, sécurisés et agréables à utiliser. Bon code ! 🚀

On this page