Adicionar uma galeria de imagens ao RichTextEditor no Vue

A caixa de diálogo Insert Gallery do RichTextEditor precisa de três coisas em um app Vue: os scripts do editor carregados antes do app, um componente que cria o editor quando é montado e o destrói quando é desmontado, e um servidor de desenvolvimento que encaminha as requisições da caixa de diálogo para a sua API. Esta página mostra uma configuração com Vite + Vue 3 que faz as três coisas, testada com o exemplo em Express.
Carregar os scripts do editor antes do app
O editor é um conjunto de scripts de navegador comuns que definem window.RichTextEditor. Eles não são módulos ES, então vão no index.html, antes do script de módulo que monta o Vue:
<!-- 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>Os arquivos ficam em public/richtexteditor/, que o Vite serve sem alterações. O rte-files.js fornece as funções de upload que o editor e o botão Upload da galeria chamam. Scripts clássicos no <head> são executados antes do bundle de módulos, então a variável global já existe quando o componente é montado.
O componente
<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é executado assim que adivdo template está no documento.useTemplateRef("container")(Vue 3.5) retorna esse elemento.onBeforeUnmountchamadestroy()enquanto o elemento ainda está lá. Verificamos isso desmontando o app inteiro comapp.unmount(): nenhum elemento do editor ficou no documento e não houve erros na página.- A instância é uma variável comum. Nada no template depende dela, então ela não precisa ser reativa, e o Vue não tem motivo para envolvê-la em um proxy.
defineExposedá ao componente pai um métodogetHTML(). O botão Show HTML do exemplo o chama por meio de uma template ref e imprimiu<p>Hello from Vue.</p>.
O componente pai passa as opções uma única vez. O componente as lê quando o editor é criado e não as observa:
const options = {
toolbar: "full",
galleryEndpoint: "/rte/gallery", // forwarded to Express by vite.config.js
maxUploadFileSize: 4000000,
};Acessar o servidor de API no desenvolvimento
O endpoint da galeria é relativo, /rte/gallery, e a página é servida pelo Vite na porta 5112. O proxy de desenvolvimento do Vite encaminha as rotas de galeria e upload e as imagens para o exemplo em Express na porta 5101:
// /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",
},O navegador vê uma única origem, então não há CORS para configurar. Mantenha as barras finais. O Vite compara uma chave simples com o início da URL, então "/rte" também encaminharia /rte-files.js para o Express. Vimos isso acontecer com o mesmo bloco de proxy no exemplo em React. Com "/rte/", o Vite serve a própria cópia.
Use o proxy apenas no desenvolvimento. Em produção, sirva o dist/ compilado e a API a partir da mesma origem.
O que a caixa de diálogo mostra
A imagem no topo é o editor neste app Vue depois que uma imagem foi inserida pela galeria. As pastas e imagens vêm do servidor Express, descrito no guia da galeria em Node.js. Duas limitações vêm da galeria na versão lançada, seja qual for o framework. A dica de formatos lista JFIF, BMP e AVIF, que o servidor de exemplo recusa. E um upload recusado mostra "Upload failed for <name>." em vez da mensagem do servidor.
Teste
Baixe o projeto de exemplo deste guia e o exemplo em Express. Inicie primeiro o Express (npm install, npm start, com a pasta richtexteditor do editor ao lado de server.mjs). Depois, no projeto Vue:
npm install
npm run dev
➜ Local: http://localhost:5112/O npm run dev primeiro copia os arquivos do editor para public/. Defina RTE_DIR com a pasta do seu editor ou coloque a pasta em public/richtexteditor você mesmo. Abra http://localhost:5112 e clique em Insert Gallery. A caixa de diálogo lista as pastas do servidor. New folder e Upload funcionam pelo proxy, e Insert adiciona <img src="/uploads/..."> ao texto. Executamos exatamente essa sequência no Chromium com Vue 3.5.44 e Vite 8.3.5.