Classic Dependency Management Approach Compared to RequireJS

    Hello World,

    Helios Kernel is a library for managing dependencies between javascript modules, which implements the “classic” approach, which is often found in other languages ​​and environments using the include () function.

    This method differs from other approaches in its simplicity: dependencies are listed at the beginning of the module by the exact path to the file, the module body contains code that runs after loading the module’s dependencies.

    Helios Kernel adheres to the KISS principle, therefore, there are some features that are not expected today from the dependency management library. When using Helios Kernel, it is not necessary to describe a config with rules for finding paths for different modules, or to export library functions through a special object. But this library was written just because I just wanted to connect the necessary modules and write code, without running into cool features when specifying each new dependency.

    Helios Kernel supports the dynamic loading (and unloading) of dependencies in runtime, and the library itself and the module format are compatible between nodejs and the browser environment - that is, the modules can be used without modification or translation.

    This article compares the classic Helios Kernel approach with dependency management using RequireJS and shows how the Helios Kernel approach avoids some of the complexity.


    Helios Kernel has the following features:

    • Dependencies are defined using the include () function in the module header. The exact relative path to the file is used as an argument.
    • After listing the dependencies, the init () function containing the module code is defined. This code will be executed after loading all the dependencies

    Therefore, the description of the relationship between the two modules is as follows.

    The library module myLibrary.js, declaring some functionality:

    init = function() {
        // объявление (глобального) библиотечного объекта
        myLibrary = {};
        // библиотечная функция
        myLibrary.writeHello = function() {
            console.log("Hello World!");

    And the module connecting and using this library:

    init = function() {
        // здесь библиотека подключена и можно её использовать

    Here, to “export” the library object, the definition of the global variable myLibrary in the first module is used. Now this method is considered to be "wrong", because global objects can be accessed from anywhere. But I use it here, since it is the most obvious as an example. Helios Kernel does not impose any restrictions on the way objects are transferred between modules: any code can be inside the init function. Including there you can define a factory function, which will return only the "exported object".

    But if you only need to determine the local variables of the module, you can use the scope of the init () function for this.

    Next, I will give examples in which using Helios Kernel makes code easier than RequireJS

    Module descriptions

    The format of the description of the module with dependencies looks like this:

    RequireJSHelios kernel
        // зависимости
        ['fooLibrary', 'barLibrary'],
        function( foo, bar ){
            // использование

    // зависимости
    init = function() {
        // использование

    The method of exporting library objects used in RequireJS forces you to specify the name of the dependency twice - once the name of the module where the dependency is located, the second time - the name of the argument where this dependency will be exported.

    This makes reading RequireJS modules more difficult to read when there are more dependencies:

    RequireJSHelios kernel
        [ 'dep1', 'dep2', 'dep3', 'dep4', 'dep5', 'dep6', 'dep7' ],
        function (  dep1,   dep2,   dep3,   dep4,   dep5,   dep6,   dep7) {
            // ...

    init = function() {
        // ...

    In order to simplify such code, RequireJS even came up with an alternative way to describe dependencies, simplified CommmonJS . Using this technique, you can describe the dependencies as follows:

        [ 'dep1', 'dep2', 'dep3', 'dep4', 'dep5', 'dep6', 'dep7' ],
        function (require) {
            var dep1 = require('dep1'),
                dep2 = require('dep2'),
                dep3 = require('dep3'),
                dep4 = require('dep4'),
                dep5 = require('dep5'),
                dep6 = require('dep6'),
                dep7 = require('dep7');
                // ...

    Such a record makes formatting a bit easier and improves readability, but even here you have to mention the name of the dependencies several times. In addition, this syntactic sugar adds another complication in the form of another way to access dependencies.

    Helios Kernel avoids all this. An additional dependency requires only one mention with include ().

    Creating assembly modules

    Suppose there are several modules that are often used together in many parts of a project. Or there is a library that consists of several parts, and you need to get all these parts at once. The easiest way to get multiple modules is to connect them all explicitly every time where they are needed.

    But after all, a large project is divided into modules in order not to duplicate extra code. Therefore, you can write one common module that will connect the rest.

    However, in the case of RequireJS, it will still be necessary to export the required dependencies and “forward” them through the exported object of the general module.

    In the case of Helios Kernel, it is enough to simply list the dependencies:

    RequireJSHelios kernel
        [ 'dep1', 'dep2', 'dep3' ],
        function( dep1, dep2, dep3 ) {
            return {
                dep1 : dep1,
                dep2 : dep2,
                dep3 : dep3


    For a general module written in Helios Kernel format, you don’t even need to describe the init () function. It also simplifies readability - if you look at the code of this module, you can immediately see that it does not perform any actions, but only connects additional modules.

    But in the case of a common module with RequireJS, you also have to rewrite all cases of its export. If earlier individual exported parts had to be addressed as dep1, dep2, ..., now it needs to be replaced with depCommon.dep1, depCommon.dep2, ...

    Easy to use regular javascript libraries

    We are talking about libraries that are supposed to be connected to an html page using a script tag.

    The format of the Helios Kernel module is much closer to regular libraries, because the init () function can contain any code. Therefore, in order to turn a regular library into a module, it is enough to wrap it in the definition of the init () function, and after that it can be connected using include ().

    In the case of RequireJS, converting a library to a module is much more difficult, because the module must export the defined objects, and you would have to do the refactoring. Instead, it is proposed to describe the module in the config using the shim attribute . However, even such an approach can lead to problems .

    Easy porting between web and nodejs

    In order to use RequireJS modules on a server in a nodejs environment, you can use the r.js library , which allows you to connect such modules to nodejs.

    On the flip side: a project written in the CommonJS module format used by node can be converted to a web library using browserify . But this will not be a module, but a large bundle connected by a script tag (or the shim config in RequireJS).

    Helios Kernel simplifies this task due to the fact that the modules work without changes and conversion on both platforms.

    Code: gz

    Also popular now: