“This is the second day of my participation in the August More Text Challenge. For details, see: August More Text Challenge.”

Module parsing is the process by which the compiler finds out where the imported content is pointed. For example, import {a} from “moduleA”. To check the use of object A, the compiler must know what a means, and moduleA needs to be checked.

At this point, the compiler asks what type is “moduleA”? Of course, the problem sounds simple enough that moduleA is defined in ts/ TSX files, or relies on.d.ts files.

First, the compiler tries to define a file that represents the module being imported. The compiler chooses one of two strategies to locate the file: Classic or Node. These two policies tell the compiler where to look for moduleA.

If neither of these works and if the module name is non-relative, the compiler tries to locate the Ambient Module declaration.

Eventually, an error will be printed if the module cannot be parsed.

Relative vs. Non-relative module imports

I’m not going to give you a Relative. / start the module. Does not resolve the Ambient Module declaration.

Non-relative: “jquer”, “@angular/core”, etc. Ambient Module Declaration can be parsed

Module resolution strategy

As mentioned above, there are two kinds of parsing strategies. Without a specific yes, Node is the default policy for commonJS modules; All other modules are Classic strategies. You can specify a policy through the –moduleResolution option.

Classic

Used to be the default resolution policy for TS. Now it’s a backwards compatible strategy.

For relative Module:

Import {b} from ‘./moduleB’ in /root/src/folder/ a.ts:

  1. /root/src/folder/moduleB.ts

  2. /root/src/folder/moduleB.d.ts

For non-relative Module:

Import {b} from ‘moduleB’ in /root/src/folder/ a.ts:

  1. /root/src/folder/moduleB.ts

  2. /root/src/folder/moduleB.d.ts

  3. /root/src/moduleB.ts

  4. /root/src/moduleB.d.ts

  5. /root/moduleB.ts

  6. /root/moduleB.d.ts

  7. /moduleB.ts

  8. /moduleB.d.ts

Node

First, see how Node resolves modules.

Relative Module: var x = require(“./moduleB”)

1. Check whether /root/src/moduleB.js exists

2. Check whether package.json exists in the /root/src/moduleb folder. If so, read the file pointed to by the main field in the folder

3. Check whether index.js exists in the /root/src/moduleB folder

Non-relative Module: var x = require(“moduleB”)

Recursively look up from node_modules in the current folder

  1. /root/src/node_modules/moduleB.js

  2. /root/src/node_modules/moduleB/package.json (if it specifies a "main" property)

  3. /root/src/node_modules/moduleB/index.js

  4. /root/node_modules/moduleB.js

  5. /root/node_modules/moduleB/package.json (if it specifies a "main" property)

  6. /root/node_modules/moduleB/index.js

  7. /node_modules/moduleB.js

  8. /node_modules/moduleB/package.json (if it specifies a "main" property)

  9. /node_modules/moduleB/index.js

Now see how TS loads modules.

Realtive Module: File search order ts -> TSX ->.d.ts -> Packages. Json -> index.ts -> index.tsx -> index.d.ts. Package. json looks for the values of the types field.

  1. /root/src/moduleB.ts
  2. /root/src/moduleB.tsx
  3. /root/src/moduleB.d.ts
  4. /root/src/moduleB/package.json (if it specifies a "types" property)
  5. /root/src/moduleB/index.ts
  6. /root/src/moduleB/index.tsx
  7. /root/src/moduleB/index.d.ts

Non – relative module:

Like node, it is a recursive lookup. But look for more TSX files with the @types folder.

Ts -> TSX -> d.ts -> packages. Json (types) -> @types/.d.ts -> index.tsx -> index.d.ts.

  1. /root/src/node_modules/moduleB.ts

  2. /root/src/node_modules/moduleB.tsx

  3. /root/src/node_modules/moduleB.d.ts

  4. /root/src/node_modules/moduleB/package.json (if it specifies a "types" property)

  5. /root/src/node_modules/@types/moduleB.d.ts

  6. /root/src/node_modules/moduleB/index.ts

  7. /root/src/node_modules/moduleB/index.tsx

  8. /root/src/node_modules/moduleB/index.d.ts

  9. /root/node_modules/moduleB.ts

  10. /root/node_modules/moduleB.tsx

  11. /root/node_modules/moduleB.d.ts

  12. /root/node_modules/moduleB/package.json (if it specifies a "types" property)

  13. /root/node_modules/@types/moduleB.d.ts

  14. /root/node_modules/moduleB/index.ts

  15. /root/node_modules/moduleB/index.tsx

  16. /root/node_modules/moduleB/index.d.ts

  17. /node_modules/moduleB.ts

  18. /node_modules/moduleB.tsx

  19. /node_modules/moduleB.d.ts

  20. /node_modules/moduleB/package.json (if it specifies a "types" property)

  21. /node_modules/@types/moduleB.d.ts

  22. /node_modules/moduleB/index.ts

  23. /node_modules/moduleB/index.tsx

  24. /node_modules/moduleB/index.d.ts

Additional Module resolution flags

Base URL

Tells the compiler where to find modules. All non-relative modules are read according to baseUrl. Relative Module will not be affected.

-> Command line arguments: If the value is a relative path, then the current folder

-> tsconfig config: If the value is relative, it is the relative path of the tsconfig config file

Path mapping

You can map the module name to a specified file/folder.

Note that the value of paths is relative to baseUrl. So if path is specified, baseUrl should also be specified.

{
    "compilerOptions":{
        "baseUrl": ".",
        "paths": {
            "jquery": ["node_modules/jquery/dist/jquery"]
        }
    }
}
Copy the code

The Paths value can also be an array, which can be used as a degradation solution for lookup.

ProjectRoot ├── folder1 │ ├── file.ts (imports 'folder1/file2' and 'folder2/file3') │ ├─ file.ts ├─ generated │ ├─ Folder1 │ └ ─ ─ folder2 │ └ ─ ─ file3. Ts └ ─ ─ tsconfig. Json {" compilerOptions ": {" baseUrl" : ""," paths ": {" *" : ["*", "generated/*"] } }}Copy the code

Virtual directory rootDirs

Sometimes files are read from multiple directories and eventually compiled into a single file. You can then use rootDirs to “consolidate” them into the same virtual root directory.

SRC ├ ── views ├ ─ view1.ts (imports './template1') ├ ─ view2.ts generated ├ ─ templates ├ ─ views ├ ─ template1.ts (imports './view2') { "compilerOptions": { "rootDirs": ["src/views", "generated/templates/views"] }}Copy the code

In addition, rootDirs has more powerful features.

For example, when internationalizing, you need to package into different languages. Reference paths containing special characters./#{locale}/messages can be configured as follows at development time

{  "compilerOptions": {    "rootDirs": ["src/zh", "src/de", "src/#{locale}"]  }}
Copy the code

When importing, “SRC /#{locale}” -> is resolved to” SRC /zh “.

Tracing module resolution

The following command can output the sequence of TS parsing modules

tsc --traceResolution
Copy the code

Using the — noResolve

Normally, the compiler parses all imported modules before compiling. Each time an import is successfully parsed, the parsed file is added to the collection. It will be processed later. The — noResolve compilation option tells the compiler not to “add” any module files that are not specified on the command line.

app.ts

import * as A from "moduleA"; // OK, 'moduleA' passed on the command-lineimport * as B from "moduleB"; // Error TS2307: Cannot find module 'moduleB'.

tsc app.ts moduleA.ts --noResolve
Copy the code