0

I am working on a FileUploader ( Images for now) which will enable the user to upload multiple files to the backend server in one go.

I have the following setup

  1. Webpack configured with url-loader supporting all kinds of images.
  2. I have a React client running on port 9002 inside separate directory called client. This has a component called "UploadDocumentsContainer". This component will let user select multiple input files to upload. The component makes axios call to backend server at end-point "/uploads".
  3. A Backend node server is running one directory up then client directory running on port 9001. It has a uploads endpoint configured to cater to the uploaded images. The server moves the images to /client/public/uploads and send the response back to client with fileName and filePath of the image.
  4. The React client also has a Separate component called ProgressFileUpload which gets fired up once upload starts from 0 to 100% depending on the upload status.

The Problem So far is as follows.

  1. The image gets successfully uploaded to server and we get the 200 response back from server with the fileName and filePath of the image.
  2. But during rendering the same uploaded images using DisplayFile component the app crashes with following error.

I have been trying to get this working since last 3 days . I have gone through lots of github and stackoverflow post but didnt find the solution for the same. I will really appreciate if i can get some input/feedback/solution on the same.

My Guess is that there is something wrong with my Webpack.configs (publicPath or url-loader) or the filePath of the images is not pointing in the right direction after bundle is made.

The above error occurred in the component: in DisplayFile (created by UploadDocumentsContainer) in form (created by UploadDocumentsContainer) in div (created by UploadDocumentsContainer) in div (created by UploadDocumentsContainer) in div (created by UploadDocumentsContainer) in UploadDocumentsContainer

Error: Cannot find module './wallpaper-1680x1050.jpg' bundle.js line 96 > eval:14:11
TypeError: _context.t0.response is undefined

Sandbox link is throwing error "Request failed with status code 422"

GITHUB LINK:- https://github.com/aryan21710/FileUploader.git

Webpack.config.js:-

const path = require("path");
const webpack = require("webpack");
const dotenv=require("dotenv");


module.exports = () => {
     // call dotenv and it will return an Object with a parsed key 


  return {
    mode: "development",
    // babel-polyfill allows us to use all the latest es7 javascript features like Array.includes , Array.from and so on
    // 
    entry: ["babel-polyfill", path.join(__dirname, "client/src/app.js")],
    devServer: {
      proxy: {
        "/client/public/uploads/": "http://localhost:9001"
      },
      // index.html will be inside build and not dist after installing htmlWebpackPlugin.
      contentBase: path.join(__dirname, "client", "public", "build"),
      hot: false,
      inline: true,
      historyApiFallback: true,
      watchContentBase: true,
      port: 9002,
      watchOptions: {
        ignored: [
          path.resolve(__dirname, "fileUploadServer/server.js"),
          path.resolve(__dirname, "node_modules/")
        ]
      }
    },
    output: {
      path: path.join(__dirname, "client", "public", "build"),
      // Will generate a new bundle.js with name "main.somerandomhash.bundle.js" every time when app changes.
      filename: "bundle.js",
    },
    module: {
      rules: [
        {
          loader: "babel-loader",
          test: /\.js$/,
          exclude: /node_modules/
        },
        {
          test: /\.s?css$/,
          use: ["style-loader", "css-loader", "sass-loader"]
        },
        {
          test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg|jpg)$/,
          loader: "url-loader",

        }
      ]
    },
    devtool: "cheap-module-eval-source-map"
  };
};

UploadDocumentsContainer.js:-

import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import axios from "axios";
import ProgressFileUpload from "./ProgressFileUpload";

