Using Node.js require vs. ES6 import/export (2018) - javascript

I'm starting a project using NodeJS.
I did few Javascript classes and they say, that the all browsers support ES6.
I found this question here, that was asked 3 years ago and the last answer was made in 2015 and edited in 2016.
The technology moves on pretty fast, so i would like to know, if this still the case in 2018.

Copying my answer from that old post with all the high vote, old info...
The most important thing to know is that ES6 modules are, indeed, an official standard, while CommonJS (Node.js) modules are not.
In 2019, ES6 modules are supported by 84% of browsers. While Node.js puts them behind an --experimental-modules flag, there is also a convenient node package called esm, which makes the integration smooth.
Another issue you're likely to run into between these module systems is code location. Node.js assumes source is kept in a node_modules directory, while most ES6 modules are deployed in a flat directory structure. These are not easy to reconcile, but it can be done by hacking your package.json file with pre and post installation scripts. Here is an example isomorphic module and an article explaining how it works.

Related

Is CommonJS 'require' still used or deprecated?

Current Javascript adopts import from ES6 as a standard way to import modules.
However, I sometimes see codes using CommonJS require instead of import.
I first wondered whether two can be used together, but it seems like two are not interchangeable. (releated stackoverflow question)
So, is CommonJS 'require' something that is still used in projects? Or is it slowly dying and needed only for maintaining legacy codes?
CommonJS will likely be supported in nodejs for a long time as there are still millions of lines of code written using it. It is the original module loading mechanism in nodejs. It is not deprecated.
ESM modules (ECMAScript modules) that use import and export are the new Javascript standard for modules and we can expect that nodejs will support these for as long as they are the Javascript standard (probably forever).
These two modules standards are not entirely compatible so mixing and matching within the same project can lead to complications that you have to learn how to deal with.
New Projects
If I were starting a new project today, I'd choose to write my code using ESM modules as it is the future trajectory of the language and nodejs. And, you can still load CommonJS modules into ESM modules if you require backward compatibility with other modules, but you do have to know how to do it properly - it's not always seamless to mix and match module types.
When ESM modules were first supported in nodejs, the interoperability with CommonJS modules was not very full featured and created some difficulties. As of the more recent versions of nodejs, you can load a CommonJS module from an ESM module or vice versa- you just have to use the right techniques to do it. This makes working from an ESM project a lot more feasible now than it was when ESM support in nodejs first came out as you can still access libraries in NPM that only support CommonJS.
Note also that more and more libraries in NPM are supporting direct loading from either module type so they are equally easy to use whether your project is CommonJS or ESM.
Over time, I would expect that any actively developed, shared module on NPM will eventually support direct loading as an ESM module. But, we're in this transition period of time where many have not yet implemented that or there are particular challenges in implementing the new loading scheme (which comes with it's own and different set of rules). In the meantime, you can still load CommonJS modules into ESM projects.
Existing CommonJS Projects
If I had an existing project that was CommonJS, I would not be spending any time thinking about converting it to ESM because there is still widespread support for CommonJS and my developer time is probably better spent on adding features, testing, fixing bugs, etc... than converting module formats.
Interoperability
One of the important interoperability things to know is that you can load a CommonJS module from an ESM module in several different ways:
With a static import: import { callMeCommon } from '../otherProject/common.js';
With a dynamic import import(someFile).then(...)
By using module.createRequire(import.meta.url) and then using that require() function to load your CommonJS module.
You can also use the dynamic import('someModule').then(...) to load an ESM module from a CommonJS module, but it's not synchronous like require() was so it has to be dealt with differently.
It's also useful to know that ESM modules do not have some nodejs niceties that CommonJS modules had. There's no automatic __dirname or __filename to tell you exactly where this file was loaded from. Instead, you have to parse those values out of import.meta.url and compute them. So, it's still possible to get that information, it's just not as convenient as it used to be.
On the other hand, ESM modules have some features like top level await that CommonJS do not which can be very useful.
Your Specific Questions
So, is CommonJS 'require' something that is still used in projects?
Yes, it is still used a lot.
Or is it slowly dying and needed only for maintaining legacy codes?
[Comments as of early 2022] I wouldn't so much say that it is dying as there are very few projects on NPM that don't still support CommonJS. In fact, when a project releases a new version that no longer supports CommonJS, it creates quite a problem for their user base (we see some of these issues here on stackoverflow) because of the significant prevalence of CommonJS projects still and people not familiar with how to load different module types.
So, I'd say that we're still in a very early stages of a transition from CommonJS to ESM and it's more like ESM is getting more and more adoption rather than CommonJS is dying. I'd hazard a guess that the majority of modules on NPM will, over the next few years, move to support direct loading from both module formats.
Transpiling
Lastly, developers often use transpiling to allow them to write code using the newest syntax and features, but using a transpiler to convert the code back to a lower, common denominator that runs anywhere. That can also be done for module architecture (write code in ESM, transpile to CommonJS).
A Few Interesting References
What does it take to support Node.js ESM?
Hybrid npm packages (ESM and CommonJS)
Node Modules at War: Why CommonJS and ES Modules Can’t Get Along
All you need to know to move from CommonJS to ECMAScript Modules (ESM) in Node.js
In Nodejs it doesn't yet appear to be deprecated given the LTS v20 precursor (v19) documentation describes the feature:
https://nodejs.org/api/esm.html#interoperability-with-commonjs
https://github.com/nodejs/Release
If locked into Nodejs the above affords a length of time into 2025 for using LTS Nodejs runtimes, with legacy code, and possibly polyfill the same whenever the Nodejs product changes status (the module system or the whole runtime).
CommonJS is the legacy module system specific to Nodejs
see https://wiki.commonjs.org/wiki/Modules/Meta
Generally outside of Nodejs Commonjs/require has been displaced in JS/TS runtimes by ESModules:
https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules
As much as possible I've been moving away from Nodejs to Deno and haven't looked at the specifics and details of its npm and Nodejs compatibility. For those who're looking to implement software using contemporary web platform features it's the best forward-looking with current working solutions that I'm aware of (more at https://deno.land/).
import { createRequire } from "https://deno.land/std/node/module.ts";
// import.meta.url...like `__filename` ...
const require = createRequire(import.meta.url);
const path = require("path");

