javascriptnode.jsbrowserisomorphic-javascript

Isomorphic JavaScript library using JavaScript modules - Omitting Node.js dependencies in the browser?


So I'm planning on writing a package which a user will hopefully be able to use on both Node.js and in the browser.

On the Node.js side it will use the fs module. This does not exist in the browser perhaps. This could be accomplished with CommonJS with an if clause to check which environment the module is in and a simple require.

This is not the case with import as it is hoisted.

Does anyone have an idea of how to structure the code or the build environment to satisfy both enviroments in the same package?


Solution

  • Stick to ES6 imports

    It seems there was an improvement in import support in Node.js. In the docs it says:

    The --experimental-modules flag can be used to enable support for ECMAScript modules (ES modules).

    Once enabled, Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements within ES module code:

    • Files ending in .mjs.

    • Files ending in .js, or extensionless files, when the nearest parent package.json file contains a top-level field "type" with a value of "module".

    • Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=module.

    The second listed approach may be useable with node.js. Simply make sure your librarie's package.json contains "type": "module" and Node should treat it as a ES6 module instead of CommonJS.

    Conditional import as promise - you will have to wait

    Conditional imports are already available in node but not actually supported. They seem to work in browser. And there's a caveat: the imported module is a promise. What that means is that you can have partially isomorphic code as long as you plan your steps well. Knowing that you can do import("test.js") in browser and that you can test for window means you can write conditions in a smart way and have cross-platform code.

    For example you can do:

    if (typeof window !== 'undefined') const FooPromise = import("foo");
    

    But not the opposite. Good luck. Hopefully more support for the es6 dynamic import will come to node.