const UploadDocumentsContainer = () => {
  const [selectedFile, setSelectedFile] = useState("Choose File");
  const [displayFile, setDisplayFile] = useState([]);
  const [file, setFile] = useState([]);
  const [uploadPercentage, setUploadPercentage] = useState(0);





  const onChangeFile = event => {
    console.log("event.target.files", event.target.files[0]);

    for (let i = 0; i < event.target.files.length; i++) {
      let _ = event.target.files[i];
      setFile(file => [...file, _]);
    }
    event.target.files.length > 1
      ? setSelectedFile(`${event.target.files.length} Files`)
      : setSelectedFile(event.target.files[0].name);
  };

  const onUpload = async e => {
    e.preventDefault();
    console.log("file", file);
    console.log("selectedFile", selectedFile);
    const formData = new FormData();
    file.forEach(_ => {
      console.log("_", _);
      formData.append("file", _);
    });
    console.log("FORMDATA INSIDE UploadDocumentsContainer", formData);

    try {
      const response = await axios.post(
        "http://localhost:9001/client/public/uploads",
        formData,
        {
          headers: {
            "Access-Control-Allow-Origin": "*",
            "Content-type": "multipart/form-data"
          },
          onUploadProgress: progressEvent => {
            setUploadPercentage(
              parseInt(
                Math.round((progressEvent.loaded * 100) / progressEvent.total)
              )
            );

            // Clear percentage
            setTimeout(() => setUploadPercentage(0), 10000);
          }
        }
      );

      let { fileName, filePath } = response.data;
      console.log("response.data", response.data);
      fileName = fileName.split(",");
      filePath = filePath.split(",");
      console.log("fileName", fileName);
      console.log("filePath", filePath);

      setDisplayFile(displayFile => [...displayFile, ...fileName]);
      console.log(
        "displayFile from the server",
        displayFile,
        ":",
        displayFile.length
      );
      console.log("response back from server:-", fileName, " AND ", filePath);

      // const importAll = r => {
      //   return r.keys().map(r);
      // };

      // setImages(
      //   importAll(
      //     require.context(
      //       "./../../../../../../../public/uploads/",
      //       false,
      //       /\.(png|jpeg|svg|jpg)$/
      //     )
      //   )
      // );
    } catch (error) {
      if (error.response.status == 500) {
        console.log("There was a problem with the server");
      } else {
        console.log(error.response.data.msg);
      }
    }
  };

  const DisplayFile = () => {
    console.log("displayFile", displayFile);
    console.log("uploadPercentage", uploadPercentage);
    return (
      <div className="displayFileContainer">
        {displayFile.length > 0
          ? displayFile.map((_, idx) => {
              const myimg = require(`./../../../../../../../public/uploads/${_}`)
                .default;
              console.log("myimg", myimg);
              return (
                <div className="fileDimension" key={idx}>
                  <img src={myimg} />
                </div>
              );
            })
          : null}
      </div>
    );
  };

  return (
    <div className="formOuterWrapper">
      <div className="formInnerWrapper">
        <div className="fileUploadContainer">
          <form className="fileUploadForm " name="myForm" onSubmit={onUpload}>
            <div className="custom-file mb-5">
              <input
                type="file"
                multiple
                className="custom-file-input"
                id="customFile"
                onChange={onChangeFile}
              />
              <label className="custom-file-label" htmlFor="customFile">
                {selectedFile}
              </label>
            </div>

            <div className="progressbar">
              <ProgressFileUpload percentage={uploadPercentage} />
            </div>

            <input
              type="submit"
              value="Upload"
              className="btn btn-primary btn-block mt-5"
            />
            <DisplayFile />
          </form>
        </div>
      </div>

    </div>
  );
};

export default UploadDocumentsContainer;

Backend FILE Server(fileUploadServer):-

const express = require("express");
const fileUpload = require("express-fileupload");
const morgan = require("morgan");

const app = express();
const path = require("path");
const cors = require("cors");
const port = 9001;
const publicPath = path.join(__dirname, "..", "client", "public");
// eslint-disable-next-line no-console
console.log("publicpath", publicPath);
app.use(express.static(publicPath));
app.use(cors());
app.use(fileUpload());
app.use(morgan("dev"));

app.post("/client/public/uploads", (req, res) => {
  if (req.files === null) {
    return res.status(400).json({ msg: "NO FILE UPLOADED" });
  }



  const filename = [],
    filepath = [];
  if (Object.keys(req.files.file).includes("name")) {
    const file = req.files.file;
    filename.push(file.name);
    filepath.push(`${publicPath}/uploads/${file.name}`);
    file.mv(`${publicPath}/uploads/${file.name}`, err => {
      if (err) {
        console.log("err while moving the file to different directory", err);
        return res.status(500).send(err);
      }
    });
  } else {
    for (let i in req.files.file) {
      const file = req.files.file[i];
      filename.push(file.name);
      filepath.push(`${publicPath}/uploads/${file.name}`);
      console.log("INSIDE UPLOADS", file.name);
      file.mv(`${publicPath}/uploads/${file.name}`, err => {
        if (err) {
          console.log("err while moving the file to different directory", err);
          return res.status(500).send(err);
        }
      });
    }
  }

  console.log(filename, "::::", filepath);

  res.json({ fileName: `${[filename]}`, filePath: `${filepath}` });
});
app.listen(port, () => {
  // eslint-disable-next-line no-console
  console.log(`SERVER IS LISTENING ON PORT ${port}`);
});

Directory Structure:-

enter image description here

ryan
  • 694
  • 9
  • 23
  • During the first upload, the image is uploaded on server but render on client fails and no progress bar is shown either nor the image. But for the same image during second upload, everything works smoothly. – ryan Mar 25 '20 at 17:42
  • The app crashes at the following culprit line inside DisplayFile component inside UploadDocumentsContainer.js ---> const myimg = require(`./../../../../../../../public/uploads/${_}`) – ryan Mar 25 '20 at 18:05
  • Is the require supposed to be '../../../public/uploads/${_}' ?? It looks like your going up like 7 levels, which doesn't seem right from your file structure. Your are 3 levels deep inside the client folder, so go up three levels and you should be on the same level as public, then you can drill down to the uploads directory. – djs Mar 26 '20 at 03:57
  • My bad the current require statement in my existing app is `'../../../public/uploads/${_}` which was giving error. require(./../../../../../../../public/uploads/${_}) was referencing the old directory structure which i trimmed before posting the query. – ryan Mar 26 '20 at 06:53
  • Got it working with both Webpack and without webpack. In case of webpack, I was trying to access the image using its file name and file,path which was sent as a response by the server. But the url-loader was expecting an image in the form of url (http://localhost:9002/uploads/filename.ext) . After adding a GET endpoint on the backend server for /uploads/* which returns the file in the form of req.params[0], i was able to upload and view multiple images. – ryan Mar 27 '20 at 12:03

0 Answers0