3

Example context

I'm writing a library based on getting crypto-secure random bytes from a native source. I want to make the lib usable both in Node.js and in the browser. This requires using different built-in APIs in the two environments.

The problem

I'm searching for the general solution to use

  1. either Node.js API methods with ES6-style imports
  2. OR browser API methods,

based on environment detection.

The problem applied to the above example context

To make the lib usable both in Node.js and in browser environments, crypto.randomBytes() is used in Node.js, and window.crypto.getRandomValues() is used in the browser as underlying the random source.

The currently working solution is based on Node's dynamic require. The lib detects the environment, then:

  • in Node.js, it uses require('crypto'),
  • in the browser, it uses window.crypto.getRandomValues(), which is simply available in the global scope and nothing has to be required/imported.

The question

Instead of using require(), I'm wondering if it's possible to use an ES6-style import { randomFill } from 'crypto'; with environment detection. The import would still be run in the browser, but there is no such built-in module in the browser, so that would be a problem.

Do you have any experience how transpilers (like babel) and bundlers (like rollup) handle this kind of problem with static imports?


Note: this is not a duplicate of How can I use an es6 import in node?. I know there are ESM and the --experimental-modules, and it works well. My question regards the case when both browser and Node.js environments are the target of an implementation, but due to the different environments, different platform-provided APIs must be used.

Robert Todar
  • 2,085
  • 2
  • 11
  • 31
Soma Lucz
  • 159
  • 12
  • Possible duplicate of [How can I use an es6 import in node?](https://stackoverflow.com/questions/45854169/how-can-i-use-an-es6-import-in-node) – Nir Alfasi Jun 14 '19 at 20:12
  • i dont think its possible to do conditional es6 imports... but maybe there's a way now? – Abdul Ahmad Jun 14 '19 at 20:13
  • 2
    @alfasin Thank you for your response. This is not a duplicate of that question. I edited mine and explained why. – Soma Lucz Jun 14 '19 at 20:26
  • Just found https://github.com/defunctzombie/package-browser-field-spec/blob/master/README.md – Jonas Wilms Jun 14 '19 at 20:41
  • There are dynamic ESM imports, but they’re not synchronous. Use `require` or import a module with a uniform interface that itself gets replaced based on the environment. – Ry- Jun 14 '19 at 20:41

1 Answers1

2

I'm not sure if this answers your question, but the way I solve this is basically through my webpack build.

I might have an import a bit like:

import { base64encode } from './base64';

In this directory I have 2 files:

base64.js
base64.web.js

It's possible to configure webpack to prefer the second one over the first. Other browser build tools have a feature like this as well.

This works really well for me, but this is only really an option if you have a 'build step'.

Evert
  • 93,428
  • 18
  • 118
  • 189
  • This is the correct approach. Don't do environment detection and dynamic module import, but let the module loader/bundler resolve the `crypto` import appropriately. – Bergi Jun 14 '19 at 21:45