
A widget factory is a way of organizing client code that fits perfectly into a multi-page application architecture (MPA).
The article will consider the architectural solution that will optimize the loading of scripts, divide the code into widgets and simplify the transfer of data to the client from the page (when server-side rendering).
Widgets will be called components (or component containers), the initialization point of which will be the DOM. And in which it will be possible to transfer data from the template.
And now everything is consistent.
Concept
The page contains information about the called widgets (the name of the widget, the data for it).
The implementation logic will be basically and the only plug-in that consists of:
')
- Scripts that run on most pages of our application
- Code for all common widgets
Hereinafter, common widgets will be understood as those widgets that are most often needed in an application, for example: navigation, search.
- A hash list of all lazy widgets * containing their names and implementation paths
Hereinafter, lazy widgets will be understood as those widgets that are needed in rare cases. Looking ahead, such widgets will be loaded dynamically, for example: gallery, marketing windows.
- Directly widget factory code
To better understand the concept, let's analyze the implementation example.
Implementation
The implementation of the architecture itself is quite simple, with its version can be found on the
githabe . It is based on the Webpack and its
dynamic import .
Next, run through the main logical points:
- The page contains a script tag containing the name of the widget, the data in the form of JSON
<script type="application/widget+json"> { "widget": "TesLazyWidget", "data": { "1": 1 } } </script>
- Connect entry.js
- Running root scripts
- The widget factory finds all script tags
initWidgets($('script[type="application/widget+json"]'));
- JSON parsing
data = $.parseJSON(script.innerHTML);
- If this is a common widget, then it initializes and remembers it.
widget = new Widget(data);
- If this is a lazy widget then it loads
loaderWidget().then(createWidget);
- Start all memorized common widgets.
for (let i = 0; i < this.widgets.length; i++) { this.widgets[i].start(); }
- Initializes and starts loaded lazy widgets.
const widget = new Widget(data); widget.start();
The implementation is schematic.

The main advantages of this architecture
Increase page loading speed
The main bundle contains only critical scripts, the main functionality. Additional logic will be loaded dynamically. In such a bundle there will be a high percentage of code coverage. This reduces its page size and, as a result, improves performance.
For example, the menu and information about the user will immediately load, and an advertising offer, a gallery of pictures and additional visual effects will dynamically load.
This is a good alternative to routing.
There is no need to create and configure routes and load the necessary scripts depending on URLs or templates. No need to maintain complex dependencies, and therefore decreases the risk of error.
Simplified way to transfer data to the client
Simply by rendering JSON on the page, already at the parsing stage, the data gets to the client, without the need for additional AJAX requests.
<script type="application/widget+json"> { "widget": "ActionBar" , "data": { "isPublic": true, "id": "{{ id }}", "items" : [{ "title": "Edit", "iconLeft": "edit" }] } } </script>
Reducing code duplication
Reuse the widget? Easy! For example, on a page you need to implement several news lists with filters, uploads and other interactive logic. For the implementation of this functionality will be responsible NewsList widget. Similarly to html-tags, it is enough just to insert into the template a call to this widget as many lists as needed, and everywhere it is required.
<script type="application/widget+json"> { "widget": "NewsList", "data": { "contentId": "business" } } </script> <script type="application/widget+json"> { "widget": "NewsList", "data": { "contentId": "policy" } } </script>
The code becomes more readable and understandable.
The widget factory formalizes the rules for writing code, which in turn creates a clear structure for initializing and executing scripts. In this approach, the widget call chain is linear. The logic of each of them is encapsulated, and, as a result, less unforeseen consequences of code changes, less welfare in the project, and greater system flexibility.
Great way to organize code for “old” projects
When in the application everything is already written, but without a special idea. The constant feeling of mess does not leave. And in the project pretty often inline scripts
<script> require(['jquery', 'selectBoxIt'], function ($) { $('#itemId_selector').selectBoxIt(); var $form = $('#savepost'); …….. $('#skip').click(function () { $form.submit(); }); }); </script>
you just need to create a widget and transfer this code to it. Thus, the widget factory is a great way to switch to the component approach.
Plus, you can automatically generate a list of widgets, like, for example,
here . This will simplify the creation of a widget before creating a directory with its name and a file with its implementation, which, in fact, can also be automated.
Instead of conclusion
As a result, the widget factory fits perfectly into the MPA architecture. Formalizes the code, optimizes loading and gives clear and convenient rules for use.