How do you build, bundle & minify ES6-modules?

Due the fact, that ES6-modules (JavaScript-modules) are available for testing:
https://www.chromestatus.com/feature/5365692190687232
https://medium.com/dev-channel/es6-modules-in-chrome-canary-m60-ba588dfb8ab7
I wonder, how should I minify and prepare the project release-file? Earlier, I havde bundled all JavaScript-files into the single and minified file, except situations, where I have to load the JS-file dynamically via XHR or Fetch API.
As I understand, it's rather impossible to prepare a single-minified file with the ES6-modules right now or may be, I'm just misunderstanding some ways of work.
So, are the any ways to prepare my ES6-modules into single file and how I should prepare the modern JavaScript-project in 2017 year, where JavaScript-modules will be available?
I wonder, how should I minify and prepare the project release-file?
That is purpose of this action? Okay, minified files take fewer network traffic, and will be downloaded faster, but most NPM libraries provides minified dist-files already. And main question about bundling in one big file.
Why webpack do it? Of cource, due absence of support for ES-modules in browser by native, What's why webpack resolves import statements and round dependencies in synchronous manner*, and then substitute it to IIFE for scoping. And perform babel translation and polyfilling, yes.
But then native support of ES-modules is started, it's become un-useful. One of main goals when exposing your web-app to production, is minify traffic volume for your server, using CDN. Now you can do it in native way, so just import ES-modules from unpkg.org and be happy
*If not using HMR, of course, But it's not appropriate for production mode.
Live examples here: https://jakearchibald.com/2017/es-modules-in-browsers/
This blog explains how you would use the ES6 module syntax and yet still bundle your code into something that the browser will understand.
The blog explains that using SystemJs as an ES6 module polyfill and Babel along with Gulp will enable you to code you modules in ES6 yet sill be able to use it today.
https://www.barbarianmeetscoding.com/blog/2016/02/21/start-using-es6-es2015-in-your-project-with-babel-and-gulp/
Using this guide will help you write your code in ES6 while still having a normal workflow to building, minifying and bundling your code.
Keep in mind there are a lot of tools out there that will help you achieve this but I've followed this method many times and I can vouch for its validity.

