How can I use aws-iot-device-sdk NPM module with Angular 11 ? (it throws fs, path, & tls errors on build)

Viewed 1013

I maintain an browser-based Angular app that was at version 5.6. This app has two components that subscribe to an IOT topic and listen for updates (no pub, just sub).

We need to upgrade to Agnular 11.0.3. I have completed that work. But now the aws-iot-device-sdk NPM module caucuses these errors when I try to run the local web server or run a build:

Error: Can't resolve 'fs' in '[PATH_TO]/node_modules/aws-iot-device-sdk/common/lib'
Error: Can't resolve 'path' in '[PATH_TO]/node_modules/aws-iot-device-sdk/device'
Error: Can't resolve 'fs' in '[PATH_TO]/node_modules/aws-iot-device-sdk/device'
Error: Can't resolve 'tls' in '[PATH_TO]/node_modules/aws-iot-device-sdk/device/lib'

I have spent many hours pulling my hair out on this issue. Our front-end (browser) IOT code has been working perfectly for the last few years. But the upgrade to Angular 11.0.3 has to happen and this issue is a big blocker.


SAMPLE CODE FROM OUR APPLICATION:

(Our package.json is at the end)

The xxxx-app.component.ts file:


import { AwsIotService } from '../../shared/awsIot/awsIot.service';

this.awsIotService.getNewIotConnection(this.iotTopic, this.iotUrl, (iotClient) => {
    //cache the iotClient
    this.iotClient = iotClient;

    //handle the iotClient's message event
    iotClient.on('message', (topic, message) => {
        // process the message here:
        console.log('IOT Message received:');
        console.dir(message);
    });
});

awsIotService.ts:

In the code below, "iotUrl" points to a custom service we wrote that provides the details needed by the browser-based Angular app in order to connect and subscribe:

awsIot = require('aws-iot-device-sdk'); //simply requiring that NPM module causes the errors stated above

getNewIotConnection (topic, iotUrl, callback) {
    this.httpClient.get(iotUrl).subscribe(responseData => {

         const client = this.awsIot.device({
                port: 443,
                protocol: 'wss',
                region: responseData.region,
                host: responseData.iotEndpoint,
                secretKey: responseData.secretKey,
                accessKeyId: responseData.accessKey,
                sessionToken: responseData.sessionToken,
            });

            // subscribe to the topic
            client.on('connect', () => client.subscribe(topic));

            // call the callback
            callback(client);
     });
}

UP-TO-DATE SUGGESTIONS THAT I HAVE TRIED:

1 - I have tried using https://www.npmjs.com/package/aws-iot-device-sdk-v2

....but have not found the documentation helpful... I hope I am missing something here.

2 I have tried AWS amplify and followed this tutorial:

https://docs.amplify.aws/start/getting-started/installation/q/integration/angular

...but using AWS amplify to solve this issue would require a re-work of the back-end we built and seems like getting a new transmission for a flat tire (i.e. just need to subscribe to an IOT topic).


OLDER WORKAROUNDS THAT I HAVE TRIED:

3 I tried adding this to package.json:

"browser": {
  "fs": false,
  "path": false,
  "os": false
}

...that did not work.

4 I tried adding this to package.json:

"dependencies": {
  ...other packages
  "mqtt": "2.15.1",
  "minimist": "1.2.0",
  "websocket-stream": "^5.0.1",
  "crypto-js": "3.1.6"
}

...that did not work.

5 I tried the patch.js approach detailed here:

https://gist.github.com/niespodd/1fa82da6f8c901d1c33d2fcbb762947d

...that did not work.

6 I tried adding this to webpack.config.js :

resolve: {
  fallback: {
    fs: false
  }
}

...that did not work.

7 I tried adding this to webpack.config.js :

node: {
  fs: 'empty'
}

...that did not work (only works in older WebPack.)


