How to Build Scalable Web SPA Systems with NEJ: Module Architecture Explained

This article walks through using NetEase's NEJ framework to decompose a complex single‑page web application into hierarchical modules, create and format dependency trees, register external and layout modules, define module directories, implement module logic and messaging, and finally integrate and package the system for scalable deployment.

ITFLY8 Architecture Home
ITFLY8 Architecture Home
ITFLY8 Architecture Home
How to Build Scalable Web SPA Systems with NEJ: Module Architecture Explained

Example Analysis

Using NetEase's NEJ framework, this article demonstrates how to achieve high scalability for a complex web interactive system by analysing and applying module‑level architecture.

System Decomposition

When a complex system is obtained, a hierarchical relationship diagram of its modules is drawn from the interaction mock‑up, and the modules that are externally accessible are identified.

Abstract Dependency Tree

From the hierarchical diagram, an abstract dependency tree is easily derived.

The tree is then formatted according to UMI rules: a root node named “/” is added, and each node receives a default “/” child node.

Resulting characteristics:

For any node (except the root), the UMI value is the concatenation of node names on the path to the root, separated by “/” (e.g., the list node has UMI "/m/blog/list").

Modules registered on a node depend on modules registered on all its ancestor nodes.

Registering External Modules

Five externally accessible modules—log, tag, profile, experience, permission—are mapped to appropriate leaf nodes in the dependency tree.

Registering Layout Modules

Traversing from each external module toward the root, the first node where two modules intersect becomes the layout module registration point; system‑wide components are registered at the root so that any module can rely on them.

Mapping Module Functions

The principle is that a common parent node implements the shared functionality of its child modules. For example, the blog and setting nodes share the parent node “m”, so the functionality common to both is implemented in the “m” module.

Decomposing Complex Modules

Complex modules are further split into reusable modules (e.g., a log list that can appear on a page or in a popup) and loosely coupled modules (e.g., a tag list that does not affect the log list).

Resulting Dependency Trees

Two trees are produced: one for external modules and one for private modules.

Module Specification Table

The specification table illustrates how modules can be combined or kept separate depending on the project’s needs.

Project Directory Structure

The project directory is organised as follows:

webroot                // front‑end development related directory
 |- res                // static resources (can be versioned during packaging)
 |- src                // source code (not deployed to production)
     |- html
         |- module    // single‑page modules; all module implementations reside here
         |- app.html // entry page

Module Unit Structure

Each module unit consists of:

Module test – independent testing page for the module.

Module structure – a set of templates extracted from the static structure.

Module logic – business logic inheriting from the module base class.

Module style – module‑specific CSS (usually placed under the css directory).

Module Implementation – Structure

Static pages are assumed to be completed; the module implementation focuses on splitting static structures into NEJ templates. External resources must use relative paths and be marked with @TEMPLATE for later packaging.

Module Implementation – Logic

Modules extend _$$ModuleAbstract and implement lifecycle methods: __doBuild – build structure, cache nodes, initialise component configuration. __onShow – place module into container, allocate components, bind events. __onRefresh – fetch data based on input parameters and render. __onHide – recycle components and restore the state after hide.

/* Project module base class */
NEJ.define(['base/klass','util/dispatcher/module'],function(_k,_t,_p){
    var _pro;
    _p._$$Module = _k._$klass();
    _pro = _p._$$Module._$extend(_t._$$ModuleAbstract);
    _pro.__doSomething = function(_args){ /* TODO */ };
    return _p;
});

Specific module implementation example:

/* Project module implementation */
NEJ.define(['base/klass','util/dispatcher/module','/path/to/project/module.js'],
function(_k,_e,_t,_p){
    var _pro;
    _p._$$ModuleDemo = _k._$klass();
    _pro = _p._$$ModuleDemo._$extend(_t._$$Module);
    _pro.__doBuild = function(){ this.__super(); /* TODO */ };
    _pro.__onShow = function(_options){ this.__super(_options); /* TODO */ };
    _pro.__onRefresh = function(_options){ this.__super(_options); /* TODO */ };
    _pro.__onHide = function(){ this.__super(); /* TODO */ };
    _e._$regist('umi_or_alias',_p._$$ModuleDemo);
    return _p;
});

Message Communication

Modules can send point‑to‑point messages via __doSendMessage and receive them by implementing __onMessage. They can also publish and subscribe to broadcast messages.

// Sending a message
_pro.__doSomething = function(){
    this.__doSendMessage('/m/setting/account/',{a:'aaaaaa',b:'bbbbbbbbb'});
};

// Receiving a message
_pro.__onMessage = function(_event){
    // _event.from – source
    // _event.data – payload
    // TODO
};

System Integration

During integration, map the nodes that need module registration in the dependency tree to their implementation files. The article shows examples for both external and private modules.

Configuration Examples

Rule configuration (rewrite, title, alias) and module mapping are defined in JSON‑like objects.

rules:{
    rewrite:{'404':'/m/blog/list/','/m/blog/list/':'/m/blog/','/m/setting/account/':'/m/setting/'},
    title:{'/m/blog/tag/':'Log Tag','/m/blog/list/':'Log List','/m/setting/permission/':'Permission Management','/m/setting/account/':'Profile','/m/setting/account/edu/':'Education'},
    alias:{'system-tab':'/?/tab/','blog-tab':'/?/blog/tab/','layout-system':'/m',...}
}
modules:{
    '/?/tab/':'module/tab/index.html',
    '/m':'module/layout/system/index.html',
    '/m/blog/list/':{module:'module/layout/blog.list/index.html',composite:{box:'/?/blog/box/',tag:'/?/blog/tag/',list:'/?/blog/list/',clazz:'/?/blog/class/'}},
    ...
}

Application Startup

The dispatcher is started with the defined rules and modules, automatically handling routing, alias resolution, and module composition.

NEJ.define(['util/dispatcher/dispatcher'],function(_e){
    _e._$startup({
        rules:{...},
        modules:{...}
    });
});

Packaging and Release

Packaging details are covered in the NEJ toolset documentation.

System Changes

When requirements evolve, new modules can be added or obsolete ones removed simply by updating the configuration without touching business logic.

Adding a module involves implementing it as described above and, if the functionality already exists elsewhere, just adding an alias entry such as:

alias:{'blog-tag':['/m/blog/tag/','/m/setting/tag/']}

Removing a module only requires deleting its UMI entry from the module map.

Conclusion

With the rapid growth of SPA technology, scalability of both the platform and its modules becomes critical. The NEJ framework provides a comprehensive solution for modular decomposition, dependency management, and flexible configuration, as demonstrated through real NetEase products like Cloud Music PC, Yixin WebIM, and others.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptfrontend developmentmodule architecturedependency treeNEJscalable SPA
ITFLY8 Architecture Home
Written by

ITFLY8 Architecture Home

ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.