x)
Not sure
Newly created project cannot lint environment.prod.ts file. After setting "include": [
"src/**/*.ts"
] in tsconfig.app.json everything works fine.
Create a new project with the CLI and run this command ng lint --files src/environments/environment.prod.ts in your terminal.
src\\environments\\environment.prod.ts" is not part of a TypeScript project 'tsconfig.app.json,tsconfig.spec.json,e2e/tsconfig.json
Angular CLI: 9.0.7
Node: 12.3.1
OS: win32 x64
Angular: 9.0.7
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.900.7
@angular-devkit/build-angular 0.900.7
@angular-devkit/build-optimizer 0.900.7
@angular-devkit/build-webpack 0.900.7
@angular-devkit/core 9.0.7
@angular-devkit/schematics 9.0.7
@ngtools/webpack 9.0.7
@schematics/angular 9.0.7
@schematics/update 0.900.7
rxjs 6.5.5
typescript 3.7.5
webpack 4.41.2
Anything else relevant?
Discussed in the CLI meeting and this is a bit of a tricky one, as replacement files aren't really a part of any TypeScript compilation.
For users experiencing this problem today, I think the workaround would be to include any file replacements in angular.json in the files array in tsconfig.app.json. ng lint should then run the relevant checks for that compilation unit.
The best real solution we identified is to add a migration in a major version which takes all the file replacements in angular.json and adds them to tsconfig.app.json. This would fix linting and put things into a good state. From there we would need to maintain that state going forward for user changes to angular.json. Easiest solution would be to add a warning to ng lint or ng build which detects a discrepancy between angular.json and tsconfig.app.json and prints out an error along the lines of "Please add tsconfig.app.json files to support linting it." This would at least notify users at the right time and give them an easy opportunity to fix the problem.
It does require a user to add a change in two places instead of one. Ideally, we would have some kind of automatic fixer when this warning is triggered, but I don't think we have infra to support that at the moment. One concern here is that we're somewhat arbitrarily choosing to add to tsconfig.app.json rather than other tsconfig files. That's __probably__ right, but some users may need to move a replacement file to a different tsconfig to enable the right lint checks.
@mgechev, how does this change with ESLint going forward? Does ESLint require its files to be part of a TypeScript compilation? Is it worth adding a migration in the next major version just to undo it in a subsequent version when we switch to ESLint?
@dgp1130
I would like to note that this issue happens not only with the replacement files. If some .ts file is not imported anywhere in your project it can not be linted too. I have created a simple repository which demonstrates the issue: https://github.com/destus90/angular-lint-issue
Had some additional discussion on the CLI team this week as this issue gets quite tricky. Fundamentally, all dependent types are needed to lint a particular file (because many lint checks are type-aware). If a file is missing from the compilation, then those dependencies cannot be resolved intelligently and we can't effectively lint that file. This also means that ESLint won't help us here because it will suffer the same problem.
There are three specific challenges which are addressed in this particular issue:
ng new creates a project which includes files that cannot be linted.This is actually a TypeScript problem moreso than an Angular one. TSLint provides no means of linting files not in the project due to the aforementioned typing issues. If you create a non-Angular project with an unused file not include in tsconfig, it encounters the same problem. The only solution in that case is to include it directly in tsconfig via a glob pattern of some kind (src/**/*.ts), which we used to do and stopped in v9 because it was slowing down builds. The only options we see to fix this are:
src/**/*.ts.tsconfig could help us here, but fundamentally we would need to make some kind of guess about the usage-pattern of an unused file. We simply don't have any effective means of inferring whether a given unused file belongs in tsconfig.app.json, tsconfig.spec.json, or anything else.We previously suggested using a migration to include file replacements in tsconfig.app.json. This could cause additional problems to users if they do weird things in file replacements. For example, if environment.ts declares a global variable foo while environment.prod.ts declares a global bar. These files can lint individually, but if another file (baz.ts) depends on ./environment, it will only have foo available during linting (even though building prod would include bar). There is also the case of a file which uses worker APIs (or Jasmine test APIs) and should be included in the associated tsconfig, which won't be tsconfig.app.json.
Instead, the warning on its own may be the best for now. This warning can iterate over file replacements in angular.json and verify that they are in the files list of a tsconfig file. If not, it will inform users to add the replacement to the relevant tsconfig.*.json. We may also need some documentation to help the user identify which tsconfig a given file should be included in.
Longer term, we should evaluate an alternative to file replacements, as it is some weird Angular magic that confuses the compiler/linter. If we could support multi-build use cases without rewriting imports, we could make this play much better with the compiler/linter. I'm thinking something similar to what https://dagger.dev/ does by injecting an interface and deferring the decision of importing a module to the very top-level main function, then generating a dev/prod version of that. We could also generate a tsconfig specifically for linting, and use a default tsconfig for file replacements (similar to what the language service does). This is quite a complex problem, and I don't want to try and solve it here, but there are potentially ways of doing this that would work better with the compiler and linter.
ng new creates a project which includes files that cannot be lintedng new should create a well-formed project. Fortunately this is the easiest to address as we can update the schematic to include environment.prod.ts in tsconfig.app.json. That should make ng lint work out of the box, and the warning will help application developers keep it that way.
After I add the src/environment/environment.prod.ts to the files array in my tsconfig.app.json, then I get the following warning when I build my Angular project in prod mode:
WARNING in ...\src\environments\environment.prod.ts is part of the TypeScript compilation but it's unused.
Add only entry points to the 'files' or 'include' properties in your tsconfig.
Is there any workaround for hiding this warning but make the linting work at the same time?
Any news on this one? We face the same problem where we have files that are only included (imported) when run/build with a specific environment by exporting them in the respective environment file. So those TS files look "unused" to the compilation and we get the same warning on the build. However, we need those file to be compiled as well to check for any errors.
Most helpful comment
Had some additional discussion on the CLI team this week as this issue gets quite tricky. Fundamentally, all dependent types are needed to lint a particular file (because many lint checks are type-aware). If a file is missing from the compilation, then those dependencies cannot be resolved intelligently and we can't effectively lint that file. This also means that ESLint won't help us here because it will suffer the same problem.
There are three specific challenges which are addressed in this particular issue:
ng newcreates a project which includes files that cannot be linted.Unused files cannot be linted
This is actually a TypeScript problem moreso than an Angular one. TSLint provides no means of linting files not in the project due to the aforementioned typing issues. If you create a non-Angular project with an unused file not include in
tsconfig, it encounters the same problem. The only solution in that case is to include it directly intsconfigvia a glob pattern of some kind (src/**/*.ts), which we used to do and stopped in v9 because it was slowing down builds. The only options we see to fix this are:src/**/*.ts.tsconfigcould help us here, but fundamentally we would need to make some kind of guess about the usage-pattern of an unused file. We simply don't have any effective means of inferring whether a given unused file belongs intsconfig.app.json,tsconfig.spec.json, or anything else.File replacements cannot be linted
We previously suggested using a migration to include file replacements in
tsconfig.app.json. This could cause additional problems to users if they do weird things in file replacements. For example, ifenvironment.tsdeclares a global variablefoowhileenvironment.prod.tsdeclares a globalbar. These files can lint individually, but if another file (baz.ts) depends on./environment, it will only havefooavailable during linting (even though building prod would includebar). There is also the case of a file which uses worker APIs (or Jasmine test APIs) and should be included in the associatedtsconfig, which won't betsconfig.app.json.Instead, the warning on its own may be the best for now. This warning can iterate over file replacements in
angular.jsonand verify that they are in thefileslist of atsconfigfile. If not, it will inform users to add the replacement to the relevanttsconfig.*.json. We may also need some documentation to help the user identify whichtsconfiga given file should be included in.Longer term, we should evaluate an alternative to file replacements, as it is some weird Angular magic that confuses the compiler/linter. If we could support multi-build use cases without rewriting imports, we could make this play much better with the compiler/linter. I'm thinking something similar to what https://dagger.dev/ does by injecting an interface and deferring the decision of importing a module to the very top-level main function, then generating a dev/prod version of that. We could also generate a
tsconfigspecifically for linting, and use a defaulttsconfigfor file replacements (similar to what the language service does). This is quite a complex problem, and I don't want to try and solve it here, but there are potentially ways of doing this that would work better with the compiler and linter.ng newcreates a project which includes files that cannot be lintedng newshould create a well-formed project. Fortunately this is the easiest to address as we can update the schematic to includeenvironment.prod.tsintsconfig.app.json. That should makeng lintwork out of the box, and the warning will help application developers keep it that way.