How to run a node.js application in vert.x?

I'm totally new to vert.x and I'm trying to see if it's possible to bring up an existing nodejs application in vert.x. Following the instructions at http://vertx.io/blog/vert-x3-says-hello-to-npm-users/, I used npm to install vert.x. I can run a simple hello-world app, but running our existing app is proving to be a little challenging. All the vert.x docs I've found talk about writing new apps, not porting existing code.
Oh, and the same code base needs to continue running on existing nodejs systems.
The trouble that I'm seeing is that vert.x won't load nodejs native modules correctly. For example, Vert.x choked on this require:
var fs = require("fs");
After a little searching I found the vert.x equivalent:
var fs = require("vertx-js/file_system");
Perhaps we could create an shim/abstraction layer to wrap the differences. I did a quick one for the file system API and it seems to load correctly. It does seem like writing an entire abstraction layer will be a fair bit of work. But it seems like it would solve the compatibility issue for APIs used within our source.
The real trouble is how to intercept all the require statements in the node_modules directories. Those modules are also going to be requiring lots of other native APIs like the file-system. This seems like a problem that others may have encountered and solved already. Better not to re-invent the wheel.
I could roll my own solution. I don't really want to sed/replace the node_module source except as a last resort. The only other alternative I have thought of is creating a directory of abstractions an inserting that directory name at the head of the NODE_PATH. This solution seems like it might work, but as I mentioned I'm a vert.x noob so I cannot forsee what kinds of pitfalls lie along that approach.
Does vert.x support a shim layer for running nodejs applications?
Short version TLDR:
You can't!
Long version:
Vert.x is not a Node.JS replacement or runtime. Although there are quite similarities and common design choices such as support for CommonJS modules and support for NPM the native libraries are not present. All I/O operations in Vert.x are done using Vert.x API and they do not always relate to the Node counter parts.
Also you should be aware that the JavaScript language version is not the same either, for example Node relies on V8 which nowadays is quite close to fully support ECMA2015 or ES6 for short, Vert.x as a framework running on the JVM relies on Nashorn (the JavaScript runtime from the JDK itself) which is still on ES5.
The idea of supporting NPM in Vert.x was not to emulate Node but to allow the usage of many of its modules (that do not depend on node native modules). For that reason there is a warning on the documentation. But I guess it is not clear.
There are some ways to get most out of NPM and Vert.x, one option is to go 100% ES6 and use a transpiler such as Babel to transpile back to ES5 which will run fine both with Node and Vert.x (until the moment you use a native module).
If you must to use Node, say that you already have an application built on node and the port is not worth (in terms of resouces/time/etc) then I'd suggest to look into the tcp eventbus bridge. This bridge will allow your existing application to produce and consume messages of an existing cluster of vert.x applications.

CommonJS support in node.js - why obsolete and/or how does it work?

Some time ago I read that entire node.js platform relies on CommonJS specification of module loading. Precisely, this is an API for all require calls:
var abc = require('./abc');
Unfortunately, I can't recall the source - but that's how I understood it. And now, as I wanted to refresh my knowledge about CommonJS, I found that node.js dropped CommonJS in 2013. To quote:
In May 2013, Isaac Z. Schlueter, the author of npm, the package manager for Node.js, said CommonJS is being made obsolete by Node.js, and is avoided by the core Node.js developers.
My question is - what is the standard that node.js bases its require functions? Is there any standard - or did the node.js implementation just fork out from CommonJS? What where the reasons for making it obsolete?

