Uploading an image and resizing with VueJS 3 and ExpressJS 4.17
I will show you how to make a simple form with VueJS 3, to upload an image and a text field that could be used for the image’s alternative text.
The server is running ExpressJS 4.17.
We will need several libraries :
VueJS Front
- Axios (V0.21) to make HTTP requests to the server
Back ExpressJS
- Multer (V 1.4.2) to retrieve the form image and insert it in the folder
- Sharp (V 0.26.3) to resize the image and put it in a thumbnail folder
- Cors (V 2.8.5) in the case of a Cross origin problem
Once the outbuildings are installed, let’s get started.
VueJS form
All we need is an input file and a text input.
<template> <div id='main'> <input type="file" name="picture" id="picture"> <!-- Input text linked to a view variablejs for the alternative text of the image --> <input type="text" name="alt-picture" id="" placeholder="alt text" v-model="alt_text"> <!-- The send button linked to a send function --> <button @click="send()">Send</button> </div> </template>
We give an id to the input file to retrieve its picture later, and we link the text input to a variable for a real-time refresh.
We also need our function to send the form to the server using Axios!
Here is the script of the VueJS component:
<script> import axios from 'axios' export default { name: 'App', data() { return { alt_text: '' } }, methods: { send(){ // Image recovery let img = document.getElementById('picture').files[0] // Creation of an obligatory formData for sending the image var formData = new FormData() formData.append('img', img) formData.append('alt_text', this.alt_text) // Sending data on the server url (put your own) in POST by sending the formData containing our image and our text axios.post('http://localhost:3000/upload_image', formData) .then((resp) => { console.log(resp) }) .catch((err) => { console.log(err.response) }) } } } </script>
So we need to import Axios, create our method that will be called by the send button, and in it get our image, put it in a formData with our alternate text and send it all to the ExpressJS server via Axios.
ExpressJS server side
First of all for our server it is necessary to import our dependencies and to set up the Cross origin :
//Importance of our dependencies 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()) // Implementation of Cross origin to avoid errors in 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() }) })
Then we will attack the configuration part of Multer so that the library knows where we want to upload the image and other parameters.
After the cross origin set up the Multer configuration:
// Creation of multer's diskStorage, it allows to define our upload configuration // /!\ Create the destination folders just in case before uploading var storage = multer.diskStorage({ // The file size limit limits: { fileSize: 1000000, //1Mo }, // The destination, here it will be at the root in the img folder. destination: function (req, file, cb) { cb(null, './img') }, // Error handling fileFilter(req, file, cb) { if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) { return cb(new Error('Le fichier doit etre un JPG')) } cb(undefined, true) }, // Function that renames the image filename: function (req, file, cb) { // Generate a random name and retrieve the old extension cb( null, Math.random().toString(36).substring(7) + '.' + file.originalname.split('.')[1], ) }, }) // Creation of the multer object const upload = multer({ storage: storage, })
You can read in the comments what each thing is used for, globally Multer allows us to choose a destination folder, to apply rules of limits and file extension, as well as to be able to rename the image.
Route POST of image reception
It is now necessary to set up our route which will receive our superb images, as well as to launch our server!
// Using the multer object as middleware // This means that first multer will upload our image, and then we go to the function of our /upload_image route. app.post('/upload_image', upload.single('img'), async (req, res) => { try { if (req.file) { // Uses the sharp library to resize to 200x100, and returns the thumbnail to another file in the destination folder chosen in the diskStorage. await sharp(req.file.path, { failOnError: false }) .resize({ width: 200, height: 100 }) .toFile( path.resolve(req.file.destination + '/thumbnail', req.file.filename), ) // You can use these variables to make insertions in databases or other applications 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('Server launch on port : ' + 3000) })
We created our route, set up the middleware that allows us to upload the image, and then we defined the function of the route as asynchronous for the resizing of our image.
After uploading the main image, Sharp will take it and resize it, in the example I put 200×100 but it is possible to set any value.
After resizing, Sharp puts our file in the destination folder of our main image in a thumbnail folder, thanks to the .toFile() method.
Here too you can choose any destination.
Then we can have access to the alternative text as well as the name of the image if we want to store this data in a database to display it under VueJS later!
This tutorial is now finished, thanks for reading and feel free to share 🙂