angularamazon-web-servicesamazon-s3angular8angular15

Error uploading files to AWS S3 from Angular 15 with AWS SDK v2.1692.0: "Cannot find name 'Buffer'"


I've been using a block of code to upload images and documents from my Angular 8 application to my bucket in AWS S3 using "aws-sdk; v2.1237.0", which has been working fairly well without issue for a couple of years now:

import { Injectable } from '@angular/core';
import * as AWS from 'aws-sdk/global';
import * as S3 from 'aws-sdk/clients/s3';

@Injectable({
  providedIn: 'root'
})
export class UploadService {

  constructor() { }

  uploadImage(file: any) {
    const contentType = file.type;
    const bucket = new S3({
      accessKeyId: 'access-key',
      secretAccessKey: 'secret-access-key',
      region: 'region'
    });
    const fileName = 'images/' + file.name;
    const params = {
      Bucket: 'bucket',
      Key: fileName,
      Body: file,
      ACL: 'public-read',
      ContentType: contentType
    };
    bucket.upload(params, function(err: any, data: any){
      if (err) {
        console.log('There was an error uploading your file: ', err);
        return false;
      }
      console.log('Successfully uploaded file.', data);
      return true;
    });
  }

  uploadDoc(file: any) {
    const contentType = file.type;
    const bucket = new S3({
      accessKeyId: 'access-key',
      secretAccessKey: 'secret-access-key',
      region: 'region'
    });
    const fileName = 'documents/' + file.name;
    const params = {
      Bucket: 'bucket',
      Key: fileName,
      Body: file,
      ACL: 'public-read',
      ContentType: contentType
    };
    bucket.upload(params, function(err: any, data: any){
      if (err) {
        console.log('There was an error uploading your file: ', err);
        return false;
      }
      console.log('Successfully uploaded file.', data);
      return true;
    });
  }
}

I've recently upgraded to Angular 15, however running this code led me to the following errors, which seemingly go on endlessly:

Warning: /Users/N/Desktop/Angular/TEST00/src/app/services/upload/upload.service.ts depends on 'aws-sdk/clients/s3'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies



Error: ../../../../node_modules/aws-sdk/clients/acm.d.ts:153:37 - error TS2591: Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.

153   export type CertificateBodyBlob = Buffer|Uint8Array|Blob|string;
                                        ~~~~~~


Error: ../../../../node_modules/aws-sdk/clients/acm.d.ts:155:38 - error TS2591: Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.

155   export type CertificateChainBlob = Buffer|Uint8Array|Blob|string;
                                         ~~~~~~


Error: ../../../../node_modules/aws-sdk/clients/acm.d.ts:580:32 - error TS2591: Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.

580   export type PassphraseBlob = Buffer|Uint8Array|Blob|string;
                                   ~~~~~~

So as anyone would today, I turned to ChatGPT to bright out solutions which recommended installing @aws-sdk/client-s3 v3.750.0 and the following optimised code:

import { Injectable } from '@angular/core';
import { S3Client, PutObjectCommand, ObjectCannedACL } from '@aws-sdk/client-s3';

@Injectable({
  providedIn: 'root'
})
export class UploadService {
  private s3: S3Client;

  constructor() {
    this.s3 = new S3Client({
      region: 'region',
      credentials: {
        accessKeyId: 'access-key',
        secretAccessKey: 'secret-access-key'
      }
    });
  }

  async uploadFile(file: File, folder: string) {
    const fileName = `${folder}/${file.name}`;

    const params = {
      Bucket: 'bucket',
      Key: fileName,
      Body: file,
      ACL: ObjectCannedACL.public_read,
      ContentType: file.type
    };

    try {
      const command = new PutObjectCommand(params);
      const response = await this.s3.send(command);
      console.log('Successfully uploaded:', response);
      return response;
    } catch (err) {
      console.error('Error uploading file:', err);
      throw err;
    }
  }
}

Which now gives the following error while trying to upload the file

Error uploading file: TypeError: readableStream.getReader is not a function

Where exactly am I going wrong in here? Is there a way I could maintain my old code which was well tried and tested in several projects, or how do I make the new more optimised code work?


Solution

  • If you need a hot fix, just add to client constuctor requestChecksumCalculation: "WHEN_REQUIRED"

      const client = new S3({
        // ... other params
        requestChecksumCalculation: "WHEN_REQUIRED",
      });
    
    

    For more details see The GitHub issue about this bug