node.bcrypt.js: Fails in Next.js app/ directory incl. with API Route Handlers

What went wrong?

Using bcrypt within a Route Handler in Next.js (API Route Handler within the new app/ directory) causes the app to crash with unusual errors:

error - ./node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/index.html
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> <!doctype html>
| <html>
| <head>

Import trace for requested module:
./node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/index.html
./node_modules/@mapbox/node-pre-gyp/lib/ sync ^\.\/.*$
./node_modules/@mapbox/node-pre-gyp/lib/node-pre-gyp.js
./node_modules/bcrypt/bcrypt.js
./app/api/route.ts

I also reported over here in the Next.js repo:

What did you expect to happen?

bcrypt should work in the app/ directory, including in Route Handlers

Which version of nodejs and OS?

    Operating System:
      Platform: linux
      Arch: x64
      Version: Ubuntu 20.04.0 LTS Mon Feb 27 2023 14:52:57 GMT+0100 (Central European Standard Time)
    Binaries:
      Node: 16.14.2
      npm: 7.17.0
      Yarn: 1.22.19
      pnpm: 7.13.6
    Relevant packages:
      next: 13.2.2-canary.1
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0

If you find a bug, please write a failing test.

Ok, maybe once I find out more.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 8
  • Comments: 21

Most upvoted comments

This error happens when you run bcrypt on the client side, to correct it if you don’t want to use it on the client side but the error is still returning, check that all the places where you are using bctypt have “use server”

Finally got around the issue. Here’s how you can fix this:

First, in next.config.js

push bcrypt to config.externals like so:

  webpack: (config) => {
    config.externals = [...config.externals, "bcrypt"];
    return config;
  },

Then where ever you are using bcrypt,

instead of importing it in the traditional way (import bcrypt from ‘bcrypt’)

You need to import it like so:

const bcrypt = require("bcrypt");

And make sure to put it above the line where it’s being used. For example,

    const bcrypt = require("bcrypt");

    const hashedPassword = await bcrypt.hash(password, 12);

I had the same problem. The problem was solved by installing and importing. Instead of bcrypt install bcryptjs.

> npm i bcryptjs 

> npm i -D @types/bcryptjs

I tried that, I got this error:

./node_modules/next-auth/core/init.js (10:14)
Module not found: Can't resolve 'crypto'

https://nextjs.org/docs/messages/module-not-found

Import trace for requested module:
./node_modules/next-auth/core/index.js
./node_modules/next-auth/next/index.js
./node_modules/next-auth/index.js
./app/api/auth/[...nextauth]/route.ts

I’m a little scared to install bcryptjs because its last publication was 7 years ago and there are at least 40 issues open

Reading this issue in the bcrypt repo over here, it made me think that webpack maybe should not be used to try to bundle bcrypt… 🤔

So it occurred to me that maybe I should be using an externals webpack config and marking bcrypt as external:

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    appDir: true,
  },
+  webpack: (config) => {
+    config.externals = [...config.externals, 'bcrypt'];
+    return config;
+  },
};

module.exports = nextConfig;

Which indeed works (does not work on StackBlitz because the native module does run there):

CodeSandbox demo: https://codesandbox.io/p/sandbox/gracious-bose-wn2731?file=%2Fnext.config.js

Screenshot 2023-02-27 at 16 11 48