Brave publisher PUBLISHER
Développeur web Front-End dans l'Oise - Gary Deshayes

VueJS 3, ExpressJS 4.17 | Upload et redimensionnement d'une image

Développeur web Front-End dans l'Oise - Gary Deshayes <--Translation

Crée le : samedi 28 novembre 2020

Upload d'une image et redimensionnement avec VueJS 3 et ExpressJS 4.17

Je vais vous présenter comment faire un formulaire simple avec VueJS 3, pour pouvoir upload une image ainsi qu'un champ de texte qui pourrait servir au texte alternatif de l'image.

Le serveur tourne sous ExpressJS 4.17.

Nous allons avoir besoin de plusieurs librairies :

Front VueJS

  • Axios (V0.21) pour effectuer des requêtes HTTP vers le serveur

Back ExpressJS

  • Multer (V 1.4.2) pour récupérer l'image du formulaire et l'insérer dans le dossier
  • Sharp (V 0.26.3) pour redimensionner l'image et la mettre dans un dossier de miniature
  • Cors (V 2.8.5) dans le cas d'un probleme de Cross origin

Une fois les dépendances installées, commençons.

Formulaire VueJS

Il nous faut seulement un input file et un input de texte

<template>
  <div id='main'>
      <input type="file" name="picture" id="picture">
      <!-- Input text lié à une variable de vuejs pour le texte alternatif de l'image -->
      <input type="text" name="alt-picture" id="" placeholder="alt text" v-model="alt_text">
      <!-- Le bouton d'envoi lié à une fonction d'envoi -->
      <button @click="envoi()">Envoyer</button>
  </div>
</template>

Nous donnons un id au input file pour récupérer sa photo plus tard, et nous lions l'input texte à une variable pour un refresh en temps réel

Il nous faut également notre fonction pour envoyer le formulaire au serveur grâce à Axios !

Voici le script du component VueJS :

<script>
import axios from 'axios'

export default {
  name: 'App',
   data() {
    return {
      alt_text: ''
    }
  },
  methods: {
    envoi(){
      // Récupération de l'image
      let img = document.getElementById('picture').files[0]
      // Création d'un formData obligatoire pour envoi de l'image
        var formData = new FormData()
        formData.append('img', img)
        formData.append('alt_text', this.alt_text)
        // Envoi des données sur l'url du serveur (mettez la votre) en POST en envoyant le formData contenant notre image et notre texte
        axios.post('http://localhost:3000/upload_image', formData)
          .then((resp) => {
            console.log(resp)
          })
          .catch((err) => {
            console.log(err.response)
          })
    }
  }
}
</script>

Nous avons donc besoin d'importer Axios, de créer notre méthode qui sera appelée par le bouton d'envoi, et dedans récupérer notre image, la mettre dans un formData avec notre texte alternatif et d'envoyer tout cela au serveur ExpressJS via Axios.

Côté serveur ExpressJS

Tout d'abord pour notre serveur il est nécessaire d'importer nos dépendances et de mettre en place le Cross origin

//Import de nos dépendances
const express = require('express')
const multer = require('multer')
const sharp = require('sharp')
const path = require('path')
var cors = require('cors')

const app = express()

app.use(express.json())

// Mise en place du Cross origin pour éviter les erreurs dans vuejs
app.use(cors())
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*')
  // authorized headers for preflight requests
  // https://developer.mozilla.org/en-US/docs/Glossary/preflight_request
  res.header(
    'Access-Control-Allow-Headers',
    'Origin, X-Requested-With, Content-Type, Accept',
  )
  next()

  app.options('*', (req, res) => {
    // allowed XHR methods
    res.header(
      'Access-Control-Allow-Methods',
      'GET, PATCH, PUT, POST, DELETE, OPTIONS',
    )
    res.send()
  })
})

Ensuite nous allons attaquer la partie de configuration de Multer pour que la librairie sache où l'on souhaite uploader l'image ainsi que d'autres paramètres.

Après le Cross origin mettez en place la configuration Multer :


// Création du diskStorage de multer, il permet de définir notre configuration d'upload
// /!\ Créez les dossiers de destination au cas où avant l'upload
var storage = multer.diskStorage({
  // La limite en taille du fichier
  limits: {
    fileSize: 1000000, //1Mo
  },
  // La destination, ici ce sera à la racine dans le dossier img
  destination: function (req, file, cb) {
    cb(null, './img')
  },
  // Gestion des erreurs
  fileFilter(req, file, cb) {
    if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
      return cb(new Error('Le fichier doit etre un JPG'))
    }
    cb(undefined, true)
  },
  // Fonction qui renomme l'image
  filename: function (req, file, cb) {
    // Genère un nom aléatoire et récupère l'ancienne extension
    cb(
      null,
      Math.random().toString(36).substring(7) +
        '.' +
        file.originalname.split('.')[1],
    )
  },
})

