javascripttypescriptnext.jsamazon-cognito

Why is Next.js throwing Error: WEBPACK_IMPORTED_MODULE is not a function?


I'm unable to figure out the problem. I'm exporting a function that serves the current authenticated user object (if present). I'm then using this user object to determine the addition of a nav link. This error won't go away no matter how much I've reformed the reference.

This is the function definition @/app/hooks/use-auth-user.ts

'use client';
import {
    fetchAuthSession,
    fetchUserAttributes,
    getCurrentUser,
} from 'aws-amplify/auth';
import { useEffect, useState } from 'react';

export default function UseAuthUser() {
    const [user, setUser] = useState<Record<string, any>>();

useEffect(() => {
    async function getUser() {
        const session = await fetchAuthSession();
        if (!session.tokens) {
            return;
        }

        const user = {
            ...(await getCurrentUser()),
            ...(await fetchUserAttributes()),
            isAdmin: false,
        };

        const groups = session.tokens.accessToken.payload['cognito:groups'];
        // @ts-ignore
        user.isAdmin = Boolean(groups && groups.includes('administrators'));
        setUser(user);
    }

    getUser();
}, []);

return user;
}

And Here is the function that I'm referencing it from @/app/lib/menus.ts

import UseAuthUser from '@/app/hooks/use-auth-user';

export function getResourceMenu(): Menu {
const user = UseAuthUser();
let links: Menu = [
    { name: 'Privacy Policy', href: '/privacy' },
    { name: 'Terms & Conditions', href: '/terms-and-conditions' },
    { name: 'Member Portal', href: '/auth/login' },
];

if (user) {
    links.push({ name: 'Dashboard', href: '/dashboard' });
}

return links;
}

I'm attaching a screenshot of the error here:

Error: (0 , _app_hooks_use_auth_user__WEBPACK_IMPORTED_MODULE_0__.default) is not a function

This is the error output

I'd love some input on where I'm going wrong here because obviously - I am.


Solution

  • I tried to reproduce your issue and stumbled upon a different one. By resolving this one, I could run the code with no issues, which perhaps should solve your issue too.

    enter image description here

    The issue here is that use-auth-user hook is marked as a client-only module using use client. Which means it can be used only within client components.

    However, the getResourceMenu() function in menus.ts is calling UseAuthUser() directly, which is being treated as a server code, causing a mismatch.

    I moved on and refactored the code to make it run successfully to resolve this particular issue and it seems to resolve yours one as well.

    Moving the logic to a client component

    Here, UseAuthUser is called in a client component and the result is handed over to getResourceMenu instead of a direct hook call inside of getResourceMenu function.

    // src/components/MenuComponent.tsx
    'use client';  // Mark this as a client component
    import React from 'react';
    import UseAuthUser from '@/hooks/use-auth-user';
    import { getResourceMenu } from '@/lib/menus';
    
    const MenuComponent = () => {
        const user = UseAuthUser();  // Fetch user on the client side
        const links = getResourceMenu(user);  // Pass user data to getResourceMenu
    
        return (
            <nav>
                {links.map((link, index) => (
                    <a key={index} href={link.href}>
                        {link.name}
                    </a>
                ))}
            </nav>
        );
    };
    
    export default MenuComponent;
    

    Changes to getResourceMenu

    Just accepting user as an input and apply conditional rendering

    export function getResourceMenu(user: any) {
        let links = [
            { name: 'Privacy Policy', href: '/privacy' },
            { name: 'Terms & Conditions', href: '/terms-and-conditions' },
        ];
    
        if (user) {
            links.push({ name: 'Dashboard', href: '/dashboard' });
        }
    
        return links;
    }