passwordless-id / webauthn

Webauthn / passkeys helper library to make your life easier. Client side, server side and demo included.
https://webauthn.passwordless.id
MIT License
436 stars 51 forks source link

Import issue in Nestjs #35

Closed neerosity closed 8 months ago

neerosity commented 11 months ago

Error

const webauthn = require("@passwordless-id/webauthn");
                 ^
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/neerajsingh/work/Deinfra/barter-api/node_modules/@passwordless-id/webauthn/dist/esm/index.js from /**/dist/authentication/authentication.service.js not supported.
Instead change the require of index.js in /**/dist/authentication/authentication.service.js to a dynamic import() which is available in all CommonJS modules.

Code

import * as webauthn from '@passwordless-id/webauthn';

// OR 

import { server } from '@passwordless-id/webauthn';

// both doesn't work and give same error

tsconfig

{
  "compilerOptions": {
    "module": "commonjs",
    }
 }

// can't change this to ES6 which result into issue for all other imports

Regenerate issue

install nestjs install '@passwordless-id/webauthn'; try to import and run

dagnelies commented 11 months ago

Hmmm... I'm not really a fan of supporting outdated import systems in new projects. A PR for a separate commonJs build is welcome, but I won't put the effort to support legacy stuff. Please just pay attention that it has to be a separate build, otherwise you will break all existing integrations using normal modules.

maxflex commented 10 months ago

@dagnelies Is this also a reason why the package doesn't work for me? Following the docs, I did

npm install @passwordless-id/webauthn

Then importing it in my Nuxt 2 project

import { client } from "@passwordless-id/webauthn"

gives me this error Cannot find module '@passwordless-id/webauthn'

Node v16. I also tried the Arch0125`s fork

neerosity commented 10 months ago

@dagnelies no matter I use commonjs or es6 or nodenext, it doesn't work

dagnelies commented 10 months ago

Node 16 has already reached EOL and nuxt2 follows in half a year. It's time to move on to ES modules. I can only repeat myself.

Hmmm... I'm not really a fan of supporting outdated import systems in new projects. A PR for a separate commonJs build is welcome, but I won't put the effort to support legacy stuff. Please just pay attention that it has to be a separate build, otherwise you will break all existing integrations using normal modules.

If you really want that commonJs "require",you are welcome to make a PR for a separate build. It may even be relatively straightforward to do.

enri90 commented 8 months ago

Is it possible to have a build in CommonJS?

dagnelies commented 8 months ago

Well, this is like asking for Internet Explorer 8 support. Native JS modules are supported since Node 8+. While it appears to be a benefit to have an additional CommonJS build, since it indeed solves cases like these, I wonder if it's a good thing. Rather than supporting the outdated CommonJS, it would be nice if the non-module projects transition to JS modules instead. For the commmunity as a whole, forcing lib maintainers to support both builds adds burdens and will slow down the transition period even further. In other words, while I'm not radically against, it's not on my priority list. It would be better to leave CommonJS in the past, like UMD and AMD.

dagnelies commented 8 months ago

What about:

npm install esm

Then

require = require('esm')(module);

Have you tried that? I guess it might complain though because this will import everything, including the client side which relies on the window object.

Kareszrk commented 8 months ago

I have tried it btw, it's not a solution. NestJS wants CommonJS build. :/ I have spent like 3 hours trying this method, it's not a solution.

Kareszrk commented 8 months ago

I've successfully integrated this functionality into NestJS without encountering any issues. The key is to leverage "dynamic import," which is a built-in feature, eliminating the need for any additional modules to be installed.

In my controller, I imported the module using dynamic import as shown below:

const FIDOResponse = JSON.parse(req.body.credential);
console.log(FIDOResponse);
console.log("headers: " + `https://${headers.host}`);
import("@passwordless-id/webauthn").then(async(module) => {
    const { server } = module;
    console.log("nodejs said, module was loaded successfully")
    const registrationParsed = await server.verifyRegistration(FIDOResponse, {
        challenge: session.TEMP_Challenge,
        origin: `https://${headers.host}`,
    })
    console.log(registrationParsed);
}).catch((error) => {
    // Handle any import errors
    console.log(error);
});

Originally, this resulted in around 10 lines of errors, starting with the one you mentioned. To resolve this issue, I made modifications to my tsconfig.json to enable the use of dynamic imports. Specifically, I added the following settings:

"moduleResolution": "NodeNext",
"target": "ESNext",

For clarity, here's the complete tsconfig.json file:

{
  "compilerOptions": {
    "module": "CommonJS",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "ESNext", // <- This line was modified
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "noImplicitAny": false,
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false,
    "moduleResolution": "NodeNext" // <- This line was modified
  }
}