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
IVY writes metadata into our symlinked monorepo's non-angular library's package.json #33395
Comments
@petebacondarwin: I saw your input in this issue AlexKhymenko/ngx-permissions#112 and thought this might be something you can explain. |
Hi @JonWallsten - for the Angular compiler (ngtsc) to be able to build your applications in ivy mode, we need all its dependencies to be compiled in ivy mode too. We have a second compiler (ngcc) that will re-compiled dependent packages into the ivy mode. Ngcc will identify packages that have been built with view engine and recompile them (in-place effectively). This is what is happening in your project. This has to happen for all dependencies whether they are in node_modules or not. One way to avoid this, if the dependency is a local project and not going to be distributed on npm, is to actually compile these packages in ivy mode and then expose the build files to the downstream application rather than the view engine builds. At this stage, if the package is going to be distributed on npm then it should be built in view engine mode (i.e. non-ivy). |
@petebacondarwin First, thanks for responding! I'm not following completely, but I get the gist of it. What I don't understand though, is why my non-angular libs (they are not in the example repo) are being compiled at all at this stage. They are already compiled by Webpack/TypeScript in an earlier stage of the build process, as commonjs modules and then we import stuff in the app. They shouldn't have to be touched by angulars compiler, or am I wrong? If they do I guess it would be nice to detect if this is a installed package or a original local package, and don't write stuff in the package.json. Would that be possible? |
If those packages are Angular packages, they will need to be "updated" from View Engine code to Ivy code. Another way to think about ngcc is that it's running the Angular compiler on your libraries. |
@alxhub: One of them are, and I can aceept that it's adding stuff to the package.json in that one. But the other libs are not containing any angular code. They are only guilty of being used by our angular app. |
I think this is a fundamental design flaw in Ivy's compiler architecture, especially in a local development workflow for linked monorepos or linked libraries in general. We use Lerna for example
and whenever we build the project the Also before publish my packages now I have to manually remove those Beside the bad UX of that another topic is actual a major regression: We use external libraries like https://github.com/marcj/angular-desktop-ui which is a TS-only library. We symlink it locally while development to make the workflow easy. Like so:
where With Ivy it's not possible anymore to use that setup with more than one consumer where each uses different versions of Angular. Imagine a second application with Angular 9.0.1 that consumers
It asks now everytime to delete the node_modules folder, however after symlinking back The assumption that deleting So for me there are 2 issues:
For me it seems Ivy completely ignored the legit workflow of multi-packages symlinked together using either Lerna or other local multi-package workflow patterns. What's Angular's approach to fixing that? |
@marcj I'm not really sure how you are building your monorepo in the case you described. I get the impression you're using TS paths to make consuming apps use the library TS sources directly. I think that's the case because you mention the original package.json is modified. This is not a use case that we've ever supported in Angular CLI. Instead, we try to setup projects so that consumers use built versions of libraries. If you have libraries generated with Angular CLI, they are also updated to directly compile to Ivy in development workflows. The symlinked package case is also not very clear to me... symlinked packages have always been a problem because they are usually broken with peer dependencies. Some setups might addressed this of course, but the devil is in the details. The setup you're describing sounds like it's using a single built (or maybe non-built) library linked to several consumers. The same built library should be able to be consumed across different Angular versions, but the same cannot be said of the particular installed version on disk for a given project. I think you've made a pretty good description of this problem but before we can jump in and describe ways to address these issues, we'd really need to see a example reproduction. This is a very non-trivial case that hinges on how things are built, linked, and consumed. There are setups that might have worked, but not because we explicitly supported them. |
@filipesilva sure, no problemo. Here is a full prepared and working repo with Lerna, 3 packages, and step-by-step doc on how to reproduce it: https://github.com/marcj/angular-ivy-issue1. This setup here is a very basic and common one in Lerna: Frontend and server share some code which is stored in a A more complex scenario could be to have a package external of lerna (like described with angular-desktop-ui) and use a solution like npm-local-development to link it correctly so However, that overall topic with linking external packages or packages in a mono-repo using links is a solved one and works fine (at least if you use a solution like npm-local-development for more complex setups).
Which I think you should consider supporting explicitly. I worked on many TS projects especially enterprise and my experience is that in TS projects mono-repos and linked packages are pretty common. Breaking this now with Ivy pushes people away from Angular because the only alternative is not to develop on multiple packages that partially use each other locally anymore. I think https://nx.dev/ has the same issue here. If that's not supported and never will, you should at least provide a workflow that works for enterprise and bigger projects where you share code between multiple packages that does not require you to publish the shared code to a registry first all the time. But honestly, the simplest solution might just be to not modify the |
@marcj I have seen this issue as well in some private repos but also have it in our public Clarity mono repo. We distribute an Angular library as well as a handful of plain TS/CSS libraries as dependencies. I wrote a script as a temporary workaround that runs ngcc during post install removing the added properties. vmware-archive/clarity@d160f0c I am also interested in how NX is able to work around this issue since they follow a similar pattern I believe. |
@marcj I followed the instructions on your repo:
This fails because it needs the
I'm not really familiar with what this command does, but I see that both Publishing TS sources is generally not safe, since the output of compiling them differs by TS version and by build system setup. If you have a separate Angular library and an app, and you should build the library using whatever build setup you have, then consume the built library from your app. Angular CLI uses Continuing with your repro I run these commands:
And see the diff you mention in the README.md. This happens because By design I don't understand why |
I saw a workaround posted at #35447 which basically has you run ngcc ahead so that it won’t run at compile time. In case it helps:
|
It doesn't work with lerna. In lerna, if you do If you do on I tried to put {
"prepare": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points",
} It compiles properly all libs installed but not other angular packages of the monorepo... So same error, need to run angular app twice to work... Really weird, it should work but it never detect the symlinked packages... EDIT: Found the trick, when we So when you run ngcc, it will not compile your package because it is not in the package.json... Workaround: compile my package manually... {
"prepare": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points && ngcc --source ./node_modules/@myOrg/ds-angular --properties es2015 browser module main --create-ivy-entry-points",
} For sure we need to find a better way to handle this... |
Seems like it was not fixed? |
This is proving to be difficult to resolve. We still don't have a solution for symlinked packages. It is not even clear if we can find a resolution for v10. |
We have two related issues here:
|
About the Lerna workaround: Lerna only does this package.json hacky rewriting if it needs to manage workspaces by working around the package manager restrictions. I don’t recommend using Lerna like that, it only causes pain & bugs in edge cases like this one. If you use Lerna with Yarn by relying on Yarn internal workspaces support instead (there’s a Lerna setting for that) all this hacky behavior is gone as Lerna leaves managing workspaces to Yarn & it doesn’t rewrite package.json. |
@mgol ok if you use |
@Nightbr Yes, sure! I just don’t consider npm to be suitable package manager to use with Lerna because of missing support for workspaces. |
We have the same problem, and there's another wrinkle to it: We have a shared library that's used by two different applications, one using Angular v8 (View Engine) and one using Angular v10 (Ivy). Up until now we relied on symlinking the library into both applications - but now we can't because as soon as the Angular 10 application is run, it modifies the shared library and thus the Angular v8 app can't deal with it any more. It seems to me that modifying the contents of dependencies is a fundamental design flaw of the Ivy compile infrastructure, that makes it completely incompatible with symlinking, which a lot of developers depend on. In my mind it shouldn't be too hard to simply use a cache folder for the Ivy-compiled versions of View Engine packages, instead of rewriting those packages' contents. This would solve all the issues with Lerna and yarn workspaces as well. |
Ran into the same issue with https://github.com/dennisameling/muuri-angular and the workaround below got me up and running at least (basically an implementation of what @petebacondarwin mentioned in #33395 (comment)). These steps are also described at https://github.com/dennisameling/muuri-angular#contributing. Update library config
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.lib.json",
"angularCompilerOptions": {
"enableIvy": true
}
}
"configurations": {
"production": {
"tsConfig": "projects/PROJECT_NAME/tsconfig.lib.prod.json"
},
"ivy": {
"tsConfig": "projects/PROJECT_NAME/tsconfig.lib.ivy.json"
}
}
"scripts": {
...
"build:prod": "ng build PROJECT_NAME --prod",
"build:ivy": "ng build PROJECT_NAME --configuration=ivy"
}, For Angular 9+ (Ivy) projects consuming your library
For Angular 8 and lower (View Engine) projects consuming your library
|
Seems like there are plans to fix this issue in future versions |
I'm having the same issue with pnpm. Running "postinstall": "find node_modules/{@angular,ngx-mask,ng-dynamic-component} | xargs -I% pnpx ngcc -s %"
Note that |
This should be solved by the ng-linker that is being developed. Please follow the progress of that here: https://github.com/orgs/angular/projects/2 |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
🐞 bug report
Affected Package
The issue is caused by package @angular/compiler?Is this a regression?
Can't tellDescription
When enabling IVY, our symlinked monorepo packages that are imported by the app using IVY, get's metadata written in their package.json by the compiler. I guess the compiler think it's a normal package in node_modules that wouldn't mind this.
🔬 Minimal Reproduction
https://github.com/JonWallsten/monorepo-repro🌍 Your Environment
Angular Version:
Anything else relevant?
The text was updated successfully, but these errors were encountered: