Skip to content

Commit

Permalink
fix(language-service): Add resource files as roots to their associate…
Browse files Browse the repository at this point in the history
…d projects

When an external template is read, adds the template file to to the project which contains.
This is necessary to keep the projects open when navigating away from HTML files.
Since a `tsconfig` cannot express including non-TS files,
we need another way to indicate the template files are considered part of the project.

Note that this does not ensure that the project in question _directly_ contains the component
file. That is, the project might just include the component file through the program rather
than directly in the `include` glob of the `tsconfig`. This distinction is somewhat important
because the TypeScript language service/server prefers projects which _directly_ contain the TS
file (see `projectContainsInfoDirectly` in the TS codebase). What this means it that there can
possibly be a different project used between the TS and HTML files.

For example, in Nx projects, the referenced configs are `tsconfig.app.json` and
`tsconfig.editor.json`. `tsconfig.app.json` comes first in the base `tsconfig.json` and
contains the entry point of the app. `tsconfig.editor.json` contains the `**.ts` glob of all TS
files. This means that `tsconfig.editor.json` will be preferred by the TS server for TS files
but the `tsconfig.app.json` will be used for HTML files since it comes first and we cannot
effectively express `projectContainsInfoDirectly` for HTML files.

We could consider also updating the language server implementation to attempt
to select the project to use for the template file based on which project
contains its component file directly, using either the internal `project.projectContainsInfoDirectly`
or as a workaround, check `project.isRoot(componentTsFile)`.

Finally, keeping the projects open is hugely important in the solution style config case like
Nx. When a TS file is opened, TypeScript will only retain `tsconfig.editor.json` and not
`tsconfig.app.json`. However, if our extension does not also know to select
`tsconfig.editor.json`, it will automatically select `tsconfig.app.json` since it is defined
first in the `tsconfig.json` file. So we need to teach TS server that we are (1) interested in
keeping projects open when there is an HTML file open and (2) optionally attempt to do this
_only_ for projects that we know the TS language service will prioritize in TS files (i.e.,
attempt to only keep `tsconfig.editor.json` open and allow `tsconfig.app.json` to close)
and prioritize that project for all requests.

fixes angular/vscode-ng-language-service#1623
fixes angular/vscode-ng-language-service#876
  • Loading branch information
atscott committed Apr 12, 2022
1 parent f1630bb commit 25da39a
Showing 1 changed file with 13 additions and 0 deletions.
13 changes: 13 additions & 0 deletions packages/language-service/src/adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@ export class LanguageServiceAdapter implements NgCompilerAdapter {
}
const version = this.project.getScriptVersion(fileName);
this.lastReadResourceVersion.set(fileName, version);
const scriptInfo = this.project.getScriptInfo(fileName)
if (!scriptInfo) {
// This should not happen because it would have failed already at either `getScriptSnapshot`
// or `getScriptVersion`.
throw new Error(`Failed to get script info when trying to read ${fileName}`);
}
// Add external resources as root files to the project since we project language service
// features for them (this is currently only the case for HTML files, but we could investigate
// css file features in the future). This prevents the project from being closed when navigating
// away from a resource file.
if (!this.project.isRoot(scriptInfo)) {
this.project.addRoot(scriptInfo);
}
return snapshot.getText(0, snapshot.getLength());
}

Expand Down

0 comments on commit 25da39a

Please sign in to comment.