// Création de l'objet multer
const upload = multer({
  storage: storage,
})

Vous pouvez lire dans les commentaires à quoi sert chaque choses, globalement Multer nous permet de choisir un dossier de destination, appliquer des règles de limites et d'extension de fichier, ainsi que de pouvoir renommer l'image.

Route POST de réception d'image

Il est maintenant nécessaire de mettre en place notre route qui va réceptionner nos superbes images, ainsi que de lancer notre serveur !

// Utilisation de l'objet multer en tant que middleware
// Cela veut dire qu'en premier multer va upload notre image, et qu'ensuite nous passons à la fonction de notre route /upload_image
app.post('/upload_image', upload.single('img'), async (req, res) => {
  try {
    if (req.file) {
      // Utilise la librairie sharp pour redimensionner en 200x100, et renvoi la miniature dans un autre fichier dans le dossier de destination choisi dans le diskStorage
      await sharp(req.file.path, { failOnError: false })
        .resize({ width: 200, height: 100 })
        .toFile(
          path.resolve(req.file.destination + '/thumbnail', req.file.filename),
        )
      // Vous pouvez utiliser ces variables pour faire des insertions en base de données ou autre
      let filename = req.file.filename
      let alt_text = req.body.alt_text
    }
    res.send('Upload fini')
  } catch (e) {
    res.status(400).send(e)
  }
})

app.listen(3000, () => {
  console.log('Serveur lancé sur le port : ' + 3000)
})

Nous avons créer notre route, mis en place le middleware  qui nous permet d'upload l'image, et nous avons ensuite défini la fonction de la route comme asynchrone pour le redimensionnement de notre image.

Après l'upload de l'image principale, Sharp va se charger de la prendre et de la retailler, dans l'exemple j'ai mis 200x100 mais il est possible de mettre n'importe quelle valeur.

Suite au redimensionnement Sharp mets notre fichier dans le dossier de destination de notre image principale dans un dossier de miniature, grâce à la méthode .toFile().

Ici aussi vous pouvez choisir n'importe quelle destination.

Ensuite nous pouvons avoir accès au texte alternatif ainsi que le nom de l'image si nous souhaitons stocker ces données en base de données pour l'afficher sous VueJS plus tard !

Images dans le dossier

VueJS, ExpressJS, upload d'une image et redimensionnement dossier

Images avant et après

Voici un aperçu des images avant et après :

VueJS, ExpressJS, upload d'une image et redimensionnement avant

Vous pouvez voir que la somme des deux images est de 454ko, les images font 1280*853px et 640x401px.

Et suite au redimensionnement :

VueJS, ExpressJS, upload d'une image et redimensionnement après

Nous gagnons environ 97% de place de stockage grâce au redimensionnement.

 

Ce tutoriel est maintenant terminé, merci d'avoir lu et n'hésitez pas à partager :)

Articles récents :

Symfony 5 | Retourner une image via une route d'un controller

Symfony

Crée le : mercredi 1 septembre 2021

VueJS 3, ExpressJS 4.17 | Upload et redimensionnement d'une image

Javascript Framework JS

Crée le : samedi 28 novembre 2020

Symfony Event Subscriber | Restriction d'une plage ip avec un Event Subscriber

Symfony

Crée le : samedi 14 novembre 2020

Angular, ExpressJS | Authentification JWT avec Angular 10 et ExpressJS 4 (MySQL)

Javascript SQL Framework JS

Crée le : dimanche 20 septembre 2020

Symfony, Excel, CSV | Générer un fichier CSV pour Excel avec Symfony

Symfony

Crée le : jeudi 6 août 2020

Symfony FormType ChoiceType | Radio button valeur par défaut dans un FormType

Symfony

Crée le : dimanche 26 juillet 2020

Doctrine, Symfony | Différence entre deux dates sous MySQL (Jour, mois, années...)

Symfony SQL

Crée le : jeudi 18 juin 2020

JavaScript, jQuery et Regex | Sécuriser un mot de passe en temps réel avec JS

Javascript jQuery

Crée le : lundi 23 mars 2020

Symfony, Doctrine | Récupérer les anciennes données d'un formulaire FormType

Symfony

Crée le : vendredi 14 février 2020

jQuery, Webpack et Symfony | Appeler jQuery dans vos fichiers twig

Symfony Bugs

Crée le : dimanche 26 janvier 2020