blakeembrey/make-error-cause

Browser compatibility

Opened this issue ยท 1 comments

Thanks for this great package! ๐Ÿ˜„

Expectation

From README.md:

Compatible with node.js and browsers

Problem

However, it imports from "util", which is only available in Node JS:

import { inspect } from "util";

And I'm seeing this error in some of my projects:

Uncaught TypeError: util_1.inspect is undefined

Reproduction

Here is a very minimal Vite project that demonstrates the problem: repro.zip

  1. npm install
  2. npm run build
    > vite-starter@0.0.0 build
    > vite build
    
    vite v5.1.6 building for production...
    [plugin:vite:resolve] [plugin vite:resolve] Module "util" has been externalized for browser compatibility, imported by "/home/dolf/tmp/20240315-make-error-cause/repro/node_modules/make-error-cause/dist/index.js". See https://vitejs.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.
    โœ“ 11 modules transformed.
    dist/index.html                0.25 kB โ”‚ gzip: 0.19 kB
    dist/assets/index-B4nqUxqB.js  7.73 kB โ”‚ gzip: 2.32 kB
    โœ“ built in 84ms
    
    Note the warning above. See https://vitejs.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.
  3. npm run preview
  4. Open browser and look in the console to see the error:
    image
    Here you can see in the built code where it happened:
    image

Possible solution

Coming soon ...

It seems that with Vite, the "externalization" means that we hope that something else will provide a polyfill. This was the case in one of my projects, until I removed some other project that was incidentally providing the right polyfill. Then I started getting this error.

However, with other build tools, the require("util") itself may fail.

So we need to avoid having require("util") at the top. It is used in two places as far as I can see:

[inspect.custom || /* istanbul ignore next */ "inspect"]() {

Here we just use the symbol. For Vite, it suffices to replace inspect.custom || "inspect" with inspect?.custom || "inspect" but that might not fix it for all build tools.

.map(err => inspect(err, { customInspect: false }))

This one sent me down quite a rabbit hole. I see that Chrome, Firefox, and even Chromium without any plugins all have an inspect function available in the console, but it's a native function, and it's not even in globalThis or window. I also can't find any documentation on it (neither MDN nor CanIUse know about it).

I don't have a solution for this yet.


Possible workaround for Vite: https://www.npmjs.com/package/vite-plugin-node-polyfills