4

I am trying to programmatically upload a file (and some fields) from the render process of an Electron application. I am using the form-data and axios packages for this purpose.

The code is TypeScript and, at its simplest, it looks like:

import axios from 'axios';
import fs from 'fs';
import FormData from 'form-data';

function upload(url: string, file: string, additionalFieldValue: string): void {
  const f = new FormData();
  f.append('additionalField', additionalFieldValue);
  f.append(file, fs.createReadStream(file));
  axios.post(url, f, {
    headers: f.getHeaders(),
  });
}

The problem I run into is that f is always a native FormData object instead of FormData object of the type declared in the form-data package. As a consequence, it generates a TypeError: f.getHeaders is not a function error.

The same thing happens if I change the import statement to:

import SomeFormDataThatIsNotNative from 'form-data';

or if I try to use an alias:

import * as SomeFormDataThatIsNotNative from 'form-data';

and invoke the constructor like:

   const f = new SomeFormDataThatIsNotNative();

I need help understanding why instantiating one type of object (FormData declared in the form-data package) results in a different type of object (native FormData). What am I doing wrong? Do I have to move the code in the main process? What would work in the renderer process?

Tibi
  • 439
  • 7
  • 15

1 Answers1

3

It's not truly a solution, more of a workaround, but it works.

I have moved the upload function from the renderer process to the main process. This changes the context from running in the browser to running under Node.

In the renderer process I have replaced the upload with


import { ipcRenderer } from 'electron';

async function upload(url: string, file: string, additionalFieldValue: string) {
  return ipcRenderer('upload', url, file, additionalFieldValue);
}

In the main process I have added the following:

import axios from 'axios';
import FormData from 'form-data';
import { ipcMain } from 'electron';

ipcMain.handle('upload', async (event, url, file, additionalFieldValue) => {
  const f = new FormData();
  f.append('additionaField', additionalFieldValue);
  f.append(file, fs.createReadStream(file));
  return axios.post(url, f, {
    headers: f.getHeaders(),
  });
});

I would still like to understand why it did not work with the code in the renderer process only, but for now, I can move forward.

Tibi
  • 439
  • 7
  • 15