nuxt: AWS Amplify generates runtime crash

Environment


  • Operating System: Windows_NT
  • Node Version: v16.13.1
  • Nuxt Version: 3.0.0-27366343.1d741cb
  • Package Manager: yarn@1.22.17
  • Bundler: Vite
  • User Config: publicRuntimeConfig, typescript, css, buildModules
  • Runtime Modules: -
  • Build Modules: @vueuse/nuxt@7.5.3

Reproduction

I tried to provide a minimal reproduction in this sandbox instance, although I cannot really understand how it works. Refer to https://github.com/nuxt/nuxt.js/issues/13277.

I’m providing in that environment some testing configurations for the convenience of the developers, I will shut them down when the problem is solved.

Describe the bug

When using @aws-amplify/auth for connecting to an AWS Cognito user pool, nuxt provides a runtime error very hard to debug. (See below).

In general, it would be very nice to have a more informative stacktrace about these kinds of issues.

Additional context

No response

Logs

Stacktrace of the bug

Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'C:\Users\..\repo\url' imported from C:\Users\..\repo\.nuxt\dist\server\server.mjs
    at new NodeError (node:internal/errors:371:5)
    at finalizeResolution (node:internal/modules/esm/resolve:416:11)
    at moduleResolve (node:internal/modules/esm/resolve:932:10)
    at defaultResolve (node:internal/modules/esm/resolve:1044:11)
    at ESMLoader.resolve (node:internal/modules/esm/loader:422:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:222:40)
    at ESMLoader.import (node:internal/modules/esm/loader:276:22)
    at importModuleDynamically (node:internal/modules/esm/translators:111:35)
    at importModuleDynamicallyCallback (node:internal/process/esm_loader:35:14)
    at $id_28e5ebab (file:///C:/Users/../repo/.nuxt/dist/server/server.mjs:13500:233) {
  code: 'ERR_MODULE_NOT_FOUND'
}

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 23 (10 by maintainers)

Most upvoted comments

I finally was able to solve the issue, thanks to https://github.com/nuxt/framework/discussions/2308, to https://github.com/nuxt/nuxt.js/issues/12803, and to nuxt3 docs, I’ll summarize the solution here, of which you can see a minimal reproduction in this sandbox environment.

Step 1 - Polyfill definition:

Include a polyfill like in https://github.com/nuxt/nuxt.js/issues/12803, (a typical location is public/js/polyfill.js, but any other is fine as long as you update the paths accordingly) with the following content:

// public/js/polyfill.js
if (global === undefined) {
    var global = window;
}

Step 2 - Polyfill inclusion:

Include the polyfill as a loaded script at the main entry point of your app, a typical example is shown here for a basic app.vue:

<!-- app.vue -->
<template>
  <div>
    <Script src="./js/polyfills.js" />
    <!-- content here --> 
  </div>
</template>

Step 3 - Plugin setup:

Add the information for setting up an Amplify plugin. The following shows a typical usage for just the Auth module of Amplify, other can be added similarly. Note also that this steps assumes an aws-exports.ts file at the root of your nuxt3 app containing the settings for Amplify, an example can be found in the sandbox environment at the beginning of this post, otherwise refer to the official Amplify documentation for the details.

// plugins/amplify.ts
import { defineNuxtPlugin } from '#app';

import awsConfig from '../aws-exports';
import { Amplify } from '@aws-amplify/core';
import { Auth } from '@aws-amplify/auth';

export default defineNuxtPlugin(nuxtApp => {
    Amplify.configure(awsConfig);

    return {
        provide: {
            auth: Auth,
        },
    };
});

Step 4 - Transpiling/aliasing libraries:

Set the nuxt config to alias the amplify libraries of aws-amplify:

// nuxt.config.ts
export default defineNuxtConfig({
    // ... 
    alias: {
      // 'aws-amplify': 'aws-amplify/lib/',
      '@aws-amplify/core': '@aws-amplify/core/lib',
      '@aws-amplify/auth': '@aws-amplify/auth/lib',
        './runtimeConfig': './runtimeConfig.browser',
    },
    // ... 
})

That’s it for the setup, now it can be used in various way. Note, however, as pointed out in https://github.com/nuxt/framework/discussions/2308, that plugin dependencies might not be available at setup time, so two usages approach can be considered. I show here an example for an authenticated variable from mt-u in a classical vue style and in a more idiomatic composable style.

Approach 1: onMounted()

<!-- app.vue -->
<script setup lang="ts">
const { $auth } = useNuxtApp();

