Yesterday we released a new version of the NativeScript Webpack plugin that includes some non-trivial changes. In this article we’ll walk you through why we made these changes, and what you’ll need to change in your apps to upgrade.
In NativeScript 3.4 we added support for Angular 5, and Angular 5 for webpack comes with a new AngularCompilerPlugin. The plugin internally creates a TypeScript compiler instance, and uses that instance as the basis for the webpack file system during compilation.
Because of that update, we had to make some changes to support the module and resource resolution conventions we use in NativeScript, for example platform-specific files such as my-component.ios.html
and my-component.android.html
. Our new extension of the AngularCompilerPlugin, NativeScriptAngularCompilerPlugin, has faster build times, and opens up the potential for us to use webpack’s --watch
flag in the future.
For NativeScript Core apps, webpack configs will now include a PlatformFSPlugin
, and map platform-specific files similar to the way the NativeScriptAngularCompilerPlugin
does.
This change unlocks the ability for us to support consuming webpack contexts when registering modules. Your app’s bundle-config.js
file will now automatically include all your page.xml|js|css files. Previously, only the .js
and .xml
files were consumed from the registered modules.
Hopefully we will eventually allow the community to write custom XML loaders that will handle component registration and ahead-of-time XML to JavaScript compilation. This should be fun!
NOTE: The
NativeScriptAngularCompilerPlugin
uses just-in-time compilation by default, and you need to use a separate flag to enable ahead-of-time compilation. Check out this section of the NativeScript webpack documentation for more information.
Webpack’s css-loader
can now be used to resolve CSS files used in the NativeScript core modules. This includes all .css
files for plain NativeScript apps, as well the app.css
file for Angular apps. Your app.css
will now be bundled in your vendor.js
file, and it will therefore be parsed during the Android snapshot generation. This feature was ready in the NativeScript Core modules, but the necessary webpack config was not yet released. It is now!
SCSS is now supported for both webpacked and non-webpack apps, as well as for Angular components, vanilla NativeScript pages, and app.scss
files. All of these file types also support platform-specific suffixes.
Prior to NativeScript v3.4.0 and nativescript-dev-webpack 0.9.0, building with webpack required running external npm scripts. With the NativeScript 3.4 CLI release we integrated the webpack plugin directly into the NativeScript CLI—there is no need for separate npm scripts.
For example, before NativeScript 3.4 you would run the following command to run an Android app with webpack bundling.
npm run start-android-bundle
With NativeScript 3.4 you can now run the following command to accomplish the same task.
tns run android --bundle
This integration makes it easier to pass in other CLI options such provisioning profiles (e. g. tns run ios --bundle --provision NativeScriptDevProfile), and it also gives us a path towards integrating the webpack watcher and debugging in the future.
Now that we’ve covered what’s why we updated the webpack plugin and what we changed, let’s look at how you can upgrade your apps.
You first need to install the latest (currently 3.4.0) version of NativeScript CLI.
npm i -g nativescript
Next, you need to update your platform and tns-core-modules dependencies of your project by running the following command.
tns update
If you are using Angular in your NativeScript app, you next need to update to version 5.0 of the NativeScript Angular plugin.
npm install --save [email protected]
After that, you’ll also need to update your Angular versions as well. Specifically you need to update your @angular/
dependencies to version ~5.0.0
, your rxjs dependency to ^5.5.0
, and your typescript
dependency to ~2.4.2
. You will also need to add one extra dependency—@angular/platform-browser-dynamic
.
You can use the script below to do all that:
./node_modules/.bin/update-app-ng-deps
If you are using NativeScript Pro UI in your NativeScript app, you next step is to update it to its latest version (currently 3.3).
npm install --save nativescript-pro-ui@latest
With those dependencies out of the way, next update your NativeScript webpack plugin to version 0.9.0.
npm install --save-dev [email protected]
NOTE: Make sure you have have committed your current version of all webpack related files:
./app/vendor-platform.android.ts
./app/vendor-platform.ios.ts
./app/vendor.ts
./webpack.config.json
You can generate new versions of those files for the new version of the plugin using the command below:
./node_modules/.bin/update-ns-webpack --configs --deps
Next, you’ll want to apply any custom configurations you have previously made on the newly generated files.
If you have CSS imports that reference files from node_modules
you need to prefix them with a tilde (~
).
For example, if you have the nativescript-theme-core
package you will need to make the following changes in your app.css file:
Before:
@import 'nativescript-theme-core/css/core.light.css';
After:
@import '~nativescript-theme-core/css/core.light.css';
NOTE: This is different from ~/
.
~
(just tilde) will resolve the path relative to node_modules
.~/
(tilde and slash) will resolve the path relative to the app
directory.This step is for NativeScript Core projects only (aka apps that don’t use Angular).
You can now register your app’s XML, CSS, and JavaScript resources with a regex instead of listing them one-by one. Here is how you can modify your bundle-config.js
or bundle-config.ts
to do that:
if (global.TNS_WEBPACK) {
// registers tns-core-modules UI framework modules
require("bundle-entry-points");
// register application modules
// This will register each `page` postfixed xml, css, js, ts, scss etc. in the app/ folder
const context = require.context("~/", true, /(page|fragment)\.(xml|css|js|ts|scss|less|sass)$/);
global.registerWebpackModules(context);
}
Here is a link to these code changes:
https://github.com/NativeScript/template-hello-world/commit/9121973bd3289358284b0da9d33a98e7624c4955
For TypeScript and Angular projects, you also need to update your nativescript-dev-typescript
plugin by running the following command:
npm install --save-dev nativescript-dev-typescript@latest
This step is for Angular projects only.
You can now get rid of your tsconfig.aot.json
file. However, you will need to update your tsconfig.json
file to now exclude only thenode_modules
and platforms
folders:
"exclude": [
"node_modules",
"platforms",
"**/*.aot.ts"
]
In your main.aot.ts
you probably have the following import:
import { AppModuleNgFactory } from "./app.module.ngfactory";
The ngfactory
file is dynamically generated during AOT compilation. To satisfy Typescript static checks, add a app.module.ngfactory.d.ts
file with the following content:
export const AppModuleNgFactory: any;
Now that the upgrade is done you’re ready to start building your apps with the new version of the NativeScript webpack plugin. Because the NativeScript CLI now directly supports the webpack plugin, you can delete any existing scripts you might have in your package.json
file for building/running your app with webpack.
After cleaning those old scripts out, go ahead and try using the new --bundle
flag to make sure everything works.
tns run ios/android --bundle
or
tns build ios/android --bundle
There are a couple of options you can pass to configure the webpack build:
--env.aot
- to enable angular AOT. Note: this is false
by default--env.snapshot
- to enable V8 snapshots (Android only)--env.uglify
- to enable uglify--env.report
- output webpack build reportsNOTE: Livesync is still not supported for webpack builds. This is something that we will be working on in the future. Exciting times lie ahead 😄
If you run into any problems during the upgrade feel free to reach out on the NativeScript community forum, and if you find issues with the webpack plugin itself please report those on GitHub.
This is just the first of many exciting things we have in store for the webpack plugin. Look forward to some cool new webpack functionality next year!