5.10 Load module
Last updated
Last updated
This subsection holds significant importance, perhaps being the most pivotal one within the text. In the upcoming paragraphs, as well as those that follow, the discussion revolves around the manner in which Deno undertakes the loading of modules into the V8 engine. Up until this juncture, Deno's efforts have predominantly been directed towards our specific program by transforming the given path into a module specifier and accomplishing a substantial portion of its initialization tasks.
The load_main_module
function in JsRuntime is a significant piece of code, notable not for its length, but for its diverse functionality. In the following discussion, we will explore key aspects of this function. The module loading process follows a recursive pattern, continuing until both the main module and its dependent submodules are successfully loaded.
The sequence of actions involved in module loading occurs through a sequence of distinct steps:
We have repeatedly traversed these steps multiple times within the recent preceding sections. We begin by considering the root module and initiating its loading. Following this, we load all associated dependencies. Afterward, both the root module and its dependencies are brought into existence. This phase involves the instantiation of the root module along with its dependent modules. As we conclude this loading process, the main module, along with its dependencies, finds instantiation within the V8 engine. This iterative process has been extensively covered in the preceding sections, providing a comprehensive understanding of the sequential actions involved.
The process of loading a module in Deno occurs through a sequence of clear steps. Let's take a closer look at each of these steps to better understand how it all works:
Acquiring the Module Loader: To begin, Deno retrieves the module loader, which is responsible for managing and orchestrating the module loading process.
Loading and Registering Modules and Dependencies: The next step involves a recursive procedure where both the main module and all its associated dependencies are loaded and registered. Deno meticulously fetches each module, making sure all the interdependencies are accounted for and properly integrated.
Generating the Module Graph: As a result of the comprehensive recursive loading process, something referred to as a "module graph" is formed. This graph essentially represents the intricate web of connections between different modules and their relationships.
Creating Instances of the Main Module: After successfully establishing the module graph, Deno proceeds to create instances of the main module. This is achieved using the unique identifier of the root (main) module as a reference.
The underlying code that drives the loading of the main module within the JavaScript runtime is encapsulated in the function named load_main_module
. This function embodies the logic that orchestrates the entire process we've just outlined.
Now, let's take a quick look at the steps involved in this process.
Recursive module loading might seem intricate, but it's a systematic process that unfolds in the following manner:
We kick off with the root module or the main module, treating it as the starting point. This module is fetched from its source. Afterward, it's established as the foundational module within the module graph, which is like a visual representation of how different modules are connected.
To make sense of the main module's content, it's parsed – essentially, we break down its code to understand its structure and components. But a module rarely stands alone; it often relies on other modules. Thus, we traverse through its direct dependencies, each time fetching a dependency, parsing it, and then adding it to our module graph.
This recursive procedure keeps going until all the required dependencies have been processed. As the code in these modules contains imports, these imports signify ES modules, a way of structuring code for better organization and reusability.
In this journey of exploration, the code dives deeper into the module tree, loading each module it encounters along the way. Having constructed the graph step by step, the next phase involves transpilation – converting the graph into a format that's more suitable for execution.
Now, it's time to traverse this transpiled graph, registering each module as we encounter them. The purpose of registration is to furnish all the necessary module details to the V8 engine, which is responsible for executing JavaScript code.
Once everything is set up, modules come to life. The process of instantiation involves taking each module and its dependencies and initializing them within the V8 engine. This final step ensures that your code can run seamlessly, leveraging the interconnected modules to perform the tasks you've programmed.
Recursive module loading is akin to navigating a forest of interconnected trees, where each tree symbolizes a module. Our journey ensures effective exploration, understanding, and assembly of these modules for seamless execution.
While the process may seem complex, with many steps involved, the v8 engine simplifies module loading into two essential steps:
Loading the module
Instantiating it
Iterate through the graph in an asynchronous manner while registering all the modules. This process is notably simpler when contrasted with loading modules recursively. By adopting this approach, the complexity of handling module registrations is significantly reduced. In comparison to the intricate nature of recursive module loading, this method offers a straightforward and efficient means of managing module dependencies.
Upon the completion of the registration process, both the main module and its dependencies are loaded into the V8 engine. Now comes the moment to create an instance of the root module. This action is only necessary for the root module; V8 will take care of managing and retrieving all the required dependencies using callbacks.
--
That was just a brief overview to get us started. Now, let's dive deeper into the next section, where we'll explore the construction of the module graph in greater detail. This graph is a crucial data structure in Deno's internal workings, and understanding it is essential to appreciating how Deno operates.