Angular-cli: ng update - Doesn't honor 'preserveSymlinks' flag, causes re-build for migrations to fail

Created on 17 Feb 2020  路  6Comments  路  Source: angular/angular-cli

馃悶 Bug report

Command (mark with an x)


  • [x] update

Is this a regression?

unsure

Description

I have an angular cli project with npm symlinks to a different framework project. When running an update ng update @angular/cli @angular/core rxjs, it seems that the package update/installation phase doesn't honor the "preserveSymlinks": true setting. The result is that my framework symlink is removed, which causes the project to fail compilation so the migrations don't all run correctly.

馃敩 Minimal Reproduction

npm i -g @angular/[email protected]
mkdir ng-up
cd ng-up
ng new framework
cd framework
ng g lib @myfw/model
ng build @myfw/model
cd ./dist/myfw/model
npm link
cd ../../../..
ng new app
cd app
npm link @myfw/model
#edit ./app/src/app/app.module.ts to the below (importing ModelModule from @myfw/model
#edit ./app/angular.json, add `preserveSymlinks: true`
ng serve #The app runs as expected

app/src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ModelModule } from '@myfw/model' //<- Add this from @myfw/model

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ModelModule //<- Add this from @myfw/model
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

upgrade process

npm i -g @angular/cli #Update angular cli to 9.0.2
cd ../framework
ng update @angular/cli @angular/core rxjs --force #--force is needed for tsickle
ng build @myfw/model
cd ../app
ng update @angular/cli @angular/core rxjs

get error as seen below. ls ./node_modules/@myfw shows no directories, the symlinks have been deleted.

馃敟 Exception or Error


> Undecorated classes with DI migration.
  As of Angular 9, it is no longer supported to use Angular DI on a class that does not have an Angular decorator.
  Read more about this here: https://v9.angular.io/guide/migration-undecorated-classes

    This migration uses the Angular compiler internally and therefore projects that no longer build successfully after the update cannot run the migration. Please ensure there are no AOT compilation errors and rerun the migration. The following project failed: tsconfig.app.json

    Error: error TS100: src\app\app.module.ts(13,5): Error during template compile of 'AppModule'
      Could not resolve @myfw/model relative to [object Object]..
    error TS100: src\app\app.module.ts(13,5): Error during template compile of 'AppModule'
      Could not resolve @myfw/model relative to [object Object]..


    Could not migrate all undecorated classes that use dependency
    injection. Some project targets could not be analyzed due to
    TypeScript program failures.

    Migration can be rerun with: "ng update @angular/core --migrate-only migration-v9-undecorated-classes-with-di"

  Migration completed.

馃實 Your Environment

@angular/cli 8.3.25 to start (to generate the original projects)


Angular CLI: 9.0.2
Node: 12.11.1
OS: win32 x64

Angular: 9.0.1
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.900.2
@angular-devkit/build-angular     0.900.2
@angular-devkit/build-optimizer   0.900.2
@angular-devkit/build-webpack     0.900.2
@angular-devkit/core              9.0.2
@angular-devkit/schematics        9.0.2
@angular/cli                      9.0.2
@ngtools/webpack                  9.0.2
@schematics/angular               9.0.2
@schematics/update                0.900.2
rxjs                              6.5.4
typescript                        3.7.5
webpack                           4.41.2

Anything else relevant?

schematicupdate low ng update DX broken triage #1 bufix

Most helpful comment

@alan-agius4 I spent some time investigating this. I was able to reproduce the issue, but only with the package manager being npm. I wasn't able to reproduce this with yarn.

Based on what I found, I think the issue comes from the fact that ng update runs npm install (to bring in the more recent package). That command seems to discard the symlink in the node_modules folder.

My NPM version is 6.12.0. I was able to observe it without ng update too:

  1. npm link @myfw/model
  2. npm install
  3. ls -alh node_modules/@myfw -> empty.

I think we should transfer this issue back to the CLI repository.

All 6 comments

I believe a workaround for this would be to remove the npm links, and instead add dependencies to your package.json, "@myfw/model": "file:../framework/dist/myfw/model". That got me past this initial compilation issue but I ran into another. Once the upgrade is done, it should be safe to remove the dependencies and move back to npm links.

This issue seems to be caused by the @angular/core migrations were the are not providing the preserveSymlinks option to TypeScript.

//cc @devversion.

@alan-agius4 I spent some time investigating this. I was able to reproduce the issue, but only with the package manager being npm. I wasn't able to reproduce this with yarn.

Based on what I found, I think the issue comes from the fact that ng update runs npm install (to bring in the more recent package). That command seems to discard the symlink in the node_modules folder.

My NPM version is 6.12.0. I was able to observe it without ng update too:

  1. npm link @myfw/model
  2. npm install
  3. ls -alh node_modules/@myfw -> empty.

I think we should transfer this issue back to the CLI repository.

@devversion thanks for looking into this.

Thanks for digging into this.

For anyone else who may run into this issue, I think a better work-around from the one I posted above is to switch from npm link to using tsconfig.json paths. The following has been stable for me for the last couple weeks and the workflow is the same as the one with npm link, you just don't need to run npm link or add the preserveSymlink setting. I probably won't go back to using npm links in favor of:

{
  //...
  "paths": {
    "@myfw/model": [ "../../myfw/src/web/dist/myfw/model" ],
    "@myfw/model/*": [ "../../myfw/src/web/dist/myfw/model/*" ]
  }
}

I think the wildcard entry is only necessary if you use secondary entrypoints for your library.

One other note: the paths seem to work if they're in the tsconfig.json in the root of your workspace, but they do not work if you put them in say, a tsconfig.app.json or tsconfig.lib.json.

@jonstelly

Simplest workaround for this. Add @myfw/model in package.json under devDependencies. like this:
"devDependencies": { "@myfw/model": "" }

Once it's in devDependencies then ng update or npm install will not remove it.

Was this page helpful?
0 / 5 - 0 ratings