“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:
-
/root/src/folder/moduleB.ts
-
/root/src/folder/moduleB.d.ts
For non-relative Module:
Import {b} from ‘moduleB’ in /root/src/folder/ a.ts:
-
/root/src/folder/moduleB.ts
-
/root/src/folder/moduleB.d.ts
-
/root/src/moduleB.ts
-
/root/src/moduleB.d.ts
-
/root/moduleB.ts
-
/root/moduleB.d.ts
-
/moduleB.ts
-
/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
-
/root/src/node_modules/moduleB.js
-
/root/src/node_modules/moduleB/package.json
(if it specifies a"main"
property) -
/root/src/node_modules/moduleB/index.js
-
/root/node_modules/moduleB.js
-
/root/node_modules/moduleB/package.json
(if it specifies a"main"
property) -
/root/node_modules/moduleB/index.js
-
/node_modules/moduleB.js
-
/node_modules/moduleB/package.json
(if it specifies a"main"
property) -
/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.
/root/src/moduleB.ts
/root/src/moduleB.tsx
/root/src/moduleB.d.ts
/root/src/moduleB/package.json
(if it specifies a"types"
property)/root/src/moduleB/index.ts
/root/src/moduleB/index.tsx
/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.
-
/root/src/node_modules/moduleB.ts
-
/root/src/node_modules/moduleB.tsx
-
/root/src/node_modules/moduleB.d.ts
-
/root/src/node_modules/moduleB/package.json
(if it specifies a"types"
property) -
/root/src/node_modules/@types/moduleB.d.ts
-
/root/src/node_modules/moduleB/index.ts
-
/root/src/node_modules/moduleB/index.tsx
-
/root/src/node_modules/moduleB/index.d.ts
-
/root/node_modules/moduleB.ts
-
/root/node_modules/moduleB.tsx
-
/root/node_modules/moduleB.d.ts
-
/root/node_modules/moduleB/package.json
(if it specifies a"types"
property) -
/root/node_modules/@types/moduleB.d.ts
-
/root/node_modules/moduleB/index.ts
-
/root/node_modules/moduleB/index.tsx
-
/root/node_modules/moduleB/index.d.ts
-
/node_modules/moduleB.ts
-
/node_modules/moduleB.tsx
-
/node_modules/moduleB.d.ts
-
/node_modules/moduleB/package.json
(if it specifies a"types"
property) -
/node_modules/@types/moduleB.d.ts
-
/node_modules/moduleB/index.ts
-
/node_modules/moduleB/index.tsx
-
/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