What is the best way to create an ES6 library, e.g. my-es6-crypto-lib
, which can be used both in the browser and in Node.js, but for which the implementations are different on each platform?
(E.g. the Node.js implementation uses the built-in crypto
module for better performance.)
ES6 module usage:
import { sha256 } from 'my-es6-crypto-lib'
let digest = sha256('abc')
console.log(digest)
Or Node.js-style requires:
let sha256 = require('my-es6-crypto-lib')
let digest = sha256('abc')
console.log(digest)
The package.json
for my-es6-crypto-lib
would include:
{
"name": "my-es6-crypto-lib",
"main": "transpiled-to-commonjs/node.js",
"module": "es6-module/node.js",
"browser": "es6-module/browser.js",
...
}
main
key to resolve the CommonJS module.module
key.browser
key.The actual implementation for Node.js would look something like: (transpiled-to-commonjs/node.js
)
// built-in module, faster than the pure Javascript implementation
let createHash = require('crypto')
export function sha256 (message) {
return createHash('sha256').update(message).digest('hex')
}
While the browser implementation would look something like: (es6-module/browser.js
)
// a javascript-only implementation available at es6-module/hashFunctions.js
import { sha256 } from './hashFunctions'
export function sha256 (message) {
// slightly different API than the native module
return sha256(message, 'hex')
}
Note, the implementation of each function is different on each platform, but both sha256
methods have the same parameter message
and return a string.
What is the best way to structure my ES6 module to provide each of these implementations? Are there any javascript libraries out there which do this?
Ideally:
After a while, I now think the best way to do this is actually to export different functionality for each environment.
In the past, complex javascript libraries have used solutions like Browserify to bundle a version of their application for the browser. Most of these solutions work by allowing library developers to extensively configure and manually override various dependencies with respective browser versions.
For example, where a Node.js application might use Node.js' built-in crypto module, a browser version would need to fall back to a polyfill-like alternative dependency like crypto-browserify.
With es6, this customization and configuration is no longer necessary. Your library can now export different functionality for different consumers. While browser consumers may import a native JavaScript crypto implementation which your library exports, Node.js users can choose to import a different, faster implementation which your library exports.
...
It's explained in depth, and with an example, in the typescript-starter readme →