I've noticed some libraries have duplicated code in an es folder. Why do developers do that?
examples:
Developers can ship their packages in a few different flavours, depending on how the user (e.g. you) wants to use them.
If you want to use the module code (i.e. import), or you want to use es2015 (i.e. the require), or you even might want to use it in a browser environment (standalone - think .min file).
The folders names are meaningless, developers can call them whatever they want, but they'll probably put their non-transpiled (i.e. import) modules in an es or esm directory
Keep in mind that just because you are "import"-ing their module doesn't mean that their module uses imports. Most nowadays are still transpiled before being shipped so the code you're import-ing is probably require-ing stuff.
It's kind of complicated...
Related
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");
I've been using Modules that are presented with ES6 for a while. While I (instinctively) know that it is better to use them, I struggle to explain why.
With modules;
I can do dependency declaration (not injection). I do not have to use a script tag for each javascript file I load.
Before modules, objects served as namespaces. Now that we have modules, we have namespaces which is a better paradigm for code organization.
Else than this, why should I use modules ?
What advantage they provide over just using objects as namespaces ?
EDIT:
Thanks to the comments of Bergi and Randy Casburn, I am now able to point out two more things.
With Module Pattern(which i been calling object-as-namespaces) we have same functionality. But we get it through closures. In Modules, we have separate files. Features of a separate file is harder to be violated.
Modules hide their internal features. It drives us towards thinking about better software design.
Answering my own question. Thanks for the comments.
Modularity is a must for software. Before ES Modules, we achieved modules through Module Pattern(which is simply putting related things in an object). By ES6, Modules are native. And native is always the better option.
In Module Pattern, we made modules with closures. In ES Modules we code them in seperate files.
Seperate files adds another layer of protection against code violation.
Modules drive us to design better software.
With ES Modules we have export keyword which gives us freedom to choose what to expose.
We also have import keyword to pick whatever we want from a module.
With ES6 Modules we can now include Javascript modules which are in seperate files into our web app without the need to include them in script tags.
Can someone provide some information about Module Loaders and Module Bundlers in JavaScript?
What are the differences?
When should I use a Module Loader and when a Module Bundler?
Why do we need them at all?
Module loaders and bundlers both make it more actionable to write modular JavaScript applications. Let me give you some background:
Module loaders
A module loader is typically some library that can load, interpret and execute JavaScript modules you defined using a certain module format/syntax, such as AMD or CommonJS.
When you write modular JavaScript applications, you usually end up having one file per module. So when writing an application that consist of hundreds of modules it could get quite painful to make sure all files are included and in the correct order. So basically a loader will take care of the dependency management for you, by making sure all modules are loaded when the application is executed. Checkout some popular module loaders such as RequireJS and SystemJS to get an idea.
Module bundlers
Module bundlers are an alternative to module loaders. Basically they do the same thing (manage and load interdependent modules), but do it as part of the application build rather than at runtime. So instead of loading dependencies as they appear when your code is executed, a bundler stitches together all modules into a single file (a bundle) before the execution. Take a look at Webpack and Browserify as two popular options.
When to use what?
Which one is better simply depends on your application's structure and size.
The primary advantage of a bundler is that it leaves you with far fewer files that the browser has to download. This can give your application a performance advantage, as it may decrease the amount of time it takes to load.
However, depending on the number of modules your application has, this doesn't always have to be the case. Especially for big apps a module loader can sometimes provide the better performance, as loading one huge monolithic file can also block starting your app at the beginning. So that is something you have to simply test and find out.
ES6/ES2015 Update
Note that ECMAScript 2015 (or ES6) comes with it's own, native implementation of modules. You can get a quick intro here and here.
I am building Angular Apps, using 1.x and have been for some time now. I use Bower to install Angular and the various packages that go with it and some other bits and pieces like Shivs, JQuery, ChartJs etc etc. I love using Bower as it's nice and quick and keeps everything in a consistent place for me to reference. I use Grunt as well as my task-runner and so I'd also like to be able to automate this process for silky smooth development.
Now as my Angular knowledge has increased and the scale of the apps that I'm building are increasing, I'm finding myself including dozens of calls to files within the index.html and I really want to tidy all this up, ideally into a nice app.js making it all much more manageable, not only for myself but for anyone else coming in and working on these apps.
I've seen maaany tools like requirejs, browserify and commonjs to name but a few, which all provide the kind of functionality I'm after, but when reading various tutorials or watching conference talks on the process, they all seem to conflict with one another on which is the best. I know to some degree (as with all these competing technologies) it's personal preference, and I was leaning towards browserify, but apparently this removes bower from the flow and uses NPM instead. I'd like to stick with Bower if possible. I've really enjoyed using it.
Does anyone have any suggestions or best practices they can offer that might clear this up for me? Would a simple concat with grunt/gulp just be the way to go?
Any useful comments/answers would be much appreciated.
Many thanks.
Use ES6 Modules along with a module bundler (my recommendation would be Webpack).
As you have correctly identified RequireJS and commonjs evolved around different (and slightly conflicting) goals and are incompatible. ES6 modules is a standardized effort towards modular javascript that is already well supported by transpilers (eg. Babel).
This article provides a great introduction to this new feature:
Even though JavaScript never had built-in modules, the community has
converged on a simple style of modules, which is supported by
libraries in ES5 and earlier. This style has also been adopted by ES6:
Each module is a piece of code that is executed once it is loaded.
In
that code, there may be declarations (variable declarations, function
declarations, etc.).
By default, these declarations stay local to the
module.
You can mark some of them as exports, then other modules can
import them.
A module can import things from other modules. It refers
to those modules via module specifiers, strings that are either:
Relative paths ('../model/user'): these paths are interpreted
relatively to the location of the importing module. The file extension
.js can usually be omitted.
Absolute paths ('/lib/js/helpers'): point
directly to the file of the module to be imported.
Names ('util'):
What modules names refer to has to be configured. Modules are
singletons. Even if a module is imported multiple times, only a single
“instance” of it exists. This approach to modules avoids global
variables, the only things that are global are module specifiers.
Example of use of Javascript modules in practice:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
I am starting a new Web project and trying TypeScript, mainly as an ES6 transpiler but also with the additional benefits of type checking, especially for existing libraries such as jQuery combined with the DefinitelyTyped type definitions.
Since the latest version, TypeScript supports both its own internal modules and ES6 modules, which calls "external" modules. Because ES6 is more standard than TypeScript, my intention is to use ES6/external modules rather than the traditional/internal TypeScript modules.
I have my own code defined in several files/modules, but I want the build to generate a single .js file that I can load from the browser.
The problem is that as far as I can tell, TypeScript is only able to generate a single output file when using its own module format. If I try to use ES6 external modules, then it generates a separate .js file for each .ts file.
This means I would need to concatenate them using browserify, but also I want source map support, which means that I should configure browserify for input and output source maps, then combine it with exorcist so the source map is extracted out of the bundle.
That looks like a very complex build setup. Isn't there a more straightforward way, maybe directly supported by TypeScript? What is the best approach? What do you recommend?
Let TypeScript do what it does best...
Add types to JavaScript be it ES5/ES6/ES7
Transpile to ES5
Resolve modules via the specified module syntax (commonjs, amd, umd, system)
Then find another tool that will take the separate files and combine them into a single bundled file (in the right order). My suggestions are to look into:
webpack
browserify
tsify
Are you looking for a solution in the browser? If so, I highly recommend my project Zwitterion. It removes the complicated build steps, and let's you include TypeScript directly into the browser with normal script tags. You can also use standard ES modules directly, with no extra setup. It uses SystemJS under the hood to achieve that. There is no source map support yet, but that should come. If you would like more information besides what's in the README, you can read "Zwitterion, forget the build step".