100% ESM module world - what it mean? - javascript

While reading about tree shaking in webpack documentation, I came across this sentence:
In a 100% ESM module world, identifying side effects is straightforward. However, we aren't there just yet.
What do they mean by "100% ESM module" and how it is different from the current import and export that we already use today?
reference: https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free

The documentation you're reading is contrasting two types of scripts:
Scripts which expose everything they do through what they import and export
Scripts which do something in addition to importing and exporting (this could be seen as a "side effect")
Consider a big library, one that installs itself as a namespace on the global object to expose its functionality. Let's say that jQuery did this - that is, that it runs something like
const jQuery = (function() {
// lots and lots of code
})();
export default jQuery;
window.jQuery = jQuery;
This contains a side-effect: the line
window.jQuery = jQuery;
This means that other parts of your application could use window.jQuery without jQuery being specifically imported into that module. For example, you might have
// someModule.js
export const doStuff = () => {
window.jQuery('div').text('Hi!');
};
And this can work without the line
import jQuery from 'jQuery';
inside the module script, because jQuery is on the window. (For this to work, there needs to be at least one module somewhere that does import 'jQuery'; or something like that, so that jQuery's code that assigns itself to the window runs)
Because of the side-effect, Webpack will have a harder time with automatic tree-shaking - you'll have to explicitly note which modules depend on modules with side-effects.
In contrast, a module without dependency side-effects would be the someModule.js example above: all it does it export a function, without adding or changing functionality elsewhere.
So by "100% ESM module", Webpack is probably referring to scripts for which all modules' dependencies are explicit with import statements, instead of having to depend on side-effects (like a non-imported module assigning something to the window).

There are two popular module syntax nodejs use.
Commonjs: https://nodejs.org/dist/latest-v14.x/docs/api/modules.html
// exporting
module.exports.a = 1
// or, exports is an alias to module.exports, for all differences check out docs
exports.a = 1
// you can assign module.exports object as well, this sets what's exported
module.exports = {
b: 2
}
// a is not exported anymore
// importing default import, imports module.exports object
const a = require('./b')
// or via named import
const {c} = require('./b');
ES modules: https://nodejs.org/dist/latest-v14.x/docs/api/esm.html
// names export
export const a = 1;
// default export
export default const b = 2;
// importing via name
import {a} from './c'
// importing default export
import c from './b'
Commonjs and esm are still in use. So we are not in %100 esm world yet.

Related

Require.js Config for Namespace Prefix

Is there any way to define a path for all modules under a certain namespace in require.js?
Let's say I have the following modules defined:
Vendor/Plugin1/MyModule1
Vendor/Plugin1/MyModule2
Vendor/Plugin2/MyModule1
Now I want to map all modules under Vendor/Plugin1 to a certain path let's say /plugin1/js/* and all modules under Vendor/Plugin2 to */plugin2/js/**.
Is this possible with require.js or do I need to define every single module by itself?
at: /plugin1/js/newModule
import Vendor/Plugin1/MyModule1
import Vendor/Plugin1/MyModule1
// organise your modules, like:
const m = {
...myModule1, ...myModule2
}
// if you you only want to change the path for some reason, just import modules, then export them.
export m; // or export default m;
the code above shows one example, you need to organise your modules depending on your needs.
you can now, import all your stuff from /plugin1/js/newModule

How to publish a library to npm that can be used both with import and require?

tealium-tracker is written in es6 and transpiled using Babel before published to npm.
When consumers do:
import initTealiumTracker from "tealium-tracker";
everything works as expected.
However, some consumers want to use a require instead of an import, and have to append .default:
const initTealiumTracker = require("tealium-tracker).default;
How could I publish the library to avoid appending .default?
I want consumers to be able to do either:
import initTealiumTracker from "tealium-tracker";
or
const initTealiumTracker = require("tealium-tracker);
Source code
In your source code, If you are ok with using commonJS syntax for import and export...
One option would be to replace all import and export with require and module.exports. Looks like webpack doesn't allow mixing the syntaxes (ES6 and commonJS modules).
So your index.js file can require the functions from dependent module as
const { callUtag, flushUtagQueue } = require("./utagCaller");
and export the default function as
module.exports = initTealiumTracker;
module.exports.default = initTealiumTracker;
Likewise your dependent module can export the functions as
module.exports = { callUtag, flushUtagQueue };
This way, consumers should be able to use either
import initTealiumTracker2 from "tealium-tracker";
OR
const initTealiumTracker1 = require("tealium-tracker");

Import, rename, and export a function in JavaScript?

With JavaScript what's the shortest way to import a named export, rename it, and export it again?
This code works but it feels more verbose than it should be
import { mock as myFunctionMock } from 'context/myFunction';
export const myFunction = myFunctionMock;
You can combine the import and export like so:
export { mock as myFunctionMock } from 'context/myFunction';
See MDN Docs
Note that you won't actually be able to use myFunctionMock within your code file since you haven't imported it. Neither mock nor myFunctionMock will be defined within this module.
This is a useful shorthand when you're building a library that will be used by other modules or by your end-user.
For example, if you had a utils library that you wanted to export, but you wanted to organize your util functions across several smaller files, such as stringUtils, objectUtils, dataUtils, etc, you can export the contents of those modules within your utils module to create a single, monolithic access point:
stringUtils.js
export function toLower(){}
export function toUpper(){}
objectUtils.js
export function propertyMap(){}
utils.js
export {
toLower as stringToLower,
toUpper as stringToUpper,
} from "stringUtils.js";
export {
propertyMap as objectPropertyMap
} from "objectUtils.js";
I wouldn't generally recommend this approach for internal code as it can make your dependency trees a bit wonky in some cases. It can, however, be extremely useful in situations where you want to import from a common interface but the implementation is dependent on the build (prod vs dev, web vs node, etc)
import { mock as myFunction } from 'context/myFunction';
export { myFunction };
in your original exporter, do:
module.exports = { mock: function () {...}}
When importing, do:
const myFunctionMock = require('file path of exporter');
then to reexport in the same file:
module.exports = {renamedMock: myFunctionMock};
Now any changes to mock will propagate to the other modules where it's referenced (side note, this is node.js in a nutshell).

Name of es6 module 'module' is equivalent to 'Module'?

// a.js
export const a = 'a';
// A.js
export const A = 'A';
// index.js
import {a} from './a';
import {A} from './A';
javascript is allowed to create es6 modules differing only in letter case?
This depends much on your module loader/bundler and file system.
ES6 considers these as two different module specifiers for sure. It's possible that they resolve to the same module, but unlikely.
In any case, I would recommend to stay away from this, to avoid confusion.

What are extra advantage of using ES6 module instead of revealing module pattern?

I am exploring ES6 module and trying to figure out what extra advantage we get using ES6 module instead of closure along with module pattern(MP).
For example
util.js in ES6.
var util ={
abc:function(){
//function body
},
def:function(){
// function body
}
export default utils; // here export is exposing the entire object
}
util.js using closure & module pattern
var util = (function(){
function _abc(){
console.log("abc")
// function body
};
function _def(){
// function body
}
return{ // each of the function will be exposed
abc:_abc,
def:_def
}
}(util ||{}))
someFile.js in ES6
import {utils} from "path/to/file"
In someFile.js with closure & module pattern
util.abc() // Will log "abc"
Also I know es6 module allow us to rename imports & exports
Like export { a as abc} .
With closure & module pattern we can give a name whatever we like inside return statement like return { a:_abc}
My question:What extra benefit we can get by using es6 module instead of closure& MP.One i guess is reduction in lines of code.
Please excuse me if I have missed any basic difference
With var util = (function(){ bla bla bla }(util || {})); the global namespace is polluted, so that once you have used import {utils} from "path/to/file", it will remain in global namespace, i.e. you'll be have window.util everywhere, even after the module has finished it's work and replace by some other module. Now consider you have 100s of modules and you do it in the same way, then imagine how dirty would the poor window become!
However if ES6 Module or CommonJS or even AMD is used, then
The global namespace is not polluted.
[ES6] You can use export default something to export a default value to use import from "path/to/file"
[ES6] You can export multiple things from ES6 Module, using export["anotherthing"]
Furthermore I would recommend you to read this blog post.

Categories

Resources