Skip to content

Using SDK v3 in the browser still uses NodeJS fs method #5009

@awaisabir

Description

@awaisabir

Checkboxes for prior research

Describe the bug

I am using the AWS v3 SDK in the browser, and it seems like the SDK does not recognize the environment it is running in. Naturally, in the browser there is no access to Node internals like fs, path, etc etc. However, it still seems to be searching for a file on the file system for credentials, even though it is being executed in the browser and I am providing it credentials.

I am providing credentials through my own custom endpoint, but when this code executes in my React application, the Webpack bundle builds fine, but fails at run-time with the following error:

Uncaught (in promise) TypeError: Cannot destructure property 'readFile' of 'fs_1.promises' as it is undefined.
    at ./node_modules/@aws-sdk/shared-ini-file-loader/dist-cjs/getSSOTokenFromFile.js (getSSOTokenFromFile.js:6:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@aws-sdk/shared-ini-file-loader/dist-cjs/index.js (index.js:7:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@aws-sdk/credential-provider-ini/dist-cjs/fromIni.js (fromIni.js:4:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@aws-sdk/credential-provider-ini/dist-cjs/index.js (index.js:4:1)

Why is my SDK in the browser calling fs methods? This doesn't make sense to me. Am I misunderstanding or missing something in the configuration?

SDK version number

@aws-sdk/client-cloudwatch:^3.358.0

Which JavaScript Runtime is this issue in?

Browser

Details of the browser/Node.js/ReactNative version

Chrome: 115.0.5790.102

Reproduction Steps

Webpack Config:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");

module.exports = {
  entry: path.resolve("src/index.tsx"),
  output: {
    path: path.resolve(__dirname, "../dist"),
  },
  module: {
    rules: [
      {
        test: /\.(png|woff|woff2|eot|ttf|svg)$/,
        loader: "url-loader",
        options: { limit: false },
      },
      {
        test: /\.tsx?$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.js$/,
        enforce: "pre",
        use: ["source-map-loader"],
        exclude: /node_modules/
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: "./public/index.html" }),
    new NodePolyfillPlugin(),
  ],
  resolve: {
    mainFields: ["browser", "main", "module"],
    extensions: [".tsx", ".ts", ".js"],
    fallback: {
      "fs": false,
      "child_process": false,
      "path": require.resolve("path-browserify"),
      "crypto": require.resolve("crypto-browserify"),
      "stream": require.resolve("stream-browserify"),
      "assert": require.resolve("assert"),
      "http": require.resolve("stream-http"),
      "http2": require.resolve("stream-http"),
      "https": require.resolve("https-browserify"),
      "os": require.resolve("os-browserify"),
      "url": require.resolve("url") 
    }
  },
};

TS File for Client:

import { CloudwatchClient } from "@aws-sdk/cloudwatch-client";

const getCredentials = async () => {
  const res = await fetch(`/credentials/endpoint`);
  const json = await res.json();

 return json();
}

export const initializeFooClient = async () => {
  const credentials = await getCredentials();

  const fooClient = new CloudwatchClient({
    region: "us-east-2",
    credentials: async () => {
      return {
        ...credentials
      };
    }
  });
  
  return { fooClient };
}};

React Component:

import { initializeFooClient } from "xyz";

const TestComponent = () => {
  useEffect(() => {
    const initalizeClient = async () => {
  
      // redacted the URL, but it does exist and works when I send a cURL request
      await initializeFooClient();
    };

    initalizeClient();
  }, []);

Observed Behavior

Get this error

Uncaught (in promise) TypeError: Cannot destructure property 'readFile' of 'fs_1.promises' as it is undefined.
    at ./node_modules/@aws-sdk/shared-ini-file-loader/dist-cjs/getSSOTokenFromFile.js (getSSOTokenFromFile.js:6:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@aws-sdk/shared-ini-file-loader/dist-cjs/index.js (index.js:7:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@aws-sdk/credential-provider-ini/dist-cjs/fromIni.js (fromIni.js:4:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@aws-sdk/credential-provider-ini/dist-cjs/index.js (index.js:4:1)

Why is my SDK v3 in the browser calling fs methods? Should it not know at run-time that it is running in a browser environment? Is there something wrong with my webpack configuration? The target for my webpack config is also defaulted to web.

Expected Behavior

It should initialize the SDK with the credentials I am providing, and should also know that it should not look for a file on the file system, as it is running in the browser 😕

Possible Solution

No response

Additional Information/Context

I have tried adding the following in my package.json, and it did not work:

  "browser": {
    "crypto": false,
    "fs": false,
    "path": false,
    "os": false,
    "net": false,
    "stream": false,
    "tls": false
  },

I have tried adding fallbacks in my webpack config, and that also does not work.

Metadata

Metadata

Assignees

Labels

bugThis issue is a bug.p2This is a standard priority issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions