Skip to content

Loading Modules

Jonathan Eiten edited this page Feb 7, 2018 · 3 revisions

Modules

Modules are a way of breaking up your code into logical pieces to maintain a separation of concerns.

On a practical level, JavaScript modules are files that resolve to a single object. Modules need to be accessible by your code, which means they need to be loaded in memory one way or another; and they need to set or return a reference to themselves.

Loading modules

Let's take as an example Hypergrid plug-ins, which are modules. Let's load a hypothetical plug-in named event-logger.

The plug-in can be built into your app and loaded with it, or can be loaded separately by the client:

  • CommonJS modules are "bundles" together at build time into a single file which is loaded at run time with a single <script> tag.
  • Client modules are individual files that are loaded at run time, each with its own <script> tag.

CommonJS modules

At build time, Browserify or webpack converts a base file, typically /index.js, and any other files it "requires" (and anything they in turn "require", etc.) into a single build file.

This file can then be loaded by the client with a single <script> tag:

<script src='my-build.js'></script>

Client modules

If not using Browserify or webpack, the client loads each "required" module separately:

index.html:

<script src='https://fin-hypergrid.github.io/core/2.0.2/build/fin-hypergrid.min.js'></script>
<script src='https://fin-hypergrid.github.io/event-logger/1.0.0/build/event-logger.min.js'></script>
<script src='main.js'></script>

In the above:

  1. Hypergrid loads itself synchronously into the fin.Hypergrid global.
  2. Other files must then be loaded (synchronously or asynchronously) into members of the fin.Hypergrid.modules namespace.

The file main.js is a "wrapped" version of index.js:

window.onload = (function(require){
    /* index.js contents goes here */
}).bind(null, fin.Hypergrid.require);

A gulp or grunt watch task can be set up to do the wrapping.

Alternatively, you can avoid wrapping by using Hypergrid.require() instead of require(). The advantage of wrapping is that index.js remains a CommonJS module, which is nice if your intention to to eventually migrate to bundling the code into a single file with Browserify or webpack.

Hypergrid Client Modules

While the above guidelines are sufficient, a Hypergrid Client Module has a wrapper that does both of the following:

  • Inserts the module into Hypergrid.modules
  • Supports module, moudle.exports, exports, and require within the module

Therefore, a Hypergrid Client Module is available to other such modules via require as well as being able to use require itself to load other such modules. If modules are dependent on one another in this way, they must be loaded synchronously. Forward and circular references are not supported.

The following utilities help wrap up modules as Hypergrid Client Modules:

  • fin-hypergrid-client-module-wrapper defines a succinct little wrapper that in addition to making require() available (similar to the simple wrapper shown above), also makes module, module.exports, and exports available and also transparently assigns fin.Hypergrid.modules[modulename] = module.exports for you.
  • fin-hypergrid-client-module-maker defines a standard gulp task for wrapping your code. It also defines standard lint and test tasks.

See also the Client Modules wiki that describes the concept in more depth.