NOTE! You are browsing legacy documentation. For latest visit docs.nativescript.org.

NativeScript Angular

Migrating existing Angular Web projects

You can add NativeScript to an existing Angular Web project with the help of Angular CLI and NativeScript Schematics.

Setup

Angular CLI

To take advantage of the automated migration commands for NativeScript Angular you will need to install the Angular CLI. Run the following command:

npm install --global @angular/cli

NativeScript CLI

To run mobile apps with NativeScript you will need to install the NativeScript CLI. Execute the following command:

npm install --global nativescript

Preview

The NativeScript CLI performs only the build of your Angular code while skipping the Android/iOS build, then it deploys your code to NativeScript Preview (a companion app hosting your app code).

To use preview, you need to install two companion apps on your Android/iOS device(s):

  • NativeScript Playground (Android, iOS) — used to scan a QR code provided by the NativeScript CLI
  • NativeScript Preview (Android, iOS) — used to host display your app

Migrating Project Structure

The first step to convert your web project to a code-sharing structure is to add NativeScript. You can do this with the following command:

ng add @nativescript/schematics

The command installs @nativescript/schematics, and then adds a NativeScript-specific copy of:

  • The Main file - main.tns.ts, which bootstraps the NativeScript Entry Module,
  • the Entry Module file - by default this is app.module.tns.ts, which is based on the name of the module provided to bootstrapModule in your main.ts,
  • Entry Component file - by default this is app.component.tns.ts, which is based on the name of the component provided to bootstrap in the web entry module,
  • and the App Routing file - app-routing.module.tns.ts, which brings in NativeScriptRouterModule. It also provides a path to a sample component (AutoGeneratedComponent).

Sample module

You can also run the ng add command with a --sample flag.

ng add @nativescript/schematics --sample

This command adds a BarcelonaModule, which is a sample NgModule to show how a code-sharing module should be constructed. It can also be used for validation that the conversion of the project was successful.

Validating the project migration

The easiest way to validate that the migration worked is to build and run your apps.

Validate the web project

Run ng serve -o from your terminal or command prompt, and you should get the same app as before running ng add.

Validate the web project with the sample module

If you migrated your project with the --sample flag, you could also test the sample module in your web app.

Assuming your app is configured with app navigation, add BarcelonaModule to your entry module (default: app.module.ts), run ng serve, and in your browser navigate to /players (i.e. http://localhost:4200/players). You should see a list of Barcelona players, and if you click on any name the app should navigate to /player/:id.

Validate the NativeScript project

To validate the mobile setup build the NativeScript application by executing:

tns preview

After a short moment, the CLI will present you with a QR Code. Scan it with the NativeScript Playground app, which will connect your project with the NativeScript Preview app.

As soon as you scan the QR Code, the CLI will bundle the TypeScript code from your project and push it to the NativeScript Preview app.

Migrating Project content

The ng add @nativescript/schematics command converts the project to a code-sharing structure, but it doesn't convert your app contents.

The next step from here is to migrate your:

  • navigation
  • components
  • modules

Migrate Navigation

Running ng add @nativescript/schematics automatically adds app-routing.module.tns.ts, which contains:

  • routes - with a single path to the default NativeScript component
  • @NgModule - with the configuration for NativeScripts version of the RouterModule - NativeScriptRouterModule

This has the same structure, as the default routing module configuration for the web when you run ng new app-name --routing.

Split Routes

At this stage you will work with two separate navigation configurations (routes):

  • app-routing.module.ts - for web (this is the usual file name for it, but it might be different in your project),
  • app-routing.module.tns.ts - for mobile

This is especially useful, while you migrate all web components into a code-sharing structure. Once this is complete, you could switch to a singe routes configuration for both web and mobile.

Also, if you expect your web app to have a different set of pages to your mobile app, then you could keep the routes separate. For example, your web app could have an admin screen, which might not be required in the mobile app. In this case it makes sense to have two sets of navigation configurations.

The process here is that you should add navigation paths to the routes array in app-routing.module.tns.ts, as you migrate each of your page components.

Shared Routes

To convert your project to use a single (shared) navigation configuration, you need to move the routes configuration to a single shared file, and make the app-routing files for web and mobile, import and use the shared routes.

Here are the steps:

  1. Add a shared file with the routes configuration: app.routes.ts

    import { Routes } from '@angular/router';
    
    export const routes: Routes = [
      { path: '', redirectTo: '/players', pathMatch: 'full' },
    ];
    
  2. Replace the routes configuration in app-routing.module.ts with the import of ROUTES

    import { NgModule } from '@angular/core';
    import { RouterModule } from '@angular/router';
    import { routes } from '@src/app/app.routes';
    @NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
    })
    export class AppRoutingModule { }
    
  3. Replace the routes configuration in app-routing.module.tns.ts with the import of ROUTES

    import { NgModule } from '@angular/core';
    import { NativeScriptRouterModule } from 'nativescript-angular/router';
    import { routes } from '@src/app/app.routes';
    @NgModule({
    imports: [NativeScriptRouterModule.forRoot(routes)],
    exports: [NativeScriptRouterModule]
    })
    export class AppRoutingModule { }
    

Migrating Modules

You should also migrate your NgModules into code sharing modules.