const authenticated = ref(false);     // then {authenticated} can be used in component's <template>

onMounted(async function () {
  authenticated.value = !!(await $auth.currentAuthenticatedUser());
});
</script>

Approach 2: composable

// composables/useIsAuthenticated.ts
export default function () {
  const { $auth } = useNuxtApp();

  const isAuthenticated = useState('authenticated', () => false);

  return {
    isAuthenticated,
    refresh: async () => {
      isAuthenticated.value = !!(await $auth.currentAuthenticatedUser());
    },
  };
}

which can then be used in components in the following way:

<!-- component.vue -->
<script setup lang="ts">
const isAuthenticated = useIsAuthenticated()
</script>

I’ll close the issue here, I recommend to continue on the related discussion https://github.com/nuxt/framework/discussions/2308, in case of other issues.

Hi, I am having the exact same issue. Not only the url but several packages that come from amplify are not properly resolved.

Thanks again! The Authenticator component works fine, but I have not been able to update my own components when the connection status changes. From the source code there seems to be an AmplifyEventBus, I’ll check if this can be used.

@markovickosta Thanks for this fix!

vite: {
	define: {
		'window.global': {} // Amplify fix, pt. 2
	},
},

This was all I needed to get API.graphql working properly. I defined it inside a client-only plugin to avoid any server-side issues, especially since I’d only be using GraphQL on the client side.

plugins/graphql.client.ts

import { API } from 'aws-amplify';

export default defineNuxtPlugin(() => {
  return {
    provide: { API },
  };
});

@ennioVisco Thank you very much for trying to reproduce my error and helping me out!

@ennioVisco I have managed to host it as SSG without a problem, but I still get this error when running ‘npm run dev’:

[nuxt] [request error] Identifier 'module' has already been declared
  at ESMLoader.moduleStrategy (node:internal/modules/esm/translators:139:18)  
  at ESMLoader.moduleProvider (node:internal/modules/esm/loader:236:14)  
  at async link (node:internal/modules/esm/module_job:67:21)

Things I have changed:

"@aws-amplify/auth": "^4.5.8",
"@aws-amplify/core": "^4.5.8",

and

//plugins/amplify.ts
import { Amplify } from '@aws-amplify/core';
import { Auth } from '@aws-amplify/auth';

@markovickosta I checked and tried to reproduce it here: https://codesandbox.io/s/long-resonance-hcodk3?file=/nuxt.config.ts

It seems that when you don’t have ssr: false in your nuxt.config.ts it doesn’t work. However, having ssr means that you are running via node on some server, which in that case it probably doesn’t need the whole alias block in the configs at least… I never explored that case tbh… Note that in SSG you must have ssr: false.

@ennioVisco I still have problems with the same issue as them. I created the same polyfill as you mentioned in #2874 (comment) My plugin looks like this:

import { defineNuxtPlugin } from '#app';
import awsconfig from '../aws-exports';
import { Amplify, Auth } from 'aws-amplify';

export default defineNuxtPlugin(nuxtApp => {
	Amplify.configure(awsconfig);

	return {
		provide: {
			auth: Auth,
		},
	};
});

My nuxt.config.ts:

alias: { // Amplify fix, pt. 1
	'./runtimeConfig': './runtimeConfig.browser'
},

vite: {
	define: {
		'window.global': {} // Amplify fix, pt. 2
	},
},

And my package.json:

{
	"private": true,
	"scripts": {
		"build": "nuxt build",
		"dev": "nuxt dev",
		"generate": "nuxt generate",
		"preview": "nuxt preview"
	},
	"devDependencies": {
		"@iconify-json/ic": "^1.1.4",
		"@nuxtjs/google-fonts": "^1.3.0",
		"@nuxtjs/tailwindcss": "^5.1.2",
		"nuxt": "^3.0.0-rc.4",
		"sass": "^1.53.0",
		"unplugin-icons": "^0.14.3"
	},
	"dependencies": {
		"@pinia/nuxt": "^0.1.9",
		"aws-amplify": "^4.3.26",
		"pinia": "^2.0.14"
	}
}

When I run ‘npm run dev’ I get the following error:

[nuxt] [request error] Identifier 'module' has already been declared
  at ESMLoader.moduleStrategy (node:internal/modules/esm/translators:139:18)  
  at ESMLoader.moduleProvider (node:internal/modules/esm/loader:236:14)  
  at async link (node:internal/modules/esm/module_job:67:21)

I can run ‘npm run build’ and ‘npm run preview’ after, without any problems. BUT when I try to publish that to amplify hosting I get “AccessDenied”.