You are viewing the Articles in the JavaScript Category

Quick Tip: React Spring & Babel Loader

Recently, I had integrated React Spring within an Application, and while it is one of the best Animation Libraries for React I have come across in quite some time; unfortunately, I encountered some issues when running tests and production builds.

Essentially, the issues I experienced were related to the imported modules being written in ES6. This was an issue for me as I prefer to have webpack babel-loader configured to exclude node_modules and only transpile project sources.

Fortunately, the work around for this is quite simple: just import the CommonJS modules (i.e. .cjs extensions) rather than their ES6 counterparts (i.e. no extension).

Thus, simply changing:

To:

Resolves the issue.

And so, should you happen to come across build issues when using React Spring, a nice alternative to including the node_modules directory or specific dependencies is to simply import the CommonJS modules.

Synchronizing package.json with yarn.lock


After having used Yarn almost exclusively for the past couple of years, there has been one nagging issue which seemed to continually crop up. Specifically, the inability to have a project’s package.json dependency versions kept in sync with the actual versions in yarn.lock. And so, while running yarn upgrade results in all packages being updated to the latest versions (as specified via the given semver ranges), the versions defined in package.json are not updated to reflect that which they have been upgraded to.

This can prove problematic as, one can not easily discern a project’s dependency versions by simply viewing their respective values in package.json.

In particular, as part of process, after each production release I have scripts which are executed to automate the process of updating all project dependencies to their respective latest Minor and Patch revisions prior to opening master for new development. While the scripts manage the updates and committals internally, each project’s package.json would remain unmodified, making it challenging to determine which packages have been upgraded, and which have not. Having to automate or manually inspect the yarn.lock files is less than ideal, and quite cumbersome to say the least.

Fortunately, like most things in the Javascript world, there is a package for this; syncyarnlock, which provides exactly what one would need to ensure that the dependency versions defined in package.json are kept in sync with the project’s yarn.lock.

Simply install syncyarnlock, and execute with the options applicable to your needs.

For example, to sync a project’s package.json with the project’s yarn.lock, and have the ranges remain intact while updating the versions to reflect what will actually be installed, simply run: syncyarnlock -s -k.

This will result in the dependency ranges being preserved, while also updating their versions to reflect the versions that will actually be installed.

And with that, we have proper syncing. A definite time-saver!

Separation of Concerns: propTypes and Immutable.js

When considering the separation of concerns between Container and Presentational Components (stateful / stateless components), I find it useful to leverage the core concepts of these patterns in order to define a clear boundary between where Immutable data types are used, and where raw JavaScript types are referenced exclusively.

By having a clear separation which compartmentalizes where Immutable types are used and where they are not, team members are afforded the ability to easily determine a components propTypes; as, without having a clear cut-off point, one must give thought as to if a prop passed down to a component will be an Immutable object, or not.

It’s no stretch of the imagination to see how this can quickly lead to code which becomes much harder to maintain than it needs to be. As such, the Container / Presentational Component pattern provides a rather natural boundary for separating these concerns.

Unfortunately; however, while such a boundary may seem rather obvious, it may not always be clearly defined, and this tends to lead to overly complex propType declarations.

For instance, on a number of occasions I’ve seen propTypes declared similar to the following:

Given the above example, it’s obvious that it was unclear to the original implementor (or current maintainer) of SomePresentationalComponent as to what the expected propTypes will ultimately be. In certain cases, it appears someList could be of type array; whereas, in other cases, it could be of type object (e.g. Immutable.List). Likewise, in some cases someItem could be an object, whereas in others it could be an Immutable.Map.

As you can see, this is obviously problematic and indeed a very good candidate for a bug (not to mention, a maintenance headache indeed).

Moreover, it results in all sorts of unnecessary type check permutations before accessing properties. For example, just to check the length of the list:

Likewise, just to get the id of someItem:

At best, this is far from ideal, to say the very least …

Now, obviously the developer could simply define a single propType and refactor Containers which are passing an invalid type; however, it may not always be clear what the type should be, if say, the component is being used by multiple applications to which the developer does not have access, and some of those applications are not using Immutable.js, in which case, it would be best to simply disallow Immutable from the component all together and have consumers of the component update their Containers. In any event, it’s symptomatic of a team not having a clear understanding of what kind of components work exclusively with Immutable data types, and which do not.

Solutions

Fortunately, as one might imagine, there are a couple of very simple solutions to this problem:

  1. Only use Immutable types throughout the entire application.
  2. Segment which components use Immutable types, and which do not.

Now, in some cases the argument for Option #1 may very well be a valid one; however, I find Option #2 to be much more feasible (and flexible) as, it helps to ensure Presentational component are kept pure, and that means only using JavaScript types. For my purposes, this is especially important as I have to maintain a shared library which must limit dependencies as much as possible; and some projects are using Immutable, Redux, etc., and some are not. As always – consider the context.

Pros

By having an internal design contract (or convention) which mandates that Container components are only ever to work with Immutable types and, Presentational components are only ever to be passed JavaScript data types, it becomes much clearer to team members where the boundary is defined, and thus, much easier to maintain a large application over time.

Furthermore, it allows less experienced developers to gradually become acclimated with the React Ecosystem by assigning them tasks focused on presentational features. This can be very useful as it only requires knowledge of core concepts without being inundated with additional libraries and APIs. This approach also affords team members with more experience to focus on the more complex portions of the application (application logic, reducers, containers, etc.).

In addition, destructuring, …rest parameters and related ES6 features can be used much more extensively to simplify implementation when using JavaScript types exclusively, helping to ensure Presentational components are kept intentionally “dumb”. Not to mention, in doing so, testing becomes considerably less complex when working with native JavaScript types – and this is equally important when helping newer developers become productive while still getting up to speed.

And, while not always likely, by reducing our dependency on Immutable.js, we position ourselves for a much more easier migration path in the event we decide to swap out Immutable for another library in the future.

Cons

Arguably, one could be justified in the assertion that only Immutable Data types should be used by both Container and Presentational components (Option #1), and indeed that would be a fair argument if you will be calling toJS() frequently when passing props down to Presentational Components (as there is obviously an inherent expense in doing so).

That being said, there is no reason why one would need to call toJS when passing props to Presentational Components as the Immutable API can be utilized to reduce the given props before being passed down to child components. In such cases, a Higher Order Component can be defined for doing either, which can simplify implementation considerably.

Summary

Like most design decisions, there is rarely a one-size-fits-all approach that perfectly solves any given problem, and what ultimately makes sense in one context, may not always be appropriate in another. However, in the context of when and where Immutable types are used, in most cases it is fair to say there should always be a clear boundary defined, regardless of where that boundary must be.

Unique Identifiers with JavaScript Symbols

JavaScript Symbols

The introduction of Symbols in ES6 marked a significant milestone, offering developers a new primitive type to enhance code clarity, privacy, and interoperability.

At their core, Symbols serve as unique, immutable identifiers, making them quite valuable for many use-cases. This article delves into the benefits of JavaScript Symbols, illustrating how they can be leveraged to provide implementations which are more secure and mitigate the risk of unforeseen conflicts.

Before we explore the benefits of Symbols, it’s important to first understand what the actually are. In JavaScript, a Symbol is a primitive data type, just like string, number, boolean, etc.. However, what sets Symbols apart is their guarantee of uniqueness. Every time you create a Symbol, it is distinct from all other Symbols, even if they share the same value.

Creating a Symbol is rather straightforward:

Despite having the same value, name1 and name2 are not equal.

There are numerous benefits to using Symbols, especially when using them within Objects.

Ensuring Property Uniqueness:
One of the most prominent benefits of Symbols is their role in ensuring property uniqueness within objects. This uniqueness is particularly beneficial in avoiding property name collisions, especially when working with complex implementations or when integrating third-party libraries.

Symbol Properties are Not Enumerated:
Another advantage of Symbols is that properties keyed by Symbols are not enumerated in for...in, or Object.keys(), Object.values(), or Object.entries(). This characteristic can be used to hide certain properties from the enumeration process, thus providing a form of property privacy.

Facilitating Meta-Programming:
Symbols play a pivotal role in JavaScript’s meta-programming capabilities. Several well-known Symbols, are used to customize the behavior of certain language constructs. For example, Symbol.iterator allows an object to define its iteration behavior, enabling it to be compatible with both the for...of loop and spread operator.

Enhanced Debugging:
Symbols can also aid in debugging by providing a descriptive identifier for otherwise anonymous properties. When you create a Symbol with a Symbol description, this description is shown in debugging tools, making it easier to identify and differentiate between various Symbols.

JavaScript Symbols present a robust mechanism for ensuring uniqueness, enhancing privacy, and empowering meta-programming within applications. By leveraging Symbols, developers can avoid common pitfalls such as property name collisions and inadvertently exposing internal properties, leading to more secure, maintainable, and sophisticated deigns. As JavaScript continues to evolve, understanding and utilizing Symbols will undoubtedly become an essential skill for modern web developers.

React PropTypes and ES6 Destructuring

At times one may be justified in the argument that cognitive (over)load is just an expected part of the overall developer experience. Fortunately, there are numerous steps we can take to minimize the general noise which tends to distract our intended focus. One particularly simple – yet effective – example is to remove unnecessary redundancy wherever possible. In doing so, we afford both our peers and ourselves a codebase which, over time, becomes considerably easier to maintain.

For instance, when performing code reviews, more often than not I tend to see considerable redundancy when specifying React PropTypes. Typically, something along the lines of:

As can be seen, with each new prop we are redundantly referencing React PropType lookup paths. And, while the ideal components will have a limited number of props (either connected directly, or passed down), the redundancy still remains for any component which references the same prop type. Considering the number of components a given application may contain, we can rightfully assume that the above redundancy will grow proportionally.

With the above in mind, we can easily reduce the redundancy (as well as micro-optimize the lookup paths) be simply destructuring the props of interest as follows:

While I would consider the above to be simplified enough; one could also take this a step further and destructure the isRequired props, which, in some circumstances, may be useful as well:

Admittedly, this example is rather straight-forward; however, it does help to emphasize the point that only through consistent vigilance can we ensure our source will continue to evolve organically while remaining as simple as possible.

Simplified Partial Application with ES6

When implementing Partial Application in ES6, implementations naturally become quite easier to reason about as default parameters, rest parameters and arrow functions can be leveraged to provide a much more comprehensive implementation.

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.

In ES5, we could implement such a function as follows:

View Pen

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:

View Pen

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:

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

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.