Avinash Kumar
Avinash Kumar

Reputation: 29

Migrating from angular 5 to angular 19 in NgModule based app

I am migrating old angular project from version 5 to version 19. I have indentified all compatible and dependent libraries and able to migrate code. However I keep getting standanlone error.

Note : I have already tried standalone:false in the component section. It is not helping, because I'm getting same error.

The project is based on NgModule and I want to have as is, and I don't need the standalone feature as now.

    ng build 
    √ Browser application bundle generation complete.

    Error: src/app/app.module.ts:7:5 - error NG6008: Component AppComponent is standalone, and cannot be declared in an NgModule. Did you mean to import it instead?

    7     AppComponent // Declare AppComponent here

To drill down the issue, I created a minimal project from actual and reproduded the issue. I added standalone:false in the angular.json, cleared cache, removed node-modules, verified all ts files for no standalone:true. However this has become a nightmare for me as from last two day I am not able to fix it.

angular.json

  {
    "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
    "version": 1,
    "newProjectRoot": "projects",
    "projects": {
      "resource-planning": {
        "projectType": "application",
        "root": "src",
        "sourceRoot": "src",
        "prefix": "app",
        "schematics": {
            "@schematics/angular:component": {
            "standalone": false
          }
        },
        "architect": {
          "build": {
            "builder": "@angular-devkit/build-angular:browser",
            "options": {
              "outputPath": "dist/resource-planning",
              "index": "src/index.html",
              "main": "src/main.ts",
              //"polyfills": "src/polyfills.ts",
              "tsConfig": "tsconfig.app.json",
              "aot": true,
              "assets": [
                "src/assets",
                "src/favicon.ico"
              ],
              "styles": [
                "src/styles.css",
                "node_modules/font-awesome/css/font-awesome.min.css",
                "node_modules/primeng/resources/themes/omega/theme.css",
                "node_modules/primeng/resources/primeng.min.css"
              ],
              "scripts": []
            }
          },
          "serve": {
            "builder": "@angular-devkit/build-angular:dev-server",
            "options": {
              "buildTarget": "resource-planning:build"
            },
            "configurations": {
              "production": {
                "buildTarget": "resource-planning:build:production"
              }
            }
          },
          "test": {
            "builder": "@angular-devkit/build-angular:karma",
            "options": {
              "main": "src/test.ts",
              //"polyfills": "src/polyfills.ts",
              "tsConfig": "tsconfig.spec.json",
              "karmaConfig": "./karma.conf.js",
              "styles": [
                "src/styles.css",
                "node_modules/font-awesome/css/font-awesome.min.css",
                "node_modules/primeng/resources/themes/omega/theme.css",
                "node_modules/primeng/resources/primeng.min.css"
              ],
              "scripts": [],
              "assets": [
                "src/assets",
                "src/favicon.ico"
              ]
            }
          },
          "lint": {
            "builder": "@angular-eslint/builder:lint",
            "options": {
              "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
            }
          }
        }
      }
    }
  }

package.json

  {
    "name": "resource-planning",
    "version": "0.0.0",
    "license": "MIT",
    "scripts": {
      "ng": "ng",
      "start": "ng serve",
      "build": "ng build --prod",
      "test": "ng test",
      "lint": "ng lint",
      "e2e": "ng e2e"
    },
    "private": true,
    "dependencies": {
      "@angular/animations": "^19.0.5",
      "@angular/common": "^19.0.5",
      "@angular/compiler": "^19.0.5",
      "@angular/core": "^19.0.5",
      "@angular/forms": "^19.0.5",
      "@angular/platform-browser": "^19.0.5",
      "@angular/platform-browser-dynamic": "^19.0.5",
      "@angular/router": "^19.0.5",
      "@fortawesome/fontawesome-free": "^6.5.0",
      "core-js": "^3.32.2",
      "ngx-bootstrap": "^19.0.1",
      "primeicons": "^7.0.0",
      "primeng": "^19.0.1",
      "rxjs": "^7.8.0",
      "xlsx": "^0.18.5",
      "zone.js": "~0.15.0"
    },
    "devDependencies": {
      "@angular-devkit/build-angular": "^19.0.6",
      "@angular/cli": "^19.0.5",
      "@angular/compiler-cli": "^19.0.5",
      "@angular/language-service": "^19.0.5",
      "@eslint/config-array": "^0.19.1",
      "@eslint/object-schema": "^2.0.3",
      "@types/jasmine": "^4.5.0",
      "@types/jasminewd2": "^2.0.10",
      "@types/node": "^20.4.0",
      "angular-eslint": "19.0.2",
      "cypress": "^13.0.0",
      "eslint": "^9.16.0",
      "glob": "^9.0.0",
      "rimraf": "^4.0.0",
      "ts-node": "~10.9.1",
      "typescript": "~5.6.0",
      "typescript-eslint": "8.18.0"
    }
  }

app.module.ts

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { AppComponent } from './app.component';

    @NgModule({
    declarations: [
      AppComponent // Declare AppComponent here
    ],
    imports: [
      BrowserModule
    ],
    providers: [],
    bootstrap: [AppComponent]
    })
    export class AppModule { }

app.component.ts

  import { Component } from '@angular/core';

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    title = 'My Angular App';
  }

app-routing.module.ts

    import { Routes,RouterModule } from '@angular/router';
    import { NgModule } from '@angular/core';

    @NgModule({
        imports: [
            
        ],
        exports: [RouterModule]
    })
    export class AppRoutingModule {}

main.ts

  import { enableProdMode } from '@angular/core';
  import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

  import { AppModule } from './app/app.module';
  import { environment } from './environments/environment';

  if (environment.production) {
    enableProdMode();
  }

  /*platformBrowserDynamic().bootstrapModule(AppModule)
    .catch(err => console.log(err));
  */

  console.log('App bootstrapping...');
  platformBrowserDynamic().bootstrapModule(AppModule)
    .catch(err => console.error('Error bootstrapping module:', err));

Upvotes: 2

Views: 2566

Answers (2)

Naren Murali
Naren Murali

Reputation: 57986

Not ready for standalone and just want my code to compile with non standalone components approach:

If you are not ready to go with standalone component, all you need to do is to add standalone: false to all your components. This can be easily achieved using vsCode find and replace feature, since we just add an extra property:

enter image description here


Problem:

In Angular 19, all components are by default standalone: true. If a component is standalone, it has to have its own imports and can work individually without relying on other parts of the application. We can add them to the imports array to use them.


Code fix to solve the problem, two ways:


If you want to use standalone component, then you should have a look at the below link:

Migrate an existing Angular project to standalone

ng g @angular/core:standalone

Migration code that helps you move to standalone components.


There are two possible fixes here.

Migrate to Angular standalone Approach (Recommended):

In this approach, you leave the component as standalone and the changes are made on main.ts, where we use bootstrapApplication to bootstrap the component (defaults to standalone), apart from this, we also use the ApplicationConfig object to add providers:

  • provideHttpClient -> required for http client to be available in dependency injection.

  • provideAnimations -> required for angular animations to work.

    import { bootstrapApplication } from '@angular/platform-browser';
    import { enableProdMode } from '@angular/core';
    import { AppComponent } from './app/app.component';
    import { environment } from './environments/environment';
    import { provideHttpClient } from '@angular/common/http';
    import { provideAnimations } from '@angular/platform-browser/animations';
    
    if (environment.production) {
      enableProdMode();
    }
    
    bootstrapApplication(AppComponent, {
      providers: [
        provideHttpClient(), // <- required for http client to work
        provideAnimations(), // <- required for animations to work
      ]
    })
      .catch(err => console.error('Error bootstrapping module:', err));
    

Continue using modular approach:

This approach requires less coding effort, we can simply set the AppComponent to standalone: false, by doing this we can bootstrap it using the appModule and it will work, but other parts of your code should try to use the standalone approach wherever needed. By manually setting the standalone to false, angular considers it as a non standalone component and bootstrapping using module works.

  import { Component } from '@angular/core';

  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    standalone: false,
  })
  export class AppComponent {
    title = 'My Angular App';
  }

Upvotes: 4

Sithila Somaratne
Sithila Somaratne

Reputation: 93

You can try the steps mentioned in this Medium article:

  • In angular.json, under schematics, add the below lines:

    "schematics": {
        "@schematics/angular: component": {
            "standalone": false
        },
        "@schematics/angular:directive": {
            "standalone": false
    ·   },
        "@schematics/angular: pipe" : {
            "standalone": false
        },
     }
    
  • Remove app.config.ts, app.config.server.ts and app.routes.ts.

  • Add app.routing.module.ts and copy all the Routes from app.routes.ts to the Routes in app.routing.module.ts.

  • In main.ts, replace:

    bootstrapApplication(AppComponent, appConfig).catch((err) =>console.error(err));
    

    to:

    platformBrowserDynamic().bootstrapModule(AppModule).catch(err =>console.error(err));
    

    And in here add the required import.

  • Delete everything from main.server.ts and paste the below line:

    export { AppServerModule as default } from ‘./app/app.module.server’;
    
  • In app.module.ts, under @NgModule, inside providers array, add the below line and import the required packages:

    provideClientHydration()
    

    Inside bootstrap array, add the below line and import the required packages:

    AppComponent
    

    Inside imports array, remove CommonModule and RouterOutlet then add below this line and import the required packages:

    BrowserModule,AppRoutingModule
    
  • Create a new file called app.module.server.ts with below lines:

     import { NgModule } from '@angular/core';
     import { ServerModule } from '@angular/platform-server';
    
     import { AppModule } from './app.module';
     import { AppComponent } from '../app.component';
    
     @NgModule({
       imports: [
         AppModule,
         ServerModule,
       ],
       bootstrap: [AppComponent],
     })
     export class AppServerModule {}
    
  • And finally in the respective component files, change standalone to false and remove import array.

Once you're done, you can build your project and then run it.

I hope this answer will help you!

Please note that these steps are tailored for Angular 17, but they should be largely applicable to Angular 19. So, you may need to adjust as needed for any version-specific differences.

Upvotes: 2

Related Questions