Often the migration step will consist of these steps:

  • Add the NativeScript version of the @NgModulemodule-name.module.tns.ts,
  • copy the providers from your web @NgModule,
  • copy the imports from your web @NgModule - use NativeScript versions for those that are web-specific (e.g. use NativeScriptHttpClientModule instead of HttpClientModule)
  • convert all of modules' components, by using migrate-component schematic,
  • and migrate declared components and add them to declarations

This task can be helped with the module migration schematic:

ng g migrate-module --name=module-name

Migrating Components

Your next task is to migrate your individual components into a code-sharing structure.

Often the migration step will consist of two steps:

  • add the component to a .tns version of the parent module
  • create a name.component.tns.html file, and provide NativeScript specific UI code

This task can be helped with the component migration schematic:

ng g migrate-component --name=component-name

In the case where the component class contains web-specific code, you will need to extract the platform-specific code into a set of helper files of services and keep only the shared code. You can read more on handling partial differences here.

Schematic: migrate-component

The migrate-component schematic looks up the location of the ComponentNameComponent in app.module.ts and then performs the component migration steps, which involve:

  • adding the component to app.module.tns.ts and
  • creating a component-name.component.tns.html file.

You can execute it using the Angular CLI:

ng g migrate-component --name=component-name

For example, to migrate:

src
└── app
    ├── home
    |   ├── home.component.html
    |   └── home.component.ts
    ├── app.module.ts
    └── app.module.tns.ts

Run the following command:

ng g migrate-component --name=home

This will create home.component.tns.html and update app.module.tns.ts.

src
└── app
    ├── home
    |   ├── home.component.html
    |   ├── home.component.tns.html  <= create
    |   └── home.component.ts
    ├── app.module.tns.ts            <= update
    └── app.module.ts           

Components not belonging to AppModule:

It is important to understand that migrate-component uses the parent NgModule to locate the migrated component, so when you want to migrate a component that doesn't belong to AppModule, you need to provide the parent NgModule.

ng g migrate-component --name=component-name --module=module-name

This schematic will find the location of the ComponentNameComponent in module-name/module-name.module.ts and then perform the component migration steps, which involves:

  • adding the component to module-name/module-name.module.tns.ts and
  • creating a *module-name/component-name.component.tns.html * file.

For example, to migrate:

src
└── app
    └── animals
        ├── dog
        |   ├── dog.component.html
        |   └── dog.component.ts
        ├── animals.module.tns.ts
        └── animals.module.ts

Run the following command:

ng g migrate-component --name=dog --module=animals

This will create dog.component.tns.html and update animals/animals.module.tns.ts.

src
└── app
    └── animals
        ├── dog
        |   ├── dog.component.html
        |   ├── dog.component.tns.html  <= create
        |   └── dog.component.ts
        ├── animals.module.tns.ts       <= update
        └── animals.module.ts       

Modules with non-standard file names

In the cases of modules with non-standard file names, you can provide a full path to the module by using the --module-path parameter.

For example, to migrate:

src
└── app
    └── animals
        ├── dog
        |   ├── dog.component.css
        |   ├── dog.component.html
        |   └── dog.component.ts
        ├── animals-md.tns.ts
        └── animals-md.ts

Run the following code to achieve the same result.

ng g migrate-component --name=dog --module-path=animals/animals-md.ts

Skip Module Updates

You can also tell the schematic to not update its parent module by using the --skipModule flag.

ng g migrate-component --name=component-name --skipModule

Skip Module Updates - with direct path

In the case where you want to use --skipModule for components that are not located at src/app, you need to provide the path to the component by using the --component-path parameter.

For example to migrate the dog component:

src
└── app
    └── animals
        └── dog
            ├── dog-cmp.html
            └── dog-cmp.ts

Run the following code to achieve the same result.

ng g migrate-component --name=dog --component-path=animals/dog/dog-cmp.ts --skip-module

Schematic: migrate-module

The migrate-module performs the module migration steps, which involve:

  • add module-name.component.tns.ts,
  • convert all of components provided by the module, by using migrate-component schematic for each,
  • copy over all providers from the web module

For example, to migrate the animals module:

src
└── app
        └── animals
        |   ├── cat
        |   |   ├── cat.component.html
        |   |   └── cat.component.ts
        |   └── dog
        |       ├── dog.component.html
        |       └── dog.component.ts
        └── animals.module.ts

Run the following command:

ng g migrate-module --name=animals

This will result in the following changes.

src
└── app
    └── animals
        |   ├── cat
        |   |   ├── cat.component.html
        |   |   ├── cat.component.tns.html  <= create
        |   |   └── cat.component.ts
        |   └── dog
        |       ├── dog.component.html
        |       ├── dog.component.tns.html  <= create
        |       └── dog.component.ts
        ├── animals.module.tns.ts           <= create
        └── animals.module.ts

Migrating to Remapped Imports

Remapped imports are preferred over relative imports in code-sharing projects. The ng add @nativescript/schematics command extends your project TSLint configuration with the prefer-mapped-imports rule. The rule enforces the use of remapped imports and also provides a fix for existing relative imports. To convert the relative imports in your project, execute:

ng lint --fix

The prefer-mapped-imports rule is part of the @nativescript/tslint-rules package. To learn more about it, refer to the official GitHub repository.