Balázs Édes
Balázs Édes

Reputation: 13816

How to deal with node modules in the browser?

My title is a bit vague, here is what I'm trying to do:

Some functions in this module are meant to be used on node-only, so there are node imports in some files, like:

import { fileURLToPath } from 'url'
import { readFile } from 'fs/promises'
import { resolve } from 'path'
// ...

I would like to find a way to:

My main problem is, that no matter what, I have to import or require the node-only modules, which breaks requirement 1 (trips up bundlers, or forces the user to add some polyfill).

The only way I found that's working, is what isomorphic packages use, which is to have 2 different entry points, and mark it in my package.json like so:

{
  // The entry point for node modules
  "main": "lib/index.node.js",
  // The entry point for bundlers
  "browser": "lib/index.browser.js",
  // Common typings  
  "typings": "lib/index.browser.d.ts"
}

This is however very impractical, and forces me to do a lots of repetition, as I don't have 2 different versions of the package, just some code that should throw in the browser when used.

Is there a way to make something like this work?

// create safe-fs.ts locally and use it instead of the real "fs" module
import * as fs from 'fs'

function createModuleProxy(moduleName: string): any {
  return new Proxy(
    {},
    {
      get(target, property) {
        return () => {
          throw new Error(`Function "${String(property)}" from module "${moduleName}" should only be used on node.js`)
        }
      },
    },
  )
}

const isNode = typeof window === undefined && typeof process === 'object'
const safeFs: typeof fs = isNode ? fs : createModuleProxy('fs')
export default safeFs

As it stands, this trips up bundlers, as I'm still importing fs.

Upvotes: 2

Views: 910

Answers (0)

Related Questions