Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Live-Reload UE's when saving changes to HTML or CSS files when using local path library #42810

Closed
longjaso opened this issue Jul 9, 2021 · 7 comments
Labels
area: compiler Issues related to `ngc`, Angular's template compiler P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: has PR
Milestone

Comments

@longjaso
Copy link

longjaso commented Jul 9, 2021

Which @angular/* package(s) are the source of the bug?

compiler-cli

Is this a regression?

Yes

Description

Prerequisite: You must have a local-path library in your package.json and be using at least one component from it in your application (whether or not the containing-component is used or not makes no difference). For example:
package.json
"dependencies" : { ... , "my-lib" : "file:..\\my-lib\\dist\\my-lib", ... }
app.component.html
<lib-my-lib></lib-my-lib>

With the setup described above, if you save changes to your application's HTML or CSS files, the server crashes throwing the error below - causing you to have to restart your server every time you make an HTML/CSS change. If you remove all component references that originate from the locally-pathed library then you no longer have this problem.

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

Error: Module build failed (from ./node_modules/@ngtools/webpack/src/ivy/index.js):
Error: Symbol MyLibComponent declared in E:/playground/my-lib/dist/my-lib/lib/my-lib.component.d.ts is not exported from my-lib (import into E:/playground/temp-project/src/app/component/test/test.component.ts)
    at AbsoluteModuleStrategy.emit (E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\imports\src\emitter.js:171:23)
    at ReferenceEmitter.emit (E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\imports\src\emitter.js:72:44)
    at E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\annotations\src\component.js:539:49
    at Array.map (<anonymous>)
    at ComponentDecoratorHandler.resolve (E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\annotations\src\component.js:538:64)
    at TraitCompiler.resolve (E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\transform\src\compilation.js:445:50)
    at E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\core\src\compiler.js:626:31
    at ActivePerfRecorder.inPhase (E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\perf\src\recorder.js:64:24)
    at NgCompiler.resolveCompilation (E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\core\src\compiler.js:625:31)
    at NgCompiler.<anonymous> (E:\playground\temp-project\node_modules\@angular\compiler-cli\src\ngtsc\core\src\compiler.js:492:54)

Please provide the environment you discovered this bug in

Angular CLI: 12.1.1
Node: 14.17.3
Package Manager: npm 6.14.13
OS: win32 x64

Angular: 12.1.1
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1201.1
@angular-devkit/build-angular   12.1.1
@angular-devkit/core            12.1.1
@angular-devkit/schematics      12.1.1
@schematics/angular             12.1.1
rxjs                            6.6.7
typescript                      4.3.5

Anything else?

This was working in 11.1.1 and I updated to 11.2.14. This is when it broke. I tried updating to 12.1.1 to see if there was a patch for it but this didn't work.

@AndrewKushnir AndrewKushnir added the area: compiler Issues related to `ngc`, Angular's template compiler label Jul 9, 2021
@ngbot ngbot bot added this to the needsTriage milestone Jul 9, 2021
@JoostK
Copy link
Member

JoostK commented Jul 9, 2021

I don't recall something having changed in this area since 11.1.1. At least, please check that MyLibComponent is indeed exported from the entry-point of my-lib, as it doesn't appear to be. The compiler should not be crashing in this scenario but it'll likely continue to report an error if MyLibComponent has not been exported from the entry-point file. But I'm honestly surprised you even get that far; building the library should report an error that MyLibComponent has not been exported.

Could you please share a Github repo with the exact reproduction, so we get the full picture of your setup? Thanks.

@JoostK JoostK added the needs reproduction This issue needs a reproduction in order for the team to investigate further label Jul 9, 2021
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Jul 9, 2021
@longjaso
Copy link
Author

@JoostK No problem! Here it is: https://github.com/longjaso/angular-lib-bug
After building the library and running the application you will see that compilation succeeded. If you then go to app.component.html and save a change to it (e.g., change class="test" to class="tes") the server will crash with the error reported. I double-checked and the component is exported both from the module and the public api file.

@JoostK
Copy link
Member

JoostK commented Jul 12, 2021

Thanks for the repo. It's interesting that it doesn't reproduce for me, but I'm on macOS and used Yarn. Switching to npm now and can try on Windows too...

@JoostK
Copy link
Member

JoostK commented Jul 12, 2021

AH, it does reproduce when installing with NPM, even on macOS.

@JoostK JoostK added state: in investigation A team member is investigating this issue and removed needs reproduction This issue needs a reproduction in order for the team to investigate further labels Jul 12, 2021
@ngbot ngbot bot modified the milestones: Backlog, needsTriage Jul 12, 2021
@JoostK
Copy link
Member

JoostK commented Jul 12, 2021

Ok, here's what is going on:

NPM installs my-lib using a symlink into the app's node_modules, which is unlike Yarn which does not create a symlink. Symlinks cause file paths to be resolved to their real path on disk, which subsequently affects module resolution as module requests then occur from the directory that is pointed to by the symlink (which is outside of the workspace root).

The initial build succeeds because the compiler resolves the my-dir module from the app.module.ts file in the project and then caches the result. There is also a request for my-lib from within my-lib (upon first thought I think this is a bug) which is not resolved during the initial compilation, as it leverages the cached result from app.module.ts. During the rebuild however the app.module.ts is not affected, such that the request for my-lib from within my-lib no longer leverages the existing cache but resolve the my-lib module by itself. The key difference is that it starts searching for my-lib inside the my-lib/dist directory (which was symlinked) but now there is no node_modules directory in the ancestor directories that have my-lib and so this request fails to resolve.

You can workaround this issue by setting "preserveSymlinks": true as a builder option in angular.json.

@JoostK JoostK added P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent and removed state: in investigation A team member is investigating this issue labels Jul 12, 2021
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Jul 12, 2021
@longjaso
Copy link
Author

Thank you @JoostK ! That resolves my issue!

JoostK added a commit to JoostK/angular that referenced this issue Jul 16, 2021
… imports in .d.ts files

The compiler keeps track of how a declaration has been referenced
using absolute module imports and from which path the absolute module
should be resolved from. There was a bug in how the .d.ts metadata
extraction would incorrectly use the .d.ts file itself as resolution
context for symbols that had been imported using a relative module
specifier. This could result in module resolution failures.

For example, when extracting NgModule metadata from
`/node_modules/lib/index.d.ts` that looks like

```
import {LibDirective} from './dir';

@NgModule({
  declarations: [LibDirective],
  exports: [LibDirective],
})
export class LibModule {}
```

and `/app.module.ts` that contains

```
import {LibModule} from 'lib';

@NgModule({
  imports: [LibModule],
})
export class AppModule {}
```

then `AppModule` would have recorded a reference to `LibModule` using
the `'lib'` module specifier. When extracting the NgModule metadata from
the `/node_modules/lib/index.d.ts` file the relative import into `./dir`
would create a reference using `'lib'` as absolute module specifier but
`/node_modules/lib/index.d.ts` as resolution context path. The latter is
incorrect, as `'lib'` needs to be resolved from `/app.module.ts` and not
from within the library itself.

Fixes angular#42810
JoostK added a commit to JoostK/angular that referenced this issue Jul 17, 2021
… imports in .d.ts files

The compiler keeps track of how a declaration has been referenced
using absolute module imports and from which path the absolute module
should be resolved from. There was a bug in how the .d.ts metadata
extraction would incorrectly use the .d.ts file itself as resolution
context for symbols that had been imported using a relative module
specifier. This could result in module resolution failures.

For example, when extracting NgModule metadata from
`/node_modules/lib/index.d.ts` that looks like

```
import {LibDirective} from './dir';

@NgModule({
  declarations: [LibDirective],
  exports: [LibDirective],
})
export class LibModule {}
```

and `/app.module.ts` that contains

```
import {LibModule} from 'lib';

@NgModule({
  imports: [LibModule],
})
export class AppModule {}
```

then `AppModule` would have recorded a reference to `LibModule` using
the `'lib'` module specifier. When extracting the NgModule metadata from
the `/node_modules/lib/index.d.ts` file the relative import into `./dir`
would create a reference using `'lib'` as absolute module specifier but
`/node_modules/lib/index.d.ts` as resolution context path. The latter is
incorrect, as `'lib'` needs to be resolved from `/app.module.ts` and not
from within the library itself.

Fixes angular#42810
JoostK added a commit to JoostK/angular that referenced this issue Jul 19, 2021
… imports in .d.ts files

The compiler keeps track of how a declaration has been referenced
using absolute module imports and from which path the absolute module
should be resolved from. There was a bug in how the .d.ts metadata
extraction would incorrectly use the .d.ts file itself as resolution
context for symbols that had been imported using a relative module
specifier. This could result in module resolution failures.

For example, when extracting NgModule metadata from
`/node_modules/lib/index.d.ts` that looks like

```
import {LibDirective} from './dir';

@NgModule({
  declarations: [LibDirective],
  exports: [LibDirective],
})
export class LibModule {}
```

and `/app.module.ts` that contains

```
import {LibModule} from 'lib';

@NgModule({
  imports: [LibModule],
})
export class AppModule {}
```

then `AppModule` would have recorded a reference to `LibModule` using
the `'lib'` module specifier. When extracting the NgModule metadata from
the `/node_modules/lib/index.d.ts` file the relative import into `./dir`
should also be assumed to be importable from `'lib'` (according to APF
where symbols need to be exported from a single entry-point)
so the reference to `LibDirective` should have `'lib'` as absolute
module specifier, but it would incorrectly have
`/node_modules/lib/index.d.ts` as resolution context path. The latter is
incorrect as `'lib'` needs to be resolved from `/app.module.ts` and not
from within the library itself.

Fixes angular#42810
JoostK added a commit to JoostK/angular that referenced this issue Jul 22, 2021
… imports in .d.ts files

The compiler keeps track of how a declaration has been referenced
using absolute module imports and from which path the absolute module
should be resolved from. There was a bug in how the .d.ts metadata
extraction would incorrectly use the .d.ts file itself as resolution
context for symbols that had been imported using a relative module
specifier. This could result in module resolution failures.

For example, when extracting NgModule metadata from
`/node_modules/lib/index.d.ts` that looks like

```
import {LibDirective} from './dir';

@NgModule({
  declarations: [LibDirective],
  exports: [LibDirective],
})
export class LibModule {}
```

and `/app.module.ts` that contains

```
import {LibModule} from 'lib';

@NgModule({
  imports: [LibModule],
})
export class AppModule {}
```

then `AppModule` would have recorded a reference to `LibModule` using
the `'lib'` module specifier. When extracting the NgModule metadata from
the `/node_modules/lib/index.d.ts` file the relative import into `./dir`
should also be assumed to be importable from `'lib'` (according to APF
where symbols need to be exported from a single entry-point)
so the reference to `LibDirective` should have `'lib'` as absolute
module specifier, but it would incorrectly have
`/node_modules/lib/index.d.ts` as resolution context path. The latter is
incorrect as `'lib'` needs to be resolved from `/app.module.ts` and not
from within the library itself.

Fixes angular#42810
dylhunn pushed a commit that referenced this issue Jul 26, 2021
… imports in .d.ts files (#42879)

The compiler keeps track of how a declaration has been referenced
using absolute module imports and from which path the absolute module
should be resolved from. There was a bug in how the .d.ts metadata
extraction would incorrectly use the .d.ts file itself as resolution
context for symbols that had been imported using a relative module
specifier. This could result in module resolution failures.

For example, when extracting NgModule metadata from
`/node_modules/lib/index.d.ts` that looks like

```
import {LibDirective} from './dir';

@NgModule({
  declarations: [LibDirective],
  exports: [LibDirective],
})
export class LibModule {}
```

and `/app.module.ts` that contains

```
import {LibModule} from 'lib';

@NgModule({
  imports: [LibModule],
})
export class AppModule {}
```

then `AppModule` would have recorded a reference to `LibModule` using
the `'lib'` module specifier. When extracting the NgModule metadata from
the `/node_modules/lib/index.d.ts` file the relative import into `./dir`
should also be assumed to be importable from `'lib'` (according to APF
where symbols need to be exported from a single entry-point)
so the reference to `LibDirective` should have `'lib'` as absolute
module specifier, but it would incorrectly have
`/node_modules/lib/index.d.ts` as resolution context path. The latter is
incorrect as `'lib'` needs to be resolved from `/app.module.ts` and not
from within the library itself.

Fixes #42810

PR Close #42879
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Aug 26, 2021
TeriGlover pushed a commit to TeriGlover/angular that referenced this issue Sep 15, 2021
… imports in .d.ts files (angular#42879)

The compiler keeps track of how a declaration has been referenced
using absolute module imports and from which path the absolute module
should be resolved from. There was a bug in how the .d.ts metadata
extraction would incorrectly use the .d.ts file itself as resolution
context for symbols that had been imported using a relative module
specifier. This could result in module resolution failures.

For example, when extracting NgModule metadata from
`/node_modules/lib/index.d.ts` that looks like

```
import {LibDirective} from './dir';

@NgModule({
  declarations: [LibDirective],
  exports: [LibDirective],
})
export class LibModule {}
```

and `/app.module.ts` that contains

```
import {LibModule} from 'lib';

@NgModule({
  imports: [LibModule],
})
export class AppModule {}
```

then `AppModule` would have recorded a reference to `LibModule` using
the `'lib'` module specifier. When extracting the NgModule metadata from
the `/node_modules/lib/index.d.ts` file the relative import into `./dir`
should also be assumed to be importable from `'lib'` (according to APF
where symbols need to be exported from a single entry-point)
so the reference to `LibDirective` should have `'lib'` as absolute
module specifier, but it would incorrectly have
`/node_modules/lib/index.d.ts` as resolution context path. The latter is
incorrect as `'lib'` needs to be resolved from `/app.module.ts` and not
from within the library itself.

Fixes angular#42810

PR Close angular#42879
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: compiler Issues related to `ngc`, Angular's template compiler P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: has PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants