Ajouter une galerie d’images à RichTextEditor avec Vue

RichTextEditor dans l’exemple Vite + Vue, avec une image de la galerie du serveur Express insérée dans le texte

Dans une application Vue, la boîte de dialogue Insert Gallery de RichTextEditor a besoin de trois choses : les scripts de l’éditeur chargés avant l’application, un composant qui crée l’éditeur à son montage et le détruit à son démontage, et un serveur de développement qui transmet les requêtes de la boîte de dialogue à votre API. Cette page présente une configuration Vite + Vue 3 qui fait ces trois choses, testée avec l’exemple Express.

Charger les scripts de l’éditeur avant l’application

L’éditeur est un ensemble de scripts navigateur simples qui définissent window.RichTextEditor. Ce ne sont pas des modules ES : ils vont donc dans index.html, avant le script de module qui monte Vue :

HTML · index.html
<!-- Plain browser scripts from public/, loaded before the Vue bundle. -->
<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css">
<script src="/richtexteditor/rte.js"></script>
<script src="/richtexteditor/plugins/all_plugins.js"></script>
<script src="/rte-files.js"></script>

Les fichiers se trouvent dans public/richtexteditor/, que Vite sert tel quel. rte-files.js fournit les fonctions d’envoi qu’appellent l’éditeur et le bouton Upload de la galerie. Les scripts classiques placés dans <head> s’exécutent avant le bundle de modules : la variable globale existe donc au moment où le composant se monte.

Le composant

Vue · src/components/RichTextEditor.vue
<script setup>
import { onBeforeUnmount, onMounted, useTemplateRef } from "vue";

// window.RichTextEditor comes from the scripts in index.html.
const props = defineProps({
  options: { type: Object, required: true },
  initialHtml: { type: String, default: "" },
});
const container = useTemplateRef("container");
let editor = null; // a plain variable: the editor object does not need to be reactive

onMounted(() => {
  editor = new window.RichTextEditor(container.value, props.options);
  editor.setHTMLCode(props.initialHtml);
});
onBeforeUnmount(() => {
  editor?.destroy();
  editor = null;
});

defineExpose({ getHTML: () => editor.getHTMLCode() });
</script>

<template>
  <div ref="container"></div>
</template>
  • onMounted s’exécute dès que le div du template est dans le document. useTemplateRef("container") (Vue 3.5) renvoie cet élément.
  • onBeforeUnmount appelle destroy() tant que l’élément est encore là. Nous l’avons vérifié en démontant toute l’application avec app.unmount() : aucun élément de l’éditeur ne restait dans le document, et il n’y a eu aucune erreur sur la page.
  • L’instance est une simple variable. Rien dans le template n’en dépend : elle n’a donc pas besoin d’être réactive, et Vue n’a aucune raison de l’envelopper dans un proxy.
  • defineExpose fournit au parent une méthode getHTML(). Le bouton Show HTML de l’exemple l’appelle via une ref de template et a affiché <p>Hello from Vue.</p>.

Le parent transmet les options une seule fois. Le composant les lit à la création de l’éditeur et ne les surveille pas :

Vue · src/App.vue
const options = {
  toolbar: "full",
  galleryEndpoint: "/rte/gallery", // forwarded to Express by vite.config.js
  maxUploadFileSize: 4000000,
};

Atteindre le serveur d’API en développement

Le point de terminaison de la galerie est relatif, /rte/gallery, et la page est servie par Vite sur le port 5112. Le proxy de développement de Vite transmet les routes de galerie et d’envoi, ainsi que les images, à l’exemple Express sur le port 5101 :

JavaScript · vite.config.js
// /rte/ and /uploads/ go to the Express sample (node-express, port 5101).
// Keep the trailing slashes: "/rte" alone would also catch /rte-files.js.
proxy: {
  "/rte/": "http://localhost:5101",
  "/uploads/": "http://localhost:5101",
},

Le navigateur ne voit qu’une seule origine : il n’y a donc pas de CORS à configurer. Conservez les barres obliques finales. Vite compare une clé simple avec le début de l’URL : "/rte" transmettrait donc aussi /rte-files.js à Express. Nous l’avons constaté avec le même bloc de proxy dans l’exemple React. Avec "/rte/", Vite sert sa propre copie.

N’utilisez le proxy qu’en développement. En production, servez le dist/ compilé et l’API depuis la même origine.

Ce qu’affiche la boîte de dialogue

L’image en haut de la page montre l’éditeur dans cette application Vue après l’insertion d’une image depuis la galerie. Les dossiers et les images proviennent du serveur Express, décrit dans le guide sur la galerie en Node.js. Deux limites viennent de la galerie publiée, quel que soit le framework. Son indication des formats mentionne JFIF, BMP et AVIF, que le serveur d’exemple refuse. Et un envoi refusé affiche « Upload failed for <name>. » plutôt que le message du serveur.

Tester

Téléchargez le projet d’exemple de ce guide et l'exemple Express. Démarrez d’abord Express (npm install, npm start, avec le dossier richtexteditor de l’éditeur à côté de server.mjs). Ensuite, dans le projet Vue :

Shell
npm install
npm run dev
  ➜  Local:   http://localhost:5112/

npm run dev copie d’abord les fichiers de l’éditeur dans public/. Définissez RTE_DIR sur votre dossier de l’éditeur, ou placez vous-même le dossier dans public/richtexteditor. Ouvrez http://localhost:5112 et cliquez sur Insert Gallery. La boîte de dialogue liste les dossiers du serveur. New folder et Upload fonctionnent à travers le proxy, et Insert ajoute <img src="/uploads/..."> au texte. Nous avons exécuté exactement cette séquence dans Chromium avec Vue 3.5.44 et Vite 8.3.5.

Le même guide pour d’autres plateformes

React · Angular

À lire ensuite