Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can not import ESM bundle for browser with NextJS 14 #418

Closed
tembra opened this issue Feb 7, 2024 · 4 comments
Closed

Can not import ESM bundle for browser with NextJS 14 #418

tembra opened this issue Feb 7, 2024 · 4 comments
Assignees

Comments

@tembra
Copy link

tembra commented Feb 7, 2024

Issue Description

When importing Human on a NextJS 14 project, the framework tries to import the node bundle instead of ESM for browsers, despite adding 'use client' on top of the page file.

Since node bundle requires a tfjs backend, the error below comes in:

./node_modules/@vladmandic/human/dist/human.node.js:7:1678
Module not found: Can't resolve '@tensorflow/tfjs-node'

I know that this is not an issue within the Human package at all and it's about NextJS SSR. However I guess you may help me to achieve the desired solution.

I already tried to load Human within a separated dynamic loaded component with dynamic(() => import('@/components/Human'), { ssr: false }), but it also did not work.

I also tried to import it inside a useEffect of the Human component created as you did in your class constructor in NextJS demo, but it also did not work.

I also tried to import Human explicitly from @vladmandic/human/dist/human.esm but it did not found the path.

Everything works fine if I use Vite instead of NextJS to create my project.

Steps to Reproduce

  1. Create a new project with npx create-next-app app-name and choose all default configs.
  2. Run npm i
  3. Change app/page.tsx to add 'use client' on top the file and add import to Human import { Human } from '@vladmandic/human.
  4. Run npm run dev
  5. Access the URL on your browser

Expected Behavior

NextJS identify that I'm using a client component on that page and load ESM bundle of Human package instead of node bundle.

Environment

  • Human library version? 3.2.0
  • Built-in demo or custom code? Custom code. Just create a project and import Human.
  • Type of module used (e.g. js, esm, esm-nobundle)? esm
  • TensorFlow/JS version (if not using bundled module)?
  • Browser or NodeJS and version (e.g. NodeJS 14.15 or Chrome 89)? Arc 1.28.0
  • OS and Hardware platform (e.g. Windows 10, Ubuntu Linux on x64, Android 10)? macOS 14.2.1 on M2 Pro (arm64)
  • Packager (if any) (e.g, webpack, rollup, parcel, esbuild, etc.)?
  • Framework (if any) (e.g. React, NextJS, etc.)? NextJS

Diagnostics

Additional

  • For installation or startup issues include your package.json
  • For usage issues, it is recommended to post your code as gist
  • For general questions, create a discussion topic
@jpieters
Copy link

jpieters commented Feb 9, 2024

can you share the code? I had some issues at first with Next.js 14, but got it working. Ensure that you are explicitly using the "use client"; where appropriate.

@tembra
Copy link
Author

tembra commented Feb 10, 2024

@jpieters You can check the issue/example of the code in this repo: https://github.com/tembra/human-nextjs-14

There I tried many ways to load Human, each one in a specific intuitive named route, and they all fail.

  • http://localhost:3000/ default way
  • http://localhost:3000/no-ssr
  • http://localhost:3000/lazy-loaded
  • http://localhost:3000/load-on-button-click

Notice that even on /load-on-button-click the error occurs during the build time. It seems that TypeScript/NextJS is executing the code inside the callback function that is assigned to a variable, but never called.

Even if NextJS is pre-rendering client components/pages on the server for the initial page load, it does not makes sense that this function is being executed.

Said that I think that import keyword is the problem, with TypeScript/NextJS trying to immediately find/import the module during the build time. Thinking this way I also tried to use (and also change/adapt) the webpack configuration from next.config.js of the human-next demo.

If you can share how you got it working it will be awesome. I'm really out of ideas.

@tembra
Copy link
Author

tembra commented Feb 10, 2024

After digging deeper on webpack configuration I managed to get it working using this next.config.mjs configuration:

/** @type {import('next').NextConfig} */
const nextConfig = {
    webpack: (config, { webpack, isServer }) => {
        if (isServer) {
            config.plugins.push(
                new webpack.IgnorePlugin({
                    checkResource(resource) {
                        if (resource === '@vladmandic/human') {
                            // ignore human package on server
                            return true
                        }

                        return false
                    },
                })
                // or a shorter (but not too explicit) version
                // new webpack.IgnorePlugin({ resourceRegExp: /^@vladmandic\/human$/ })
            )
        }

        return config
    }
}

export default nextConfig

With this configuration all my examples of the shared code work.

However I obviously got the error below during page compiling. So this is not the correct approach.

$ npm run dev

> human-nextjs-14@0.1.0 dev
> next dev

   ▲ Next.js 14.1.0
   - Local:        http://localhost:3000

 ✓ Ready in 6s
 ○ Compiling / ...
 ✓ Compiled / in 8.4s (477 modules)
 ⨯ Error: Cannot find module '@vladmandic/human'
    at webpackMissingModule (./app/page.tsx:7:50)
    at eval (./app/page.tsx:7:142)
    at (ssr)/./app/page.tsx (.../human-nextjs-14/.next/server/app/page.js:162:1)
    at __webpack_require__ (.../human-nextjs-14/.next/server/webpack-runtime.js:33:42)
    at JSON.parse (<anonymous>)
 ✓ Compiled in 243ms (230 modules)

I also still want to know WHY the module is being imported/resolved by webpack on server rendering if it is lazy loaded inside a callback.

Anyone has any thoughts/explanations or am I missing something in my code?

@vladmandic
Copy link
Owner

since this is not an issue with human itself, this is better suited for discussions.
also, i'm not a next.js user, so really cannot help much. i've experimented with next long time ago and while i liked the concept, i really did not like how its build/packaging process and weird webpack worked.

Repository owner locked and limited conversation to collaborators Feb 15, 2024
@vladmandic vladmandic converted this issue into discussion #420 Feb 15, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants