The NativeScript 4.1 release includes an update for the nativescript-dev-webpack plugin. The new version of the plugin is 0.12.0 and brings a few important changes.

Don't miss the next NativeScript webinar that covers {N} 4.0/4.1 along with Angular and Vue.js code sharing strategies!

Webpack 4 and Angular 6

The plugin now requires webpack v4+, Angular v6+ and {N} v4+.

Faster startup for Android

The extended UglifyJS support for Android and the improved snapshot bundle generation led to smaller bundle sizes and faster launch times. Adding that to the new super fast Android runtime, the total launch time improvement is ~50% for every app that we measured. Please share the results for your apps! The table below shows the launch times before and now for a few NativeScript apps. They are built in release mode with enabled ahead-of-time compilation, minification and snapshot.



Android

runtime 4.0

{N}-webpack 0.11.0 Android

runtime 4.1

{N}-webpack 0.11.0 Android

runtime 4.1

{N}-webpack 0.12.0 Improvement App: Groceries

Device: Pixel 2 1467ms 1156ms 764ms 51.76% App: Hello world Angular

Device: Pixel 2 1277ms 976ms 600ms 46.99% App: SDK samples

Device: Nexus 5x (slower than Pixel 2) 2301ms 1816ms 1333ms 57.93%



Easier setup

For non-Angular projects you had to configure a few things manually to make webpack work. Usually, you would add a bundle-config.js file in your project to require the xml pages, register external UI plugins, load the css, etc.

You don't have to do that anymore and can safely delete the bundle-config file, because the nativescript-dev-webpack plugin will configure all of the above things for you. The plugin achieves that with a couple of webpack loaders, that are now part of your webpack configuration. We'll go through each loader in the next sections.



Dependencies

As mentioned above, the plugin requires webpack 4. Clearly, the first thing you need to do in order to upgrade to webpack 4 is to… update your webpack dependency to version 4. However, if you are developing {N} apps, there is a chance you are using a whole bunch of webpack loaders and plugins. And if your app is built with Angular, you also need to update your Angular packages. Here are a few steps you can follow to automate the update process:

[Angular only] Update the nativescript-angular package:

npm i nativescript-angular@6.0.0 [Angular only] Update your @angular/* packages. There's a script distributed with the nativescript-angular package which will do that for you: ./node_modules/.bin/update-app-ng-deps [Angular only] You have to migrate your code to Angular 6. This will help you a lot - https://update.angular.io. Update the nativescript-dev-webpack package:

npm i --save-dev nativescript-dev-webpack@0.12.0 Update your webpack plugins and loaders by running the special script distributed with the nativescript-dev-webpack package:

./node_modules/.bin/update-ns-webpack --deps

Make sure you are using {N} runtimes and tns-core-modules 4.0 or higher version. If it's possible, upgrade to 4.1 to take advantage of the awesome performance improvements in the Android runtime and all the new features in that release.

// package.json

{

"name": "MyAwesomeProject",

"version": "0.0.0",

"nativescript": {

"id": "org.nativescript.myawesomeproject",

"tns-ios": {

"version": "4.1.0"

},

"tns-android": {

"version": "4.1.0"

}

},

"dependencies": {

// ...

"nativescript-angular": "~6.0.0",

"nativescript-theme-core": "~1.0.4",

"tns-core-modules": "^4.1.0",

"zone.js": "~0.8.2"

}

}

Webpack config

The webpack.config.js file that's distributed from the plugin is quite different from the previous one. If you have made manual configurations, make sure to create a backup. Then pregenerate the config and apply your changes to it.

# back up your modified config mv webpack.config.js webpack.config.js.bak

# get the latest version added to your project ./node_modules/.bin/update-ns-webpack --configs

# find the differences and apply the manual changes that you need diff webpack.config.js webpack.config.js.bak

EcmaScript modules

All TypeScript and Angular apps now use target EcmaScript modules when built with webpack. That allows webpack to remove all unused exports from your code and improves the final bundle size.

A special tsconfig.esm.json file, which specifies that, is added to your project when you install the nativescript-dev-webpack plugin. It looks like that:

// tsconfig.esm.json { "extends": "./tsconfig", "compilerOptions": { "module": "es2015", "moduleResolution": "node" } }

That introduces a breaking change. You can't use import assignment when targeting ES2015 modules. If you see the following error:

ERROR in app/calendar/calendar-localization/calendar-localization.component.ts(2,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead.

You need to migrate your import assignments in the following way:



BEFORE

import buttonModule = require("tns-core-modules/ui/button"); const testButton = new buttonModule.Button();

AFTER

import * as buttonModule from "tns-core-modules/ui/button"; const testButton = new buttonModule.Button();

or even better:

import { Button } from "tns-core-modules/ui/button"; const testButton = new Button();



Importing only the Button class will allow webpack to tree-shake all unused code from the tns-core-modules/ui/button module. This will lead to smaller app sizes and faster launch times.

Split chunks plugin

The CommonsChunkPlugin is gone in webpack 4 in favor of the SplitChunksPlugin. We changed the way we generate chunks to be compliant with the new webpack splitting strategies.

All external packages and custom Android app components that you use in your app are extracted to the vendor.js chunk. Because all external packages are in the common chunk, you don't have to add explicit requires inside app/vendor.ts . That's why app/vendor.ts , app/vendor-platform.android.ts and app/vendor-platform.ios.ts are gone. If you have them in your app, you can delete them. If you want something else to be part of the vendor.js chunk, modify the splitChunks configuration inside webpack.config.js .

Snapshot generation changes and customization

The changes in the vendor.jsgeneration also affect the snapshot plugin. The cool thing is that now you have all your NativeScript plugins snapshotted out-of-the-box and you don't have to worry if they have native API access inside of them or not. That's because they are not executed. If you want to explicitly execute some plugin on launch, you need to add it to the requireModules array that's part of the NativeScriptSnapshotPlugin configuration. That will be beneficial only for quite big plugins and you probably won't ever need to do it. For example, the main Angular packages are executed when generating snapshot for NativeScript Angular apps:

// webpack.config.js

// ... new nsWebpack.NativeScriptSnapshotPlugin({

chunk: "vendor",

requireModules: [

"reflect-metadata",

"@angular/platform-browser",

"@angular/core",

"@angular/common",

"@angular/router",

"nativescript-angular/platform-static",

"nativescript-angular/router",

],

projectRoot,

webpackConfig: config,

});



Minification improvements

UglifyJS's compress option was breaking the NativeScript static binding generator for Android and was disabled for that platform. We've identified the causes and the option is now enabled, which results in smaller app bundle and better launch time.

Bundle config

As mentioned above, the new version of the nativescript-dev-webpack plugin comes with a few loaders that reduce the number of manual steps you have to do to make your project webpack-ready.

