Concisely it can be said that there are 3 different generations when it comes to importing libraries.
- including the library in the global space (the oldest and most common)
- using package/library/dependency managers (for who knows and needs)
- using
import
(the future, ES6 and ES7)
The most common way today is to import into the global space by inserting the file directly on the page. Examples of this are the jQuery
, Angular
, Mootools
, etc when loaded into HTML with for example:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
That way the variables that are global in that file will be global in my application.
This is simple, but can cause problems when we are importing code that exports many variables/names to the global space. If we think that each application can have 20 files .js
to be loaded then it is easy to realize that the probability of overlapping names and variables that erase others is great. This works well on small projects and where the author has control/knowledge of which files includes in the application.
Later managers like the require.js
and the Browserify (that converts modules in Node.js to the browser).
The idea is simple, these Programs load the necessary libraries and their dependencies and then expose the chosen variables of these libraries to a closed/limited scope. That is, the code we have is never run in the global space, but within functions to limit the scope and only with access to the variables that the module generator has configured. Basically, minimalist example:
requirejs(['jquery'], function( $ ) {
// aqui dentro o $ do jQuery está disponivel.
// o código da aplicação coloca-se a partir daqui
});
Parallel to this reality more or less usual in the browser came the Node.js, which is Javascript on the server side. There was adopted the CJS model. Which basically makes every file never exports to global space, and everything that enters the file (module) must enter via require
.
var $ = require('jquery');
exports.myExample = function () {};
This would be the equivalent exepmlo, although jQuery is not used in Node.js. But following the comparison we see that inside that file the $
is available after the module is requested and assigned to the variable. The exports
is the gateway to the outside world and will be passed to the next variable that var x = require(etc...);
The future is to use [import
]3 which is part of the ES6 and ES7 specifications but not yet available in browsers. These modules (in times called Harmony) are inspired by the Node.js (CJS) model. Although this belongs to the future, it is nevertheless possible today to write Javascript with this syntax and then convert to the browser with Babelify (Babel + Browserify), which are simulators (very reliable and very used). So write code that does not need to be changed in the future.
This new way of loading dependencies is very useful and expected. In this future case the syntax is:
// para importar todas as variáveis globais nesse "meu-modulo"
// e colocar numa nova variável chamada "meuModulo":
import * as meuModulo from "meu-modulo";
// para importar somente a variável meuModulo desse "meu-modulo"
import {meuModulo} from "meu-modulo";
// para importar e dar novo nome ao mesmo tempo (multiplos nomes/variáveis neste exemplo)
import {meuModulo as m, calculadora as c} from "meu-modulo";
An important difference between this model and CJS is that in ES6/7 it is possible to use export multiple times to make these features available to "who imports" that file.
An example:
file main.js
import {closest, getElements} from 'utils';
// ou até import * as utils from 'utils'
getElements('div').forEach(el => {
el.innerHTML = 'foo';
});
file utils.js
export function getElements(what, rel) {
if (typeof what != 'string' && typeof what != 'undefined') return what.tagName ? [what] : what;
var els = (rel || document).querySelectorAll(what);
return [].slice.call(els);
}
export function getClosest(el, selector) {
while (el && !el.matches(selector)) {
el = el.parentElement;
}
return el;
}
If you have any improvement suggestions you can leave a comment please.
– gato
+1
this question is very important for Javascript. Because the "native" model has given many headaches, because there has been a great war between AMD and CJS in the past and because the future is there with ES6 Harmony. I gave a +/- succinct answer. I hope it helps to understand the concepts at least.– Sergio
@Sergio yes, and this doubt has been a barrier for me, since I came from desktop programming :) I will read your answer calmly :D
– gato