Un­der­stand how ES mod­ules work

Ec­mascript 6 brings a new na­tive mod­u­lar­i­sa­tion API in­tended to see off ex­ist­ing Javascript mod­u­lar­i­sa­tion tech­nolo­gies

Web Designer - - Meta Contents -

Ec­mascript 6 brings a new na­tive mod­u­lar­iza­tion API. Find out how to use it in your projects

Both ob­ject-ori­ented and tra­di­tional pro­gram­ming lan­guages pro­vided de­vel­op­ers with some way of ‘ac­cess con­trol’ – by break­ing down li­braries and other el­e­ments into mod­ules of their own, out­side med­dling with in­ter­nal data struc­tures can be avoided. Fur­ther­more, the act of declar­ing an in­ter­face be­tween a pro­gram and its en­vi­ron­ment is ben­e­fi­cial for all par­ties in­volved. In ad­di­tion to the clear sep­a­ra­tion of con­cerns, de­vel­op­ers tend to im­prove code qual­ity and con­cept co­herency while work­ing out the de­tails of a mod­ule ac­cess API.

Javascript did not pro­vide a mod­u­lar­i­sa­tion API of its own. This has led to the ap­pear­ance of var­i­ous mod­u­lar­i­sa­tion sys­tems like Com­monjs, which will be dis­cussed tan­gen­tially in this ar­ti­cle. Some de­vel­op­ers also re­sorted to server-side or work­sta­tion-based tran­spi­la­tion, where groups of files were bun­dled to­gether be­fore de­liv­ery.

While all of these work­arounds are fine and well – when used prop­erly, Javascript, to­day, is a first-class lan­guage and get­ting a na­tive way to han­dle mod­u­lar­i­sa­tion is much more con­ve­nient. Ec­mascript 2015 – the stan­dard is also known as ES6 – pro­vides ex­actly that with its mod­u­lar­i­sa­tion API.

1. Get­ting started

Get­ting started with Ec­mascript re­quires the pres­ence of a worker file. En­list the struc­ture shown ac­com­pa­ny­ing this step to get started – it con­tains a ‘work area’ and loads a mod­ule.

<html>

<body>

<script type=”mod­ule” js”></script>

<script>pu­ber();

</script>

</body>

</html> src=”./main­mod­ule.

2. Al­ter­na­tive load

Us­ing a ded­i­cated <script> tag for load­ing the mod­ules is not to ev­ery­one’s taste. The mod­ule im­port syn­tax nor­mally in­tended for in­ter-mod­ule im­ports can, how­ever, also be ap­plied to script tags hosted in­side of web­pages. <script type=”mod­ule”> im­port { pu­ber } from ‘./tree.js’;

// ...

</script>

3. First test

Given that our test har­ness re­quires the pres­ence of a func­tion called ‘lives_in_­mod­ule’, we can – in the­ory – sim­ply de­clare it in ‘main­mod­ule.js’. Sadly, run­ning the pro­gram yields the re­sults shown in the fig­ure ac­com­pa­ny­ing this step.

4. Break out

As men­tioned in the in­tro­duc­tion, one of the most sig­nif­i­cant ben­e­fits of mod­u­lar­i­sa­tion is the ca­pa­bil­ity to com­part­men­talise pro­grams cleanly. Due to that, we need to ex­port the func­tions needed by adding the ex­port state­ment below. Then, pro­ceed to run­ning the web­site once again. ex­port func­tion pu­ber(){

con­sole.log(“pu­ber() says Hello!”); }

5. Fix the CORS is­sues

Like most other dy­namic con­tent, Ec­mascript is also sub­ject to var­i­ous meth­ods of ori­gin con­fir­ma­tion. When work­ing on an unixoid sys­tem, Python pro­vides a nice work­around – sim­ply en­ter the com­mand shown ac­com­pa­ny­ing this step to spin up a little web server.

sudo python -m Sim­ple­httpserver 80

6. Im­ports, re­dux

In­sert­ing a ran­dom <script> tag to load a mod­ule is not enough to get our pro­gram work­ing. If two mod­ules would ex­pose a func­tion with the same name, a names­pace col­li­sion would oc­cur ac­cord­ing to the scheme shown in the im­age below.

7. A ques­tion of need is a ques­tion of taste!

In­clud­ing el­e­ments di­rectly and into a names­pace of its own has its mer­its. How­ever, names­pace con­tention is pro­por­tional to project size. Thus, large projects are well-ad­vised to avoid di­rect in­cludes to pre­vent prob­lems as the amount of li­brary code in­creases.

8. Lim­ited in­clude

As a first ‘re­vi­sion’, let us load the mod­ule into the ‘Tamsmod­ule’ names­pace. This re­quires no changes in the mod­ule file – in­stead, mod­ify the worker har­ness’s code as shown in the list­ing ac­com­pa­ny­ing this step. <body>

<script type=”mod­ule” src=”./main­mod­ule. js”></script>

<script type=”mod­ule”> im­port * as Tamsmod­ule from “./main­mod­ule. js”;

Tamsmod­ule.pu­ber();

</script> </body>

9. Gen­eral in­clude

The sec­ond op­tion loads the mod­ule part into the global names­pace. This does not pre­clude you from load­ing ad­di­tional parts into other names­paces – keep in mind that each mod­ule file gets parsed when it gets ad­dressed the first time. This caching lets you save HTTP la­tency, thereby in­creas­ing ap­pli­ca­tion per­for­mance.

<body>

<script type=”mod­ule” src=”./main­mod­ule. js”></script>

<script type=”mod­ule”> im­port { pu­ber } from “./main­mod­ule.js”; pu­ber();

</script>

</body>

10. even more in­cludes

Open­ing the Mod­ules fea­ture doc­u­men­ta­tion at https:// de­vel­oper.mozilla.org/en-us/docs/web/javascript/ Ref­er­ence/state­ments/im­port re­veals almost a dozen dif­fer­ent in­clude syn­taxes, all of which are demon­strated in ac­tion. im­port de­faul­t­ex­port from “mod­ule-name”; im­port * as name from “mod­ule-name”; im­port { ex­port } from “mod­ule-name”; im­port { ex­port as alias } from “mod­u­le­name”; im­port { ex­port1 , ex­port2 } from “mod­u­le­name”; im­port { ex­port1 , ex­port2 as alias2 ,

[...] } from “mod­ule-name”; im­port de­faul­t­ex­port, { ex­port [ , [...] ] } from “mod­ule-name”; im­port de­faul­t­ex­port, * as name from “mod­ule-name”; im­port “mod­ule-name”;

11. Check en­cap­su­la­tion

In the next step, let us ver­ify that our mod­ule’s con­tent re­ally is pri­vate. For this, we cre­ate a sec­ond, non-ex­ported func­tion which gets called from the test har­ness. When in­voked via pu­ber(), all is fine – in­vok­ing foo() di­rectly will lead to a per­mis­sion de­nied er­ror like the one shown in the screen­shot below. ex­port func­tion pu­ber(){ con­sole.log(“pu­ber() says Hello!”); foo(); } func­tion foo(){

con­sole.log(“foo() also says Hello!”); }

12. Cre­ate a sin­gle­ton

While the ex­port state­ment can also be ap­plied to a class, in some cases, cre­at­ing a ‘com­mon’ sin­gle­ton in the mod­ule it­self can be con­ve­nient. For this, let us start out with an­other test har­ness which emits a mes­sage dur­ing load­ing and fur­ther­more adds some state vari­ables. var my­name=””; var my­weight=0; con­sole.log(“sin­gle­ton global load done!”);

13. Add ac­ces­sory func­tions

While we could sim­ply put an ex­port in front of the mem­ber vari­ables, this al­lows users to wreak havoc in­side them. In­stead, we will im­ple­ment a set of func­tions which mar­shal the val­ues of my­name and my­weight into and out of the mod­ule. In­ci­den­tally, the length of the get­ter func­tions for lo­cal vari­ables is a com­mon eye­sore – look at https://stack­over­flow.com/ques­tions/44757177/ how-to-ex­port-get­ter-in-es6-mod­ule-sys­tem for a

dis­cus­sion of the topic. ex­port func­tion get­name(){ re­turn my­name; } ex­port func­tion getweight(){

re­turn my­weight; } ex­port func­tion set­name(what){

my­name=what; } ex­port func­tion setweight(what){

my­weight=what; }

14. Spin it

Our test code loads the mod­ule twice; once into the ‘Tamsmod­ule’ names­pace, and once into the names­pace ‘Tamsmod­ule2’. The changes made in the ‘Tamsmod­ule’ in­stance will also prop­a­gate into ‘Tamsmod­ule2’ – this can eas­ily be ver­i­fied by look­ing at the out­put of the pro­gram in the con­sole. In­ci­den­tally, this be­hav­iour is caused by the above-men­tioned caching sys­tem, which loads the mod­ule but once for each page. im­port * as Tamsmod­ule from “./main­mod­ule. js”; con­sole.log(tamsmod­ule.get­name()); Tamsmod­ule.set­name(“its a name”); im­port * as Tamsmod­ule2 from “./main­mod­ule. js”; con­sole.log(tamsmod­ule2.get­name());

15. ex­port classes quickly

Should you cre­ate a mod­ule which con­tains one class, set­ting a de­fault ex­port is a par­tic­u­larly neat way to sim­plify ac­cess. In par­tic­u­lar, the two code snip­pets ac­com­pa­ny­ing this step demon­strate both the use of the ‘ex­port de­fault’ at­tribute and in­clu­sion of the class into a worker or a test har­ness. The file name worker.js, in­ci­den­tally, is not a typo – the Ec­mascript mod­ule sys­tem also sup­ports Javascript-on-javascript in­cludes. //------ Tam­sclass.js -----ex­port de­fault class { ... };

//------ worker.js -----im­port Tam­sclass from ‘file­name’; let aclass = new Tam­sclass();

16. elim­i­nat­ing la­tency

With that out of the way, let us re­turn to our sin­gle­ton. It con­tains some global code, which gets run dur­ing the ini­tial­i­sa­tion of the pro­gram. At this point, an in­ter­est­ing ques­tion re­mains – how does the Javascript run­time han­dle de­lays caused by net­work la­ten­cies?

17. Check it out

Some ques­tions are best an­swered with a little test. Thus, re­place the worker code in our test­ing har­ness with the one ac­com­pa­ny­ing this step – it con­tains the sin­gle­ton op­er­a­tions, and also a few ‘lo­cal’ script blocks. Run it, or take a look at the ren­dered out­put in the fig­ure ac­com­pa­ny­ing this step.

<script type=”mod­ule” src=”./main­mod­ule. js”></script>

<script type=”mod­ule”> im­port * as Tamsmod­ule from “./main­mod­ule. js”; con­sole.log(tamsmod­ule.get­name()); Tamsmod­ule.set­name(“its a name”); im­port * as Tamsmod­ule2 from “./main­mod­ule. js”; con­sole.log(tamsmod­ule2.get­name());

</script>

<script de­fer>

con­sole.log(“de­fer In­line Script 1”);

</script>

<script de­fer> con­sole.log(“in­line Script 1”);

</script>

<script de­fer>

con­sole.log(“de­fer In­line Script 2”);

</script>

18. un­der­stand the hi­er­ar­chy

Script tags equipped with the mod­ule at­tribute are as­signed a lower ex­e­cu­tion pri­or­ity, which – at the time of writ­ing – can not be mod­i­fied by the de­vel­oper. Ba­si­cally, a mod­ule script is al­ways equipped with a de­fer com­mand – treat it like any other valid use of the de­fer order in a script tag.

19. Beat the mod­ule

The above-men­tioned in­clu­sion of the type=”mod­ule” string is not born from malev­o­lence on the side of the Ec­mascript stan­dard­i­s­a­tion. In­stead, it uses a pe­cu­liar­ity of HTML – browsers ig­nore script tags with un­known types. This per­mits the use of the fol­low­ing fall­back struc­ture, which is sup­ported by quite a few browsers. Al­ter­na­tively, an even bet­ter – al­beit quite in­volved – work­around can be found at https://medium.com/ dev-chan­nel/es6-mod­ules-in-chrome-ca­nary-m60­ba588df­b8ab7.

<script type=”mod­ule” src=”has-mod­ules.js”> </script>

<script nomod­ule src=”has-no-mod­ules.js”> </script>

20. eval() isn’t ideal

While the use of eval() is not to ev­ery­one’s lik­ing, the num­ber one source of weird pro­gram be­hav­iour re­mains in wide­spread use. Sadly, code passed to eval() is not al­lowed to interact with func­tions or other el­e­ments ex­ported from mod­ules. This odd lim­i­ta­tion is caused by the un­der­lying loader, and is part of the stan­dard.

21. Work with Fire­fox

Fire­fox pro­vides de­vel­op­ers with a set of first-class de­vel­oper tools. If you want to use Mozilla’s browser for de­bug­ging and test­ing mod­ule-based pro­grams, fret not. Sim­ply open the web­site about:con­fig, and look for the at­tribute dom.mod­ule­scripts.en­abled. Next, set it to true – one restart, and all is golden.

22. Find out more

One of the best re­sources/dis­cus­sions of the mod­ule sys­tem can be found as part of Ex­plor­ing JS. Head to https://bit.ly/2w2ilft for a deep dive.

Left

If mod­ules would be loaded glob­ally, the red func­tion tiles would col­lide main names­pace mod­ule A foo() het() tay() mod­ule B foo() baum() tanne()

Right

Mozilla re­cently added sup­port for mod­ules. Make sure to check out the first-class doc­u­men­ta­tion

Right

The advanced ren­der­ing set­tings display can be fil­tered us­ing the text box at the top of the screen

Newspapers in English

Newspapers from UK

© PressReader. All rights reserved.