Back to Blog Home
← all posts

Migrating to NativeScript 6.0

July 16, 2019 — by Stanimira Vlaeva

The highly expected 6.0 release of NativeScript is dangerously close! Two of the biggest changes in this release are the AndroidX support and the bundle (webpack-only) workflow. Both of them may require changes in existing projects. Follow this blog post to find out how to migrate your application code to NativeScript 6.0.

tns migrate

tns migrate is a new CLI command aiming to help with the NativeScript 6.0 migration process. Executing this command in an existing project will update:

  • the build configuration files used by the CLI ("webpack.config.js", "karma.conf.js", "tsconfig.tns.json").
  • most of the plugin dependencies to versions, compatible with 6.0.

Update your NativeScript CLI and execute the migration command in your project:

npm install --global nativescript@latest
tns migrate

Then, run the application with the familiar command:

tns run

If you experience problems during your development workflow, you might need to make changes to your application code to make it compatible with NativeScript 6.0. Read the rest of the article to find out how. If your problem is not mentioned, please open an issue on Github.

AndroidX

NativeScript 6.0 supports the Android extension libraries (AndroidX). The Android Support Library is no longer supported. Any application and plugin code relying on the support library must start using AndroidX instead. To learn how to migrate, follow the dedicated blog post

CLI Hooks

The NativeScript CLI hooks allow you to customize the execution of a CLI command. They are widely used in NativeScript plugins. The hooks API is changed in version 6.0. You might be using an outdated plugin if your build is failing with an error such as:

Cannot read property X of undefined.

To learn how to update an outdated hook refer to this article.

Bundle workflow

Prior to version 6.0, NativeScript used to support two ways of building your application: 

  • tns build - The Legacy Workflow, which copies the full content of the source code directory (src/) to the built application;

  • tns build --bundle - The Bundle Workflow, which relies on webpack to bundle the source code directory (src/) into a few output files.

NativeScript 6.0 supports only the bundle workflow. When updating your project, you need to make sure it can be built with webpack. The NativeScript team put a lot of effort to close the gap between the legacy workflow and the bundle workflow. However, the two approaches are quite different and their behavior cannot be completely unified. Below you will find the most common differences between them with migration steps for each one.

Static assets must be loaded manually

Project type

All

Code Sample

The following code tries to load a local file - /assets/shipping.json.

export class CartService {
...
  getShippingPrices() {
    return this.http.get('/assets/shipping.json');
  }
}
Legacy workflow

All files from the source directory are part of the built application. That's why the /assets/shipping.json file will be available and loaded successfully.

Bundle workflow

Webpack only compiles files that are explicitly required in the source code or included by a webpack plugin. With the default setup /assets/shipping.json won't be in the built application and the request will fail.

Migration

Configure the CopyWebpackPlugin to move the static resources from your project to the built application.

webpack.config.js

module.exports = env => {
…
    const config = {
        ...
        plugins: [
        ...
             new CopyWebpackPlugin([
                { from: { glob: "assets/*.json" } },
                { from: { glob: "fonts/**" } },
                { from: { glob: "**/*.jpg" } },
                { from: { glob: "**/*.png" } },
            ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
}

Worker threads

Project type

All

Migration

You need to use the nativescript-worker-loader plugin to create worker threads. Make sure to install the package using the next tag:

npm install nativescript-worker-loader@next --save-dev

Refer to the documentation to migrate your code based on the project type.

Template and style paths must be relative

Project type

Angular

Code sample

Consider the following code located in app/item/items.component.ts, which uses an absolute path for the templateUrl:

@Component({
    selector: "ns-items",
    templateUrl: "app/item/items.component.html"
})
export class ItemsComponent {
...

Legacy workflow

The legacy workflow used to support the above syntax.

Bundle workflow

The bundle workflow doesn't support the above syntax. The templateUrl and styleUrls paths are resolved relative to the current module.

Migration

Convert the absolute paths to relative:

@Component({
    selector: "ns-items",
    templateUrl: "./items.component.html"
})
export class ItemsComponent {
...

Exports object cannot be used in TS projects

Project type

TypeScript

Code sample

The following code uses the exports object to export a function:

exports.onTap = function () {
    alert("Hi there");
}

Legacy workflow

The legacy workflow used to support the above syntax.

Bundle workflow

The bundle workflow doesn't support the above syntax.

Migration

Use the export keyword instead:

export function onTap() {
    alert("Hi there");
}

Pro tip

With the bundle workflow, you can now use the ES6 module syntax (import and export) in all types of projects. Prefer it over CommonJS (require and exports) to help webpack eliminate all unused exports from your bundle.

Different values of __dirname and __filename

Project type

All

Code sample

Consider the following code located in app/nested-folder/test.ts:

console.log("__dirname", __dirname);
console.log("__filename", __filename);

Legacy workflow

In the legacy workflow, the project structure used to remain the same in the built application. Executing the code above would have resulted in the following console output:

__dirname /data/data/org.nativescript.ns5/files/app/nested-folder
__filename /data/data/org.nativescript.ns5/files/app/nested-folder/main-page.js

Bundle workflow

In the bundle workflow, the built application is packaged in a few output files. The file locations are not persisted. The output from the above code will be:

__dirname /data/data/org.nativescript.ns6/files/app
__filename /index.js

Migration

You can use module.id to get the original file path. 

console.log(module.id) // ./nested-folder/main-page.ts

However, if you build for production the module.id will be a number. To enforce webpack to continue using file paths for the module IDs, set the namedModules optimization property to true:

module.exports = env => {
…
    const config = {
        ...
        optimization: {
             namedModules: true
         }
}

The __dirname will point to the absolute path of the bundle file. Using __dirname and module.id you can calculate the original absolute file path and directory of the module.

Enum values are not inlined

Project type

TypeScript

Code sample

The following code declares an enum without defining it and then uses it:

declare const enum TestEnum {
    value1 = 1,
    value2 = 2
}

console.log("Printing the second enum value: ", TestEnum.value2);

Legacy workflow

The above syntax was supported. The legacy workflow used to rely on the nativescript-dev-typescript plugin to perform a TypeScript compilation. The plugin used to start the TypeScript compiler - tsc.

Bundle workflow

The bundle workflow uses the ts-loader in a transpileOnly mode. The enum values are not inlined. Running the code above results in a reference error:

ReferenceError: TestEnum is not defined

Migration

You need to modify a couple of settings in your `webpack.config.js` file. In the configuration of `ts-loader`, set `transpileOnly` to `false`. Also, make sure to remove the `ForkTypeChecking` plugin.