6.3 Module graph with imports

Overview

This is the first major difference from the hello world program present in the previous chapter. The earlier hello world program had no imports, so the graph ended up with just 1 node, which was for the main module.
In the hello world v2 example, there are imports, so the graph would get bigger. We'll see how the graph gets built and how big it gets.
The graph building happens in the following steps:
  • Add the main module
    • Fetch it
      • Fetch the module
      • Add it to graph
      • Add it to the pending module list
  • Loop over pending modules
    • Visit pending module
      • Parse module
      • Loop through dependencies
        • Fetch them
The main module would get added as before. The dependencies would get added later.

Build the module graph

For hello world v2, the module graph would get built in a number of steps. All the dependencies would be recursively fetched, added, and visited. This would go on till there are no more dependencies.
Add module:
Visit module:
Let's go over the steps and see how the graph gets built:

Step 1

The function add is called with the main module.
Module specifier is file:///Users/mayankc/Work/source/deno-vs-nodejs/helloLogV2.ts.

Step 2

The function fetch is called with the main module specifier.

Step 3

A future is created for fetching the specifier. This future would resolve when fetching is done. The future is added to the pending list.
pending list = [ file:///Users/mayankc/Work/source/deno-vs-nodejs/helloLogV2.ts ]

Step 4

The function add goes in the loop and waits for the next future to resolve in the pending list. The next and only future is the main module fetch future.
At this point graph has only one node, the main module:

Step 5

The main module's future is resolved. The main module specifier has been fetched and cached. The visit function is called for the cached main module. Note that the visit function takes the cached module as input. It doesn't take specifier.
visit = file:///Users/mayankc/Work/source/deno-vs-nodejs/helloLogV2.ts

Step 6

The cached module is parsed. The main module of the hello world v2 program has some dependencies which would be assigned to a fetch future and added to the pending list.
pending list = [ https://deno.land/x/doze/mod.ts, https://deno.land/x/machine_id/mod.ts ]
At this point the graph has three nodes:

Step 8

The pending future would resolve once the module is fetched.
The loop present in the add function processes the next available item in the pending list. https://deno.land/x/doze/mod.ts is the next module to get visited.
visit = https://deno.land/x/doze/mod.ts

Step 9

The cached module is parsed. The parsed module has some dependencies which would be assigned to a fetch future and added to the pending list.
pending list = [ https://deno.land/x/machine_id/mod.ts, https://deno.land/x/doze/doze.ts]
At this point the graph has four nodes:

Step 10

Let's go a bit faster now.
The loop present in the add function processes the next available item in the pending list. https://deno.land/x/machine_id/mod.ts is the next module to get visited.
visit = https://deno.land/x/machine_id/mod.ts

Step 11

The cached module is parsed. There are no dependencies. No more nodes get added to the graph. The graph continues to have 4 nodes.

Step 12

The loop present in the add function processes the next available item in the pending list. https://deno.land/x/doze/doze.ts is the next module to get visited.
visit = https://deno.land/x/doze/doze.ts

Step 13

The cached module is parsed. There are no dependencies. No more nodes get added to the graph. The graph continues to have 4 nodes.

Step 14

pending list = []
There is nothing left in the pending list. The loop in the add function breaks. The module graph has been built.
The final graph looks like this:
--
Unless there are dynamic imports, Deno goes through all the static imports, fetches them, parses them, and finally loads them into v8 before the program or application starts processing. Only dynamic imports are handled later.