how to create an environment agnostic javascript library

I'm creating a javascript library, and i want it to be environment agnostic (It will not use DOM, AJAX, or NodeJS api. It will be vanilla javascript). So, it's supposed to run in any javascript environment (browsers, npm, meteor smart packages, V8 C bindings...).
My currently approach is creating git repo with the library, with all the library inside a single global variable, without thinking about patterns like CommonJS or AMD.
Later, i'll create another git repo, using my library as a git submodule, and create what is needed to release it as a npm module. I'm concerned if it's a good approach, i didn't found anyone doing this way.
Pros: code will be vanilla javascript, without awareness of environment patterns. It will not bind itself to CommonJS. It will be repackable (copy and paste or git submodule) to any javascript environment. It will be as small as needed to be sent to browsers.
Cons: I'll have to maintain as many git as environments i want to support. At least a second git repo to deliver on npm.
Taking jQuery as example, it runs in both browser and nodejs, with just one git repo. There is some code to be aware of the "exports" variable to run on nodejs or other CommonJS compatible enviroment.
Pros: Just one git repo to mantain.
Cons: It will be binded to CommonJS pattern (to achieve npm compatibility)
My question is: Am i following a correct (or acceptable) approach? Or should i follow jquery's path, and try to create a single git repo?
Update 1:
Browserify and other require() libraries are not valid answers. My question is not how to use require() on the browser, instead, it's about the architecture pattern to achieve enviroment agnosticism.
Update 2:
Create a browser/nodejs module is not the question, it's known. The question is: can make a real enviroment agnostic library? This example is binded to CommonJS pattern, used in NodeJS.
If you are looking for design recommendation for your future library work then in my opinion you can think-future and just use usual Object Oriented Practices well proven in other languages, systems and libraries.
Mainly concentrate on the UML view of your design.
Forget the "one variable" requirement.
Use features proposed in the planned next version of JavaScript.
http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes
http://wiki.ecmascript.org/doku.php?id=harmony:modules_rationale
There is an experimental compiler available that allows you to write ES6-style code even today (see https://www.npmjs.org/package/es6-module-transpiler-rewrite).
Node.js has a --harmony command line switch that allows for the same (see What does `node --harmony` do?)
So in my opinion correct approach is to follow best practices and "think future"
"Use a build tool" is the answer for this question. With a build tool, you can develop with the best code pratices, without accopling your code to some enviroment standard of today (AMD, commonjs...) and still publish your code to these kind of enviroments.
For example, I'm using Grunt.js to run some tasks, like build, lint, test, etc.
It perform tedious operations (minification, compilation...) like Make, Maven, Gulp.js, and various others.
The build task can handle standards (like commonjs) for the compiled code. So, the library can be totally enviroment agnostic, and the build process handle enviroment adaptations.
Note that i'm not talking about compiling to binaries. It's compiling source to another source, like CoffeScript to JavaScript. In my case, it's compilation of JavaScript without enviroment standard to JavaScript with commonjs standard (to run as a Node.js module).
The final result is that i can compile my project to various standards without messing with my code.
Aditionally, with a build phase i can "think-future", like xmojmr answered and use the EcmaScript 6 features on my JavaScript code, using Grunt plugins like grunt-es6-transpiler or grunt-traceur to compile JavaScript code from ES 6 to 5 (so it can run on enviroments of today)
According to modular your library (if you need modules). Read this question Relation between CommonJS, AMD and RequireJS?
Take bootstrap for example, it uses npm to manage project dependencies and use bower to publish as static content for other web apps.
Take a look at browserify as reference, it's a little heavy because it provides the capability to bundle dependent npm modules as resource for browsers.

Categories