I haven’t started writing for several months. Recently, I have been studying some technical things with my team. I happen to have some content about the front-end module to share with you.

Before we get down to business, let’s review a brief history of the front end module from scratch

If you have any experience and have lived in the jQuery era, you should know that the early front-end modules were just local variables on the window.

In the early days, front-end engineers used Windows to share their code, an ancient practice that is still used by many people because of its simplicity. For example, if we write a script, we usually don’t think of it as a module, but we get used to wrapping the script as an object. For example,

window.myModule = {
    getName(name){
        return `hello ${name}`}}Copy the code

When someone else loads the script, it is easy to call the getName method through window.myModule.

Early JavaScript scripts were mainly used to develop some simple forms and web page interaction functions. At that time, the number of front-end engineers was also very few, so it was not a big problem to implement modularization through Window.

Until the advent of Ajax pushed the Web into the rich client phase, with the rise of SPA, front end engineers found it increasingly difficult to maintain Windows modular code for two main reasons

  1. A large number of module loads contaminate the Window, causing all sorts of naming conflicts and accidental overwrites that are difficult to locate.
  2. As more and more modules interact with each other, the loading order of script tags needs to be artificially guaranteed in order to ensure the order of calls

In order to solve this problem, module loaders like Require SeaJS have been created. Through module loaders, these two problems are greatly alleviated.

But the front-end technology and the development of the Internet speed is far beyond our imagination, as the web more and more like a real client, the front-end engineering ability put forward the challenge, only by a simple script development has been difficult to meet the needs of the project, and gulp scaffold for the front-end engineering management begin to enter our field of vision, However, at this stage, there is no organic combination between module loader and front-end engineering flow.

It wasn’t until NodeJS came along that the front end got its own package management tool, NPM. On this basis, Webpack further promoted the integration of front-end engineering flows and modules, and then the process of front-end modularization began to take hold, which has been maintained to this day.

Looking back from this history, the whole process of front-end modularization, including es6 standards on Modules, has always been around this one core proposition.

There is no difference between require and Webpack in the core proposition that front-end modules follow

Load → call → execute such a logical relationship. Because modules must be loaded before they can be called and executed, module loaders and build tools must manage and analyze the dependencies of all modules in an application to determine which modules can be split and which can be combined, as well as the order in which modules are loaded.

However, as time goes by, the front-end application has more and more modules, and the application is getting bigger and bigger. Our local node_modules starts from hundreds of megabytes. Although Webpack has made a lot of optimization, the rebuild time is still very slow in front of large applications.

In February of this year, Webpack 5 released their module dismantling solution, Module Federation, a plug-in that solves the problem that webPack-built modules cannot be reused in multiple projects.

Earlier yarn 2.0 used shared node_moudles to solve the performance problem caused by a large number of redundant local modules. Nodejs abandons NPM in deno and uses network to load modules.

You can see that the community has realized that the pioneering front-end modularization mechanism is once again facing bottlenecks, both in terms of performance and maintenance costs, and teams are looking for ways to move in a new direction.

However, these efforts do not go beyond the core proposition of the modularity-first mechanism, which is that modules must be loaded and then invoked.

As long as this core proposition remains unchanged, the module dependency problem remains unsolvable. So we try to put forward a new idea

Why can’t a module be called first and then loaded and executed?

If module A calls module B but does not need module B to be ready immediately, this means that the module loader can be indifferent to module dependencies and focus solely on the efficiency and performance of module loading.

At the same time for the build tool, if the execution of A module is not based on B module ready immediately, then the build tool can safely split A and B module into two files, if there are many modules, can take advantage of http2 parallel loading capability, greatly improve module loading performance.

In our vision, a new way to load modules looks like this

// remoteModule. Js this is a remoteModule published to the CDN, the internal code is like this

widnow.rdeco.create({
    name:'remote-module'.exports: {getName(name, next){
            next(`hello ${name}`)}}})Copy the code

Instead of loading the module, let’s just execute the code on the calling side like this

Window. rdeco can be thought of as something similar to Webpack Runtime, but rdeco is a stand-alone library that does much more than that

// localmodule. js this is a localModule
window.rdeco.inject('remote-module').getName('world').then(fullName= >{
    console.log(fullName)
})

Copy the code

Then we load localModule.js and remoteModule

<scirpt src="localModule.js"></script>
<scirpt src="remoteModule.js"></script>

Copy the code

Localmodule. js will attempt to call remote-Module’s getName method after loading, but remoteModule has not yet loaded. To avoid this problem

The module builder needs to analyze the code in both files to find that localModule.js depends on remoteModule. Js, and then save the order of dependencies, notifying the module loader that remoteModule.

But if modules can be called first and then loaded, this complicated process can be completely avoided. Codesandbox.io /s/tender-ar…

Try clicking on the Call Remote Module’s getName Method button

The copy doesn’t change, it just says hello, but the code doesn’t throw an exception, and then you click the Load remoteModule button and start loading remoteModule. When the Load is complete, the getName will actually execute. Now the copy becomes hello World

The above example is a microcosm of our rethinking of front-end modularization and code splitting. We use a lot of similar ideas in actual application development, and currently related functions are encapsulated in RDECo: github.com/kinop112365… If you are interested in our work, please follow star at 👏🏻 and leave a comment below