Amplify-cli: [cli/@multi-dev] React Native metro bundler crashes on naming collision for rest endpoints

Created on 21 Jan 2019  路  5Comments  路  Source: aws-amplify/amplify-cli

Describe the bug
I'm working on a passwordless authentication flow. For that reason I did add some new rest api resources to my react-native app via the amplify cli. After I pushed the new resources to the AWS my package refuses to start the app.

Looking for JS files in
   /Users/timkuilman/brthrs/project

Loading dependency graph...(node:15580) UnhandledPromiseRejectionWarning: Error: jest-haste-map: @providesModule naming collision:
  Duplicate module name: verifyAuthChallengeResponse
  Paths: /Users/timkuilman/brthrs/project/amplify/#current-cloud-backend/function/verifyAuthChallengeResponse/src/package.json collides with /Users/timkuilman/brthrs/project/amplify/backend/function/verifyAuthChallengeResponse/src/package.json

This error is caused by a @providesModule declaration with the same name across two different files.
    at setModule (/Users/timkuilman/brthrs/project/node_modules/metro/node_modules/jest-haste-map/build/index.js:462:17)
    at workerReply (/Users/timkuilman/brthrs/project/node_modules/metro/node_modules/jest-haste-map/build/index.js:512:9)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:189:7)
(node:15580) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:15580) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:15580) UnhandledPromiseRejectionWarning: Error: jest-haste-map: @providesModule naming collision:
  Duplicate module name: verifyAuthChallengeResponse
  Paths: /Users/timkuilman/brthrs/project/amplify/#current-cloud-backend/function/verifyAuthChallengeResponse/src/package.json collides with /Users/timkuilman/brthrs/project/amplify/backend/function/verifyAuthChallengeResponse/src/package.json

This error is caused by a @providesModule declaration with the same name across two different files.
    at setModule (/Users/timkuilman/brthrs/project/node_modules/metro/node_modules/jest-haste-map/build/index.js:462:17)
    at workerReply (/Users/timkuilman/brthrs/project/node_modules/metro/node_modules/jest-haste-map/build/index.js:512:9)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:189:7)
(node:15580) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)

To Reproduce
Steps to reproduce the behavior:

I used the following flow to create the three lambda functions (createAuthChallenge, defineAuthChallenge and verifyAuthChallengeResponse)

-> amplify add api
-> Choose REST
-> Choose ' Create new Lambda Function'
-> Choose 'Serverless express function (Integration with Amazon API Gateway)'

After completing these (and some naming choosing steps) the packagers still starts. But when I run amplify push, the error pops up.

Expected behavior
I'd expect the react native metro bundler to start.

Screenshots
-

Smartphone (please complete the following information):

  • Device: Simulator
  • OS: iOS latest
  • Browser [e.g. stock browser, safari] n/a
  • Version n/a

Additional context
I am using the multi env cli for amplify.

bug

Most helpful comment

Just an update on this. If you are using RN 0.60.0 or above then you need to add these two lines to your metro.config.js

You are basically telling the metro bundler to ignore the #current-cloud-backend directory as it's simply a backup that amplify keeps track of locally and isn't used by your CLI.

const blacklist = require("metro-config/src/defaults/blacklist");

resolver: {
blacklistRE: blacklist([/amplify\/#current-cloud-backend\/.*/])
}

Here's what the completed file should look like:

/**
 * Metro configuration for React Native
 * https://github.com/facebook/react-native
 *
 * @format
 */

const blacklist = require("metro-config/src/defaults/blacklist");

module.exports = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: false
      }
    })
  },
  resolver: {
    blacklistRE: blacklist([/amplify\/#current-cloud-backend\/.*/])
  }
};

All 5 comments

@timkuilman There's a workaround for this provided out here - https://github.com/aws/awsmobile-cli/issues/172#issuecomment-455712263 Please take a look at this and let me know if you've any concerns regarding the approach

I initially did add rn-cli.config.js to the root of my project with the following content.

const blacklist = require('metro-config/src/defaults/blacklist');

// blacklist is a function that takes an array of regexes and combines
// them with the default blacklist to return a single regex.

module.exports = {
  resolver: {
    blacklistRE: blacklist([/amplify\/.*/])
  }
};

This configuration leaded to another problem: the amplify node packages could no longer be bundled. I changed the configuration a bit to make it work:

const blacklist = require('metro-config/src/defaults/blacklist');

// blacklist is a function that takes an array of regexes and combines
// them with the default blacklist to return a single regex.

module.exports = {
  resolver: {
    blacklistRE: blacklist([/amplify\/#current-cloud-backend\/.*/])
  }
};

For future reference: I came across https://stackoverflow.com/questions/41813211/how-to-make-react-native-packager-ignore-certain-directories describing how different versions of RN native require a slightly different rn-cli.config.js. I used the one for RN > 0.57.

Thank you @kaustavghosh06

Thanks for this, I was getting this error for every single REST api that Amplify generates.

Hi @kaustavghosh06, perhaps I don't understand how metro works very well, but does this mean that metro is trying to bundle backend code into the client application? If so, this seems like a serious problem. After all, how much sensitive data do people place in their backend code?

Hi @timkuilman, amplify-cli creates two copies of your backend code, and metro was complaining about collisions between these two copies. I would recommend excluding the entire amplify folder, not just part of it. Your first attempt created problems because the regex was matching amplify/* and excluding packages like aws-amplify in node_modules. To include the starting slash, use blacklistRE: /\/amplify\/.*/ However, I'm not convinced that this is a good long-tern solution, as it can cause future unintended matches.

Anyone know how to get the full path of each file or module that metro is processing?

Just an update on this. If you are using RN 0.60.0 or above then you need to add these two lines to your metro.config.js

You are basically telling the metro bundler to ignore the #current-cloud-backend directory as it's simply a backup that amplify keeps track of locally and isn't used by your CLI.

const blacklist = require("metro-config/src/defaults/blacklist");

resolver: {
blacklistRE: blacklist([/amplify\/#current-cloud-backend\/.*/])
}

Here's what the completed file should look like:

/**
 * Metro configuration for React Native
 * https://github.com/facebook/react-native
 *
 * @format
 */

const blacklist = require("metro-config/src/defaults/blacklist");

module.exports = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: false
      }
    })
  },
  resolver: {
    blacklistRE: blacklist([/amplify\/#current-cloud-backend\/.*/])
  }
};

Was this page helpful?
0 / 5 - 0 ratings