Comment uploader fichiers publics avec Meteor.js

Comment uploader fichiers publics avec Meteor.js
Alexandre P. dans Dev - mis à jour le 03-05-2025

MeteorJS est une plateforme fullstack qui de part sa conception et l'utilisation du Distributed Data Protocol (DDP) change l'approche en matière de communication front/back. Comment faire pour gérer l'upload de fichiers dans ces conditions ?

L'upload de fichier avec le protocole DDP

Dernièrement je partageais avec vous ma façon d'organiser mon code lorsque j'utilise MeteorJS, vous pouvez retrouver cet article ici .

Mais comme je vous disais dans cet article, l'utilisation protocole DDP risque de casser vos habitudes en matière de communication serveur. Il ne s'agira pas de REST API ni de GraphQL ! Nous allons devoir nous servir des RPC (Remote Procedure Call).

Ainsi, je vais vous expliquer comment je m'y prends pour uploader des ressources publiques. Notez que le mot public a son importance étant donné que pour une ressource publique, il suffit de le positionner dans un dossier public/ à la racine de votre projet Meteor.

Ce fichier sera accessible via un appel HTTP standard. Nous verrons ultérieurement comment déposer les fichiers dans un dossiers inaccessible, nous forçant ainsi à gérer les accès aux fichiers (plus facile à faire une fois que nous avons mis en place des sessions !).

Important à savoir pour les utilisateurs de Meteor Typescript ⚠️

Lorsque vous travaillez en Typescript, votre code est compilé. Donc au runtime, votre interpreter se positionne dans le dossier .meteor qui contient le build du projet. Ce qui signifie que parcourir les dossiers et fichiers depuis cet endroit peut s'avérer fastidieux !

C'est pourquoi il y a des variables d'environnement pour nous aider à nous repérer plus facilement au niveau des paths. Nous utiliserons : process.env.PWD

Preparons notre API pour l'upload

Commençons par créer un dossier /public à la racine de notre projet et dans ce même dossier, ajoutons un fichier .keep pour pouvoir ensuite faire les règles .gitignore nécessaires :

# gitignore
public/
!public/.keep

Maintenant tout ce que vous uploadez ne sera pas versionné (évitons d'envoyer des fichiers binaires sur git... 😅).

// /imports/api/file.ts
import { Meteor } from 'meteor/meteor'
import * as fs from 'fs'
import path from 'path'
import { v4 as uuid } from 'uuid'

const FILES_PATH = path.resolve(process.env.PWD ?? '', 'public/files')

type UploadedFile = {
  mimeType: string
  name: string
}

Meteor.methods({
  'file.upload'(
    file: UploadedFile, // Changement de type car le File Object ne passe pas via RPC
    fileData: any // Ici nous passons les données binaires en raw
  ) {
    if (Meteor.isServer) {
      // On donne un nom unique à notre fichier uploadé
      const fileName = uuid()
      const filePath = path.resolve(FILES_PATH, `${fileName}.${file.mimeType?.split('/')?.[1]}`)

      // On écrit notre fichier dans notre répertoire
      fs.writeFileSync(filePath, fileData, 'binary')
      
      // ... Ici je fais les écritures DB nécessaires (à personnaliser) 
      
      // On retourne le nom du fichier uploadé
      return `${fileName}.${file.mimeType?.split('/')?.[1]}`
    }
  },
})

Mise à jour du fichier api/index.ts :

// imports/api/index.ts

// ...
import './file'
// ...

Côté formulaire client

Sur notre page, nous allons ajouter un input file pour gérer l'envoi du fichier :

// pages/page.tsx

//...

type MaPageProps = {
  uploadFile: (f: File) => void
}

const MaPage = ({ uploadFile }: MaPageProps) => {
  return (
    /* ... form inputs */
    <div>
      <label htmlFor="name">
        Photo
      </label>
      <input type="file" onChange={e => uploadFile(e.currentTarget.files?.[0])} />
    </div>
  )
}

export default withTracker(() => {
  return {
    uploadFile: (file: File) => {
      if (file) {
        const reader = new FileReader()
        
        reader.onload = function () {
          Meteor.call(
            'file.upload',
            // File to Object pour le RPC
            {
              mimeType: file.type,
              name: file.name,
            },
            // Raw binary data
            reader.result,
            (err: any, fileName: string) => {
              if (err) {
                console.log(err)
                return error()
              }
              alert('Fichier uploadé')
              console.log(fileName)
            }
          )
        }

        reader.readAsBinaryString(file)
      }
    }
  }
})(MaPage)

Affichage du fichier uploadé sur la page

Une fois le fichier uploadé, puisqu'il s'agit d'un fichier public. Je pars du principe que vous avez fait les stockage DB nécessaires. Une fois que vous récupérez votre collection via des requêtes, il ne vous reste plus qu'à l'afficher. Vous pouvez tester avec une URL en dur juste pour vérifier que votre fichier est accessible.

Si votre dossier public est organisé de la sorte :

/public
|_/img
   |_picture.jpg

Il ne vous reste plus qu'à faire un essai :

// /pages/index.tsx

const pictureUrl = "/img/picture.jpg";

// ...
<img src={pictureUrl} />

Dans un prochain article on parlera de la pagination de données sur les requêtes de collection. D'ici là, portez vous bien, bon code ! 😉

FAQ

Pourquoi ne pas utiliser une API REST classique pour uploader des fichiers avec Meteor ?

Meteor repose sur le protocole DDP qui remplace les appels REST ou GraphQL habituels. Les échanges avec le serveur passent par des RPC (Remote Procedure Call), ce qui impose d'adapter la façon dont on envoie les données, y compris les fichiers binaires.

Pourquoi le File Object ne peut pas être envoyé directement via un appel Meteor.call ?

Le protocole DDP ne sait pas sérialiser un objet File natif du navigateur. Il faut donc le convertir en données binaires brutes avec FileReader, et transmettre séparément les métadonnées comme le nom et le type MIME.

À quoi sert process.env.PWD dans ce contexte Meteor Typescript ?

En TypeScript, le code compilé s'exécute depuis le dossier .meteor, ce qui rend les chemins relatifs peu fiables. La variable process.env.PWD pointe vers la racine réelle du projet, ce qui permet de construire correctement le chemin vers le dossier public.

Comment éviter que les fichiers uploadés soient versionnés dans Git ?

Il suffit d'ajouter le dossier public dans le .gitignore tout en conservant un fichier .keep pour que le dossier reste présent dans le dépôt. Ainsi les fichiers binaires uploadés ne seront jamais commités par accident.

Comment accéder à un fichier uploadé dans le dossier public depuis le front-end ?

Tout fichier placé dans le dossier public de Meteor est accessible directement via une URL HTTP, en utilisant son chemin relatif comme source. Par exemple un fichier dans public/img/ sera accessible à l'URL /img/fichier.jpg sans configuration supplémentaire.

#meteor#react#typescript#programming#upload#file

user picture

Alexandre P.

Développeur passionné depuis plus de 20 ans, j'ai une appétence particulière pour les défis techniques et changer de technologie ne me fait pas froid aux yeux.