Our package.json (just dependencies & devDependencies):

  "dependencies": {
    "@angular/animations": "^11.0.3",
    "@angular/cdk": "^11.0.1",
    "@angular/common": "^11.0.3",
    "@angular/core": "^11.0.3",
    "@angular/forms": "^11.0.3",
    "@angular/platform-browser": "^11.0.3",
    "@angular/platform-browser-dynamic": "^11.0.3",
    "@angular/router": "^11.0.3",
    "@mapbox/mapbox-gl-draw": "^1.2.0",
    "@mapbox/mapbox-gl-geocoder": "^2.2.0",
    "@ng-bootstrap/ng-bootstrap": "^8.0.0",
    "@turf/helpers": "^6.0.0",
    "@turf/inside": "^5.0.0",
    "@turf/turf": "^5.1.6",
    "@types/lodash": "^4.14.165",
    "@types/unist": "^2.0.0",
    "angular-calendar": "^0.28.22",
    "aws-iot-device-sdk": "^2.2.6",
    "core-js": "^3.6.4",
    "date-fns": "^2.16.1",
    "intl": "^1.2.4",
    "jquery": "^3.1.1",
    "lodash": "^4.17.20",
    "mapbox-gl": "^2.0.0",
    "moment": "^2.12.0",
    "moment-timezone": "^0.5.27",
    "ng2-datepicker": "^3.1.1",
    "rxjs": "^6.5.4",
    "rxjs-compat": "^6.6.3",
    "selenium-webdriver": "^3.6.0",
    "tslib": "^2.0.0",
    "zone.js": "^0.11.3"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.1100.3",
    "@angular/cli": "^11.0.3",
    "@angular/compiler": "^11.0.3",
    "@angular/compiler-cli": "^11.0.3",
    "@ngtools/webpack": "^11.0.3",
    "@types/jasmine": "^3.6.2",
    "@types/jquery": "^2.0.34",
    "@types/node": "^14.14.10",
    "@webpack-cli/serve": "^1.1.0",
    "angular-router-loader": "^0.8.5",
    "angular2-template-loader": "^0.6.2",
    "codelyzer": "^6.0.0",
    "copy-webpack-plugin": "^6.3.2",
    "cross-env": "^7.0.3",
    "css-loader": "^5.0.1",
    "exports-loader": "^1.1.1",
    "html-loader": "^1.3.2",
    "html-webpack-plugin": "^4.5.0",
    "jasmine-core": "^3.6.0",
    "jasmine-spec-reporter": "^5.0.0",
    "karma": "^5.2.3",
    "karma-chrome-launcher": "^3.1.0",
    "karma-coverage": "^2.0.3",
    "karma-coverage-istanbul-reporter": "^3.0.3",
    "karma-jasmine": "^4.0.1",
    "karma-jasmine-html-reporter": "^1.5.4",
    "karma-mocha-reporter": "^2.2.5",
    "mini-css-extract-plugin": "^1.0.0",
    "postcss": "^8.1.13",
    "postcss-import": "^13.0.0",
    "postcss-loader": "^4.1.0",
    "postcss-nested": "^5.0.2",
    "protractor": "^7.0.0",
    "raw-loader": "^1.0.0",
    "rimraf": "^3.0.2",
    "retyped-stripe-tsd-ambient": "^0.0.0-0",
    "sass": "^1.29.0",
    "sass-loader": "^10.1.0",
    "script-ext-html-webpack-plugin": "^2.1.5",
    "style-loader": "^2.0.0",
    "to-string-loader": "^1.1.6",
    "ts-loader": "^8.0.11",
    "ts-node": "^8.3.0",
    "tslint": "^6.1.0",
    "typescript": "4.0.3",
    "webpack": "^5.9.0",
    "webpack-cli": "^4.2.0",
    "webpack-dev-server": "^3.11.0"
  },
2 Answers

Does this help? The author seemed to have/avoid the same trouble as you. He mentions:

   "browser": {
       "fs": false,
       "tls": false,
       "path": false
   },

I'm using the following environment:

Angular CLI: 12.2.13
Node: 16.13.0 (Unsupported)
Package Manager: npm 8.1.0
OS: linux x64

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1202.13
@angular-devkit/build-angular   12.2.13
@angular-devkit/core            12.2.13
@angular-devkit/schematics      12.2.13
@angular/cdk                    12.2.12
@schematics/angular             12.2.13
ng-packagr                      12.2.5
rxjs                            6.6.7
typescript                      4.3.5

And in order to complement the approach of @kackle123, the following worked for me in package.json:

"browser": {
    "http": false,
    "https": false,
    "net": false,
    "path": false,
    "stream": false,
    "tls": false,
    "fs": false
}

But it only mute the error outputs, and the package will not work anyways.

Related