Thoughts on Modern Web Development …

When dealing with NPM Permissions, often times it can be tempting to resort to installing modules as root (sudo), especially when under tight time constraints; where troubleshooting such issues will only serve to delay your progress.

Admittedly, I have been guilty of this more often than I care to admit. That said, being as I always have the Broken Windows Theory in the back of my mind, I knew this workaround needed to be resolved as soon as I had a moment to dig into it a bit more.

Previously, I had followed the instructions from docs.npmjs; however, they focus more on installations of global dependencies, rather than local dependencies. Fortunately, after a few quick searches, it became apparent that by simply changing permissions to the ~/.npm directory, this issue could easily be resolved as, all that is needed is to change the owner of the ~/.npm directory to the current user (as opposed to root).

When leveraging React Bootstrap, one important consideration missing from the documentation (or perhaps, simply not emphasized enough) relates to module access when using ES6 imports.

Specifically, in the context of React Bootstrap’s “convenience components” <Component.SubComponent> (e.g. <Modal.Body>), such imports must be made explicit as they can not be resolved against their parent components during transformations of ES6 imports to CommonJS modules.

Like many developers, at times I find the need to convert raw HTML to JSX. It was only after I found myself needing to do this a bit more frequently that I considered writing a quick tool to automate the task. However, like most things, I knew there must be something out there which handles this already, and as I suspected, there certainly is: HTMLtoJSX – a component of React-Magic which does precisely this.

So, if ever you need to quickly convert raw HTML to JSX, be sure to check out the online converter and, for more frequent needs, the converter is also available via NPM and can easily be integrated into part of an existing build pipeline.

While on the surface this may appear insignificant, when compared to having relied almost exclusively on the arguments object and Array.prototype to provide the same functionality in ES5, the benefits become rather apparent.

For instance, consider a simple multiply function which, depending on the arity of the invocation, either computes basic multiplication against the provided parameters, or returns a partial application. That is to say, if invoked as a unary function (single argument), the function returns a partial application (a new function which multiplies by the given argument). If invoked as a variadic function (variable amount of arguments), the function returns the product of the arguments.

Given the above example, in order to inspect and iterate over the provided arguments, we need to rely on the Array.prototype, specifically, we need to invoke Function.prototype.call on Array prototype in order to apply the slice method so as to convert the arguments object to an Array. Additionally, we also have to account for a default value of arguments[0] should it be omitted or NaN.

Not only does this require a superfluous amount of code, but it also results in a more complicated implementation that becomes considerably more verbose, and as a result, more difficult to reason about; especially for developers who may not be familiar with the specific mechanisms employed within the implementation.

ES6 to the rescue …

With the introduction of default parameters, …rest parameters, and Arrow Functions (fat arrows) in ES6, the implementation of the above example can be significantly reduced, and as a result, becomes considerably easier to understand, as we can simply re-write the multiply function as:

As can be seen, implementing the multiply function in ES6 not only reduces the SLOC by 1/2 of the previous ES5 implementation, but more importantly, by using rest parameters, it allows us to determine and work with the functions arity in a much more natural way. Moreover, both iterating over the provided arguments and returning the partial application becomes considerably more concise simply by using arrow functions, and the need to account for undefined arguments becomes moot thanks to default parameters.

In addition, variadic invocations of such functions can also be simplified considerably using the ES6 spread operator. For example, in order to pass an Array of arguments to a function in ES5, one would need to call Function.apply against the function, like so:

1

2

3

multiply.apply(null,[1,10,100]);//1000

With ES6 spread operators, however, we can simply invoke the function directly with the given array preceded by the spread operator:

1

2

3

multiply(...[1,10,100]);//1000

Simple!

Hopefully this article has shed some light on a few of the features available in ES6 which allow for writing implementations which not only read much more naturally, but can be written with considerably less mental overhead.

Unlike ES5, which is syntactically less opinionated, in ES6, when using an IIFE, parenthetical order matters.

For instance, in ES5 an IIFE could be written either as:

1

2

3

4

5

// parentheses wrap expression and invocation ...

(function(){

}());

… or

1

2

3

4

5

// parentheses wrap function expression ...

(function(){

})();

As can be seen in the above examples, in ES5 one could either wrap and invoke a function expression in parentheses, or wrap the function expression in parentheses and invoke the function outside of the parentheses.

However, in ES6, the former throws an exception, thus, one can not use:

1

2

3

4

(()=>{

}());// Uncaught SyntaxError: Unexpected token

But rather, the invocation must be made outside of the parentheses as follows:

1

2

3

4

5

(()=>{

console.log('IIFE');

})();

As an aside for those who are curious, the syntax requirements are specific to ES6 and not a by-product of any particular transpilers (i.e. Babel, Traceur, etc.).

Being a typical aspect of Object Oriented Design, inheritance, and mixins, provide the means by which modular reuse patterns can be facilitated within a given system. Similarly, Polymer facilitates code reuse patterns by employing the notion of shared behaviors modules. Let’s take a quick look at how to leverage them in Polymer when using ES6 classes.

Implementing Behaviors

Implementing a Behavior is quite simple, just define an object within a block expression or an IIFE, and expose it via a namespace, or module loader of choice:

1

2

3

4

5

6

7

8

9

10

11

12

13

'use strict';

(()=>{

// define the behavior

constSomeBehavior={

...

};

// add the behavior to a specific namespace ...

constns=(window.SomeNamespace=window.SomeNamespace||{});

ns.SomeBehavior=SomeBehavior;

})();

some-behaviors.js

Then, include the behavior in a corresponding .html document of the same name so as to allow the behavior to be imported by subsequent elements:

1

2

3

<script src="some-behaviors.js"type="text/javascript"></script>

some-behavior.html

Extending Behaviors

After having defined and exposed a given Behavior, the Behavior can then be extended from element classes by defining a behaviorsgetter / setter as follows:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

'use strict';

// define element class ...

classSomeElement{

beforeRegister(){

this.is='some-element';

}

// implement behaviors getter, returning an array of behaviors

// which are to be extended ...

get behaviors(){

return[window.SomeNamespace.SomeBehavior]

}

// implement corresponding setter ...

set behaviors(val){

this._behaviors=val;

}

}

Once the behavior has been extended, simply import the behavior in the element’s template (or element bundle, etc.) and it is available to the template class:

Implementing Multiple Behaviors

Similar to individual behaviors, multiple behaviors can also be defined and extended:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

'use strict';

(()=>{

// define first behavior ...

constFirstBehavior={

properties:{

first:{

type:String,

value:'First Behavior'

}

}

};

// add the behaviors to the given namespace ...

constns=(window.SomeNamespace=window.SomeNamespace||{});

ns.FirstBehavior=FirstBehavior;

})();

first-behavior.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

'use strict';

(()=>{

// define second behavior ...

constSecondBehavior={

properties:{

second:{

type:String,

value:'Second Behavior'

}

}

};

// add the behaviors to the given namespace ...

constns=(window.SomeNamespace=window.SomeNamespace||{});

ns.SecondBehavior=SecondBehavior;

})();

second-behavior.js

In certain cases, I have found it helpful to group related behaviors together within a new behaviors (array) which bundles the individual behaviors together:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

'use strict';

(()=>{

// define first behavior ...

constFirstBehavior={

properties:{

first:{

type:String,

value:'First Behavior'

}

}

};

// define second behavior ...

constSecondBehavior={

properties:{

second:{

type:String,

value:'Second Behavior'

}

}

};

// define third behavior ...

constThirdBehavior={

properties:{

third:{

type:String,

value:'Third Behavior'

}

}

};

// define a behavior which bundles the related behaviors ...

constFourthBehavior=[

FirstBehavior,

SecondBehavior,

ThirdBehavior

];

// add the behaviors to a specific namespace ...

constns=(window.SomeNamespace=window.SomeNamespace||{

'FirstBehavior':FirstBehavior,

'SecondBehavior':SecondBehavior,

'ThirdBehavior':ThirdBehavior,

'FourthBehavior':FourthBehavior

});

})();

Note: As can be seen in the FourthBehavior, a behavior can also be implemented as an Array of previously defined behaviors.

Extending Multiple Behaviors

As with extending individual behaviors, multiple behaviors can also be extended using a behaviorsgetter / setter. However, when extending multiple behaviors in ES6, there are syntactic differences which one must take note of. Specifically, the behaviorsgetter must be implemented as follows: