I recently ran into an issue when I tried to import a reference to jsonwebtoken
into a new Vue 3 project configured with Vite. I’ve observed others encountering the same error (although through different circumstances) and I figured I’d document what I did to resolve the problem for me in case it helps someone else out there.
data-stream.js:39 Uncaught TypeError: util.inherits is not a function
at node_modules/jws/lib/data-stream.js (data-stream.js:39:6)
at __require (chunk-PWNRNYY6.js?v=9f9eb6fa:23:50)
at node_modules/jws/lib/sign-stream.js (sign-stream.js:3:18)
at __require (chunk-PWNRNYY6.js?v=9f9eb6fa:23:50)
at node_modules/jws/index.js (index.js:2:18)
at __require (chunk-PWNRNYY6.js?v=9f9eb6fa:23:50)
at node_modules/jsonwebtoken/decode.js (decode.js:1:11)
at __require (chunk-PWNRNYY6.js?v=9f9eb6fa:23:50)
at node_modules/jsonwebtoken/index.js (index.js:2:11)
at __require (chunk-PWNRNYY6.js?v=9f9eb6fa:23:50)
I’ve attempted several things before finally finding a solution that resolved the error. My failed attempts included:
- Altering the import statement as described in this GitHub Issue.
- Ensuring I saved
@types/jsonwebtoken
anddeclared module 'jsonwebtoken'
in a .d.ts file as suggested in this StackOverflow answer.
I came across a GitHub issue with the same error and what resolved the issue for one person was modifying their webpack config file. For this Vue 3 project, I was using Vite, but this issue helped shift my focus from the import of jsonwebtoken
to how Vite was configured. That’s when I stumbled upon another GitHub issue related to the util
module that contained this comment:
Niputi (GitHub user)
util
is a node builtin module and isn’t/won’t get polyfilled by vite
you will need to add polyfills for node builtins
This newfound knowledge is what ultimately led me to the solution of my problem: I needed to configure Vite to polyfill node builtin modules. I did not know how to do this, but I found an excellent tutorial on Medium with details on how to accomplish it.
I only needed to polyfill the util
module, so there was a lot of configuration code that I was was able to omit that was included in the the Medium tutorial.
First I needed to install two new dependencies:
npm install --save-dev @esbuild-plugins/node-globals-polyfill
npm install --save-dev @esbuild-plugins/node-modules-polyfill
With the new dependencies, I added a new alias for the util
module and under plugins
, I added references to NodeGlobalPolyfillPlugin
and NodeModulesPolyfilPlugin
.
import { fileURLToPath, URL } from 'url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill'
import { NodeModulesPolyfillPlugin } from '@esbuild-plugins/node-modules-polyfill'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
util: 'rollup-plugin-node-polyfills/polyfills/util'
}
},
optimizeDeps: {
esbuildOptions: {
plugins: [
NodeGlobalsPolyfillPlugin({
process: true,
buffer: true
}),
NodeModulesPolyfillPlugin()
]
}
}
})
With that modification to vite.config.js
, I was able to get pass the import error and start using the jsonwebtoken
module.
An Important Update
I celebrated prematurely. The changes above resolved my issues when I ran the dev server, however, when I switched to the production build of the application a new (but related) issue emerged.
Digging into the source, it looked like the buffer node module needed to be polyfilled as well. I revisited the Medium article, and in the comments, a few people also ran into a similar issue. I started going down the path of trying to figure out a way to properly polyfill the node module before I stopped and viewed the problem from a different lens.
The reason Vite (and now Webpack 5) do not polyfill node builtin modules out of the box is because the practice is discouraged. The node builtin modules do not exist in the browser.
I swapped the use of the jsonwebtoken library with jose. (I discovered the existence of jose from jwt.io. They have a page dedicated to libraries and under the JavaScript section, I stumbled upon jose.) It was a relatively easy swap and I no longer have a need to polyfill builtin node modules.