Category Archives: Performance

Optimization Gotcha's for for/i and forEach

So I mentioned something on my interview with Alex of NativeScripting.com that he did with me. And someone asked about this in the comments, so I decided to create a blog article on this specific optimization tip.

I am going to code this to a browser rather than in NativeScript because well JS in a browser is just plain easier to show the memory issues because you can plop the code in to a new browser tab and step through the code instantly. 🙂

<html>
<body><div id="stacklayout"></div></body>
<script type="application/javascript">

// Pretend Color class to be similar to NativeScript
class Color {
    constructor(val) { this._color = val; }
    toString() { return this._color; }
}

const <strong><em>colors </em></strong>= ["#ff0000", "#00ff00", "#0000ff"];
for (let i=0;i&lt;<strong><em>colors</em></strong>.length;i++) {
    const labels=["Wow","Awesome","Interview", "Alex", "Created!"];
    for (let j=0;j&lt;labels.length;j++) {
        const clr = new Color(<strong><em>colors</em></strong>[i]);
        const txt = <strong><em>document</em></strong>.createElement("div");
        txt.innerText = labels[j];
        txt.style.backgroundColor = clr.toString();
        const parent = <strong><em>document</em></strong>.getElementById("stacklayout");
        parent.appendChild(txt);
    }
}
&lt;/script>
&lt;/html>

And you should see something like this:

We are repeating the labels for each of the primary colors...

Or you might be used to doing something like this instead:

&lt;html>
&lt;body>&lt;div id="stacklayout">&lt;/div>&lt;/body>
&lt;script type="application/javascript">

class Color {
  constructor(val) { this._color = val; }
  toString() { return this._color; }
}

["#ff0000", "#00ff00", "#0000ff"].forEach((clr) => {
  ["Wow","Awesome","Interview", "Alex", "Created!"].forEach((word) => {
     const txtColor = new Color(clr);
     const txt = <strong><em>document</em></strong>.createElement("div");
     txt.innerText = word;
     txt.style.backgroundColor = txtColor.toString();
     const parent = <strong><em>document</em></strong>.getElementById("stacklayout");
     parent.appendChild(txt);
  });
});

&lt;/script>
&lt;/html>

Both have several issues, however the second one can be vastly worse than the first one depending on how many iterations. So lets walk through the issues.

So the Color class is fine, we are using it to show creating objects... So just ignore it for now.

const <strong><em>colors </em></strong>= ["#ff0000", "#00ff00", "#0000ff"];
for (let i=0;i&lt;<strong><em>colors</em></strong>.length;i++) {

These lines are fine, we allocated colors, then looped through them. So far so good. Lets proceed, what about:

const labels=["Wow","Awesome","Interview", "Alex", "Created!"];

Well here is the first issue; Fortunately for us, the v8 JS engine actually pre-allocates the 5 different string "Wow" through "Created!" when it parses the JavaScript however, each loop through it does create a brand new Labels array and then links those strings into it. So in this case it is small overhead; however in the 3 loops that still is 2 more sets of allocations and all new GC enties that have to be cleaned up after the loop is completed. If you were to put this single line of code outside the loop; your code runs the same, but no less memory usage and less processing.

 const clr = new Color(<strong><em>colors</em></strong>[i]);

What about this line, well in this case all 15 times it creates a brand new Color object. You can easily make this only be ran 3 times just by moving it outside the inner for (j) loop into the for (i) loop. In this example the Color class is very light weight. But many classes you create inside loops will be very heavy with lots of allocations going on when you allocate the class. So pay attention, 3 allocations vs 15 allocations, all by putting the line in the wrong spot...

Continuing on, most the rest of the lines has to be inside the loop; but I tossed another item into the loop, that wasn't needed... This line is very easy to accidentally end up in the loop because you needed it at that point.

     const parent = <strong><em>document</em></strong>.getElementById("stacklayout");

Yep, this has to do an expensive lookup in the dom to find this element, it never changes. It also has to allocate it to that "parent" variable 15 times. If you dropped it before/outside of both loops, you would have a single lookup and allocation...

---

Finally lets look at the last example; it suffers from the same issues. However, this one I used a Array.forEach rather than the simple for (i) loop. Why do I say it can be worse then? Well in small numbers, the difference is actually pretty tiny. The extra amount of memory it uses over a for (i) loop is also reasonable. But in larger loops (especially loops inside of loops inside of loops); the difference can end up being exponentially larger.

Your creating and calling functions, and all those functions now has added scopes and the engine has to setup all the callstacks for each and every iteration, additional error checking and just plain running a lot more code behind the scenes. So what is a simple for (i) loop in the first example, now became 15 EXTRA functions calls with all the extra overhead of cpu and memory that entails. Again in small chunks they are perfectly fine, but if you are wanting performance, every ms and gc adds up and sometimes they can add up very quickly when dealing with the Array helper functions that use callbacks...

As a better way to phrase this; imagine you have a for (i) loop that takes 5ms and a forEach loop takes 25ms to finish. Both are still dang fast, hard to even benchmark. But now you embed it in another forEach that also by itself takes 25ms. 25ms * 25ms = 625ms. More than half of a second. But, if you were to switch this to a for (i) loop each of them is 5ms. So, 5ms * 5ms = 25ms. Both are exponentially larger, but 25ms vs 625ms and the difference starts becoming much clearer. Now add a third loop; 5ms*5ms*5ms = 125ms. 25ms*25ms*25ms=15,625ms (or > 15 seconds!) In small chunks the time and memory used from a forEach is minuscule. But depending on how many times it is called; it can add up very quickly to be a major difference.

Please note this goes for all the nice Array helper functions, .map, .reduce, .filter, etc. Everyone of them that uses a callback, has somewhere between 2 times and 50 times as much overhead as a simple for (i) loop. Remember, despite this overhead; these functions are extremely fast. So don't be afraid to use them, but be more wary of using them in deeply nested code that can easily be called in loops when the datasets they are working against are also large.

As many items that you can actually move outside of your loop, the better off you are. This Includes any expensive calculations! You might be able to do 99% of the expensive calculation outside of the loop; and then finish off the last part of the calculation inside the loop...

I hope this answers the question about loops and performance. Every loop is a golden opportunity to greatly enhance your app,

VMWare - Shrinking disk size Macintosh/Linux

If you have a Macintosh or Linux based image; the tooling to shrink the hard drives is basically broken in the Gui (and/or, don't work). So to shrink these types of containers; the easiest method is to force the entire empty area to be Zero's, then defragment, and finally shrink all ..

First thing we need to do is Zero all blocks that are no longer used. Please note this will make your container grow to the maximum size your container is allowed to grow; so you might need a lot of disk space!

cat /dev/zero > zerofile; rm zerofile

Next you need to shutdown the client, so on linux it might be shutdown now -h or clicking a couple buttons to shutdown cleanly. After the VM has been shutdown you need to run the following commands from the command line.

vmware-vdiskmanager -d <diskimage.vmdk>

This command will defragment the image; moving all the data to the front of the image and all the empty blocks to the end. You obviously need to point the &lt;diskimage.vmdk> at wherever the vmdk you are working with is located, and if the vmware-vdiskmanager is not on your path; you will have to manually call it from wherever it resides. Finally you need to call

vmware-vdiskmanager -k <diskimage.vmdk>

As this will shrink the image; and if you are lucky, your 280 gig image will shrink to 80 gigs.

NativeScript-SQLite Multi-Threading!

The first release of NativeScript-SQLite was April 19th, 2015 on GitHub, and April 26th to NPM. I am happy to say this plugin is now almost 4 years old, and it was one of the first plugins available to NativeScript. I believe there was two or three others released before, like NativeScript-Flashlight. By June of 2015 we had a grand total of 18 (eighteen) plugins in the NativeScript eco-system, where today we are at almost 1,000 plugins.

NativeScript-Sqlite has had a lot of upgrades like encryption, prepared queries, and several bug fixes over the last 4 years. But the newest feature; I'm probably the most proud of. Without your app changing a thing (besides setting a simple option flag); NativeScript-Sqlite can now be fully multithreaded. What do I mean by that? In a nutshell all SQLite calls can now happen in a background thread. This means that if you are inserting or reading 20 records the UI won't freeze.

A couple years ago I did a session on Performance and NativeScript; my sample app showed how doing several different things could freeze the UI easily; and the best way to deal with this was to move as much of your work to background threads.

Now if you watch this image; every time I hit the SQLite button, the "n" freezes for a few seconds. This is because the work loading and processing the records is all done on the main thread which is the UI thread, causing the Animation to stop and/or stutter.

Since NativeScript-Sqlite has always been Promise (and/or Callback) based ASYNC code; it ended up that I could preserve the entire API as is; when allowing you to use multithreading. You just need to set a flag when opening up the connection and it will become multithreaded.

And this is what it looks like when sqlite is doing everything in a background thread. Notice how smooth it is. This is because the main thread is just waiting for the acknowledgement back that everything has been loaded.

If you check out the demo app; the code change is just this:

new sqlite(dbname, {key: \'testing\', multithreading: !!sqlite.HAS_COMMERCIAL}, function(err, dbConnection) {

Basically if the commercial plugin has been loaded; we flip on the multithreading flag. Otherwise we leave it off. (This way the app can test, Encryption, Multithreading, Commercial features, and no extra features all in the same codebase.)

The open source version of the plugin can be easily installed by typing tns plugin install nativescript-sqlite@latest, the open source repo can be seen at https://github.com/NathanaelA/nativescript-sqlite.

The commercial version which includes Encryption, transactions, prepared queries, and now multithreading can be purchased from my site at nativescript.tools.

NativeScript application wide runtime settings (updated 5.2)

NativeScript Switch

On thing most people are probably not aware of is that the Android runtimes has a large number of knobs and switches to customize certain behavior of the engine.   I will try and list out all the current switches and knobs that you can use.   iOS now has one switch.

First of all the settings go into the /app/package.json   If you open up the default package json you probably will see:

{   
    "android": {      
        "v8Flags": "--expose_gc"    
   },    
   "main": "app.js",
   "name": "tns-template-hello-world",
   "version": "5.2.0"
}

That "android" key is where everything goes for Android specific settings.   The default setting that comes in the files is "v8Flags": "--expose_gc" this one is rather critical in that this enabled the runtime to call gc from JavaScript.   Now, there is quite a few v8Flags you can use; most the time they aren't needed but if you need to tune the v8 engine; you can add more flags into this string.  I even list a few in this post.   Let me warn you again; DO NOT remove the "--expose_gc".   You will cause your app to crash when something attempts to call the GC from code.

As of version 5.2; there is a "ios" key called "jscFlags" option that is now available. My recommendation while building/testing your app is to add the key "ios": { "jscFlags":"--validateOptions=1" } The jscFlags has items that can be used to tweak the JavaScript core engine. You can find more flags here.

Ok, so here is the complete list of settings you can change in the Android section:

SettingDefaultMin VersionDescription
gcThrottleTime03.xAllows you to throttle
how frequently JS GC
triggers native GC
See:
Memory Management
memoryCheckInterval03.xHow frequently to check
memory usage
See:
Memory Management
freeMemoryRatio0.03.xRation of memory before a GC is ran (works with
memoryCheckInterval)
See:
Memory Management
markingModefull3.xSwitches which type of GC engine to use.  "none" will enable a different engine which doesn't do
marking.  Typically faster
for Angular apps
handleTimeZoneChangesfalse4.1True will enable the
ability for a time zone
change in the settings to
effect the NS app.
maxLogcatObjectSize10244.0How many lines of text a
console output will log.
forceLogfalse4.0True will enable logging
in release mode
suppressCallJSMethodExceptionfalse5.1True will suppress the
boolean type conversion error from null that could randomly occur and crash the application.
codeCachefalse2.xTrue - Enables code
caching in the v8 engine.
v8Flags--expose_gc1.xTunes the v8 engine
heapSnapshotBlob""2.x(Believe to be unused
now)
heapSnapshotScript""2.x(Believe to be unused
now)
snapshot.blob""2.x(Believe to be unused
now)
profilerOutputDirKey""2.x(Believe to be unused
now)
profiling""2.x(Believe to be unused
now)

IOS Level Flags:

SettingDefaultMin VersionDescription
gcThrottleTime05.2Allows you to throttle
how frequently JS GC
triggers native GC
See: Custom Flags
memoryCheckInterval05.2How frequently to check memory usage
See: Custom Flags
freeMemoryRatio0.05.2Ration of memory before a GC is ran (works with
memoryCheckInterval)
See: Custom Flags
jscFlags""5.2Tunes the JavaScriptCore engine. Valid Flags

Top Level Global Flags:

SettingDefaultMin VersionDescription
discardUncaughtJsExceptionsfalse4.2True - will disable
crashing on JS errors, will
log any issues to console.

Recommended changes:
discardUncaughtJsExceptions: "true" - This will keep the app from crashing on certain types of errors; this should be enabled for release mode! Some developers might find it more productive to have this enabled while coding to eliminate application crashes. Please note you MUST pay attention to the console if you enable this during development; because most JS errors that would crash out; will now be just logged to the console.

suppressCallJSMethodExceptions: "true" - This will keep the app from crashing on the boolean conversion issue that can occasionally occur.  This is not to say the app might have some other issue later; but this will eliminate a stupid (imho) crash reason.

markingMode: "none" - This will enable the experimental GC engine, this will help incredibly with Angular based apps. Please note it "might" cause more crashing errors if a plugin forgot to hold a reference to something it needed later. However with the above discardUncaughtJsExceptions enabled; those errors won't crash the app.

Late Breaking news; in 4.2 they actually moved "discardUncaughtJsExceptions" to the top level of the package; the reason why is because shortly after they added the support to Android; the support was added to iOS.  So now this flag controls both iOS and Android, so it no longer belongs just in the "android" block.

So in your package json would look like this if you used my recommended settings:

{
   "android": {
       "v8Flags": "--expose_gc",
       "markingMode": "none",
       "suppressCallKSMethodExceptions": "true"
    },
    "ios": {
        "jscFlags": "--validateOptions=1"
    },
    "discardUncaughtJsExceptions": "true",
    "main": "app.js",
    "name": "tns-template-hello-world",
    "version": "5.2.0"
}

NativeScript 4.1.0 Released

I took a bit of a break from reporting on NativeScript things; but guess what, I'm BACK!!!

Well, looks like I was on the ball again this time.   😉    4.1.0 has been released to NPM, and it is HOT!

Version 4.0 was a great release and all; had a lot of cool changes.   But 4.1 is an awesome release building upon that great release and if you haven't upgrade to the NativeScript 4 yet; this is what you have been waiting for!   Thank you Progress.

First of all the item that we have been all waiting for if you do any Android development; they have updated the Android V8 engine to pretty much the latest stable released version.  So we jumped from v8 v5.5 to v6.6.   Now that might not seem like a large change but the number of changes in the v8 engine from v5 to v6 are incredibly large.   We now have the brand new JavaScript optimizing engine (Turbo Fan); the new optimized Garbage Collection engine, pretty much full ES6 support ; and so many other countless optimized features -- I could dedicate a post to all the cool things we now have access to in Android.   In a nutshell this v8 is now considerably faster.  In fact one of the tweets you might have seen is how much faster this version even starts the application.     Always awesome for our customers to have the app startup now almost twice as fast.   For all you iOS fans; v4.0.0 of NativeScript upgraded the JavaScript core to pretty close to the latest, so now both sides are running the state of the art JavaScript engines..

In addition to that awesome change that is totally worth the upgrade by itself - we can now use Angular 6 and Webpack 4!   I'm sure many of you will be very happy to see these.

Now that I'm done drooling over all this new found speed and these two other awesome feature updates; lets run down some of the other new features and fixes that you get for free when you upgrade:

  • Android: "in" names space is now fixed.  Prefix it with a $ so that it is $in.rest.of.namespace.
  • Android: Java ByteArray to ArrayBuffer support was improved to support more types of ByteArray's.
  • Android: Latest Gradle now used (and a bug fixed against it).
  • Android: Several Console fixes; including release mode no longer logs.
  • Android: Fixed JNI crash
  • Android: Debug tools are and LiveSync fixes.
  • Android: Android P fixes!
  • Android: ReturnKey no longer fires twice
  • Android: Transition no longer crashes
  • iOS: Console fixes
  • iOS: Inspector port no longer times out quickly
  • iOS: Flexbox fixes
  • iOS: getImageAsync() added
  • iOS: searchbar and listview sizing fixes
  • All: Modal dialog fixes
  • All: Navigation fix
  • All: LayoutChanged event added
  • All: css; linear-gradient support
  • All: File System; get file size
  • All: TabView font size
  • All: Read XML from Bundles
  • Angular: Angular 6 Support!
  • Angular: router state should no longer crash the app in an invalid state
  • Webpack: Webpack 4 Support!
  • Webpack: XML Loading support
  • Webpack: Android Compression
  • CLI: Supports driving more than one iOS simulator
  • CLI: Support Java 10
  • CLI: Full application templates (Beta)
  • CLI: Allow native Objective C source as part of plugins.
  • CLI: iOS wifi driving should work again.

What do you think; I think this is a Rock'n awesome release, thank you to the different development teams (and community members) who contributed to this release!

First of all to upgrade is done is a couple steps:
> npm install -g nativescript@latest
> npm install tns-core-modules@latest --save

Next try the new update command or you can manually run the commands below
> tns update

For Android:
> tns platform remove android
> tns platform add android@latest

For iOS
> tns platform remove ios
> tns platform add ios@latest

Then you can type tns info and verify that everything says 4.1.x

Common Issues:

  1. None so far.  🙂

NativeScript: Performance from the Trenches

Well my video for Performance from the Trenches, was released today!   This is the talk I gave at the NativeScript Developer Days 2017.

 

There is a lot of good useful information in this Talk, so enjoy.

Slide Deck: Performance

NativeScript App: https://github.com/NathanaelA/PerformanceFromTheTrenches

V8-Natives Repo: https://github.com/NathanaelA/v8-natives

 

 

 

MySQL SSL required connection Ubuntu solutions

I went to implement MySQL replication for a client this evening and ran into some interesting issues that I haven't ran into before. Guess it has been a while since I had to set it up for a client.   So this post is for notes for me or someone else who might need to do this in the future. The normal installation replication installation works great but if you are going to enable ssl connections this is where the things can get a bit more complex.

The first thing to find out is if you have your SSL setup correct, try doing:
And verify the SSL is enabled and build in, in my case everything looked good:

mysql&gt; SHOW VARIABLES LIKE '%ssl%';

have_openssl  = YES
have_ssl      = YES
ssl_ca        = /etc/mysql/certs/ca-cert.pem
ssl_capath    =
ssl_cert      = /etc/mysql/certs/server-cert.pem
ssl_cipher    =
ssl_crl       =
ssl_crlpath   =
ssl_key       = /etc/mysql/certs/server-key.pem\";

This looks correct, so the next thing to figure out is where the error log file is located;
mysql&gt; SHOW VARIABLES LIKE '%error_log%';

log_error     =  ./mysql-bin.err
or something like
log_error     = /var/log/mysql/error.log

Now that you know where the error log is at you can see why it is failing.

In my case the error was this:

2016-12-06 23:21:33 32695 [Warning] Failed to setup SSL
2016-12-06 23:21:33 32695 [Warning] SSL error: SSL_CTX_set_default_verify_paths failed

I love that it is a "Warning".   It is totally broken, but we will list it as a Warning...

Well, this can be caused by several things:

  1. No permissions to the files in the folder, use chmod/chown to give perms.
  2. SELinux blocking it, disable selinux or grant permissions via SELinux
  3. AppArmor blocking it.  (this was my case)

Edit the /etc/apparmor.d/usr.sbin.mysqld file.

You'll see something like this in the file:

/etc/mysql/*.pem r,
/etc/mysql/conf.d/ r,
/etc/mysql/conf.d/* r,
/etc/mysql/*.cnf r,
---&gt; /etc/mysql/certs/*.pem r,  &lt;---
/usr/lib/mysql/plugin/ r,

Add the ---> line <---, make sure it matches your path to where you are storing the certs.  Then restart mysql. After restarting the server, I then got this error: SSL error: Unable to get private key from '/etc/mysql/certs/server-key.pem' 2016-12-06 23:53:32 21728 [Warning] Failed to setup SSL 2016-12-06 23:53:32 21728 [Warning] SSL error: Unable to get private key Ok, this one threw me for a while.  The files are fully readable by MySQL.  The issue ends up being incompatibilities between SSL libraries in use.  OpenSSL 1.0x vs yaSSL The key file will start like this:
-----BEGIN PRIVATE KEY-----

If you used OpenSSL to generate the keys;  OpenSSL creates keys in PKCS#8 with a SHA256 digest.  Of course yaSSL which is (normally) used by MySQL doesn't support either, and want PKCS#1.  So despite having the files fully readable, MySQL is telling you it can't figure out how to "get the private key" out of the file.  Once you know the issue, it has a simple solution:
openssl rsa -in server-key.pem -out server-key.pem

when you are done with this command the beginning of the file should look like this:
-----BEGIN RSA PRIVATE KEY-----

Again, the internal format is different, so don't try and just change the text and insert the "RSA" into it -- it will look like it works until something try's to connect using SSL.

Once you have this done, restart mysql again and you should be good to go.

NativeScript - Workers

ns-workersOne of the best new features in the brand new 2.4.0 release of NativeScript is WebWorkers.    For those who have seen me around in the community; you will probably all know how long I have been harassing the NativeScript Core Teams to get this done (Since Aug of 2015).  I even went so far as to create a plugin (NativeScript-WebWorkers) that allowed you to spin up more JS threads but with the major limitation that they didn't have access to the native OS side of things, they were only pure JS.    So getting real 100% NativeScript webworkers this release means I am a VERY happy camper!

The feature is fully cross platform (i.e. works on iOS and Android) and allows you to spin up additional JavaScript engines to do all your heavy lifting needs in the background.    Now obviously, the more you spin up the more memory and cpu you will use; so you want to treat them as a precious resource and only spin up those you need.   Let me re-iterate; use these for only heavy duty processes; each worker is another FULL JS engine, which takes a chunk of memory and cpu to just start and maintain.

They still have full access to the iOS and/or Android runtime just like normal.   The only difference between them and the main thread is that you do not have any valid access to the GUI or GUI elements.   You can attempt to modify the GUI, but you will crash your app as you are not allowed in even in a native app to modify the GUI outside the main thread.  Same rules apply to a NativeScript app.

The NativeScript Core Teams modeled the background threads after the web workers model.  They are created, developed and destroyed the same way as a browser web worker would be.   So lets dig in.

Everything is passed via messages between the workers and the main thread; so lets look at a sample demo:

main file

"use strict";
exports.onNavigatingTo = function(args) {
   let myWorker = new Worker('./myWorker.js');
   myWorker.onmessage = function(msg) {
     console.log("Hi I'm a message from the worker: ", msg.data);
     myWorker.terminate();  // We no longer need the worker around, so kill it.
   };
   myWorker.onerror = function(err); {
      console.log("Opps, something went wrong in the worker", err.message);
   };
   setTimeout(function() { worker.postMessage("a Cool Message"); }, 500);
}

myWorker.js
"use strict";
require("globals");
global.onmessage = function(msg) {
  console.log("Got a message form the main thread!", msg.data);
  postMessage("Worker's cool Message");
  // global.close();  // If ran, this would close the worker from inside.
};

global.onerror = function(err) {
  console.log("We can handle our own errors too", err.message);
};

Now as you can see we have two files; the first file is from the main thread it starts the new worker by doing let myWorker = new Worker([path to worker script]); this is how you start a brand new worker.   The new worker will load that JavaScript file and start it up.  Now there are some gotcha's we are going to cover on the worker side that you will want to know about.

  1. You want to require('globals'); as your first or second line.    If you do NOT require the global module, you will not have access to console, setTimeout , setInterval, and any other function you are used to using globally.   So requiring this function is pretty important for most workers.
  2. When you assign .onmessage (or .onerror if you are using it) you must assign them to the global variable.  The new version of the Android engine is enforces "use strict"; properly and having implied "this" variables is NOT allowed.  So as a habit when assigning something to the global scope; implicitly use global.
  3. All messages have a .data parameter that contains the data you sent from the other side.  When you do a postMessage({cool: "wow", I: "am"}); this will be in msg.data.cool and msg.data.I in the onmessage message.  This might catch you, but is easily fixed.  Please make sure that any objects you send across to the other side is fully serializable (i.e. no recursion, no native gui elements) ; if not it will fail unless you use some third party lib to serialize the recursive structure.
  4. Terminate() or Close() the webworker if you are no longer going to use it.  If you are planning on continuing to use it; then leave it running it is cheaper to leave it running (& not doing anything) than to terminate and restart.
  5. If you get an error message like this: Worker Error: Uncaught TypeError: Cannot read property 'prototype' of undefined this can mean it can't find the worker file that you wanted to load.  Using the tilde to say main app folder '~/path/to/worker' is the easiest way to fix it.  OR it can mean that the file that is required is doing something that is causing the worker to crash.
  6. If you see the error: Uncaught TypeError: global.moduleMerge is not a function The solution is to do a require('globals'); at the top of your worker file.

Once you understand these items, you are ready to rock and create cool background threads to do all your busy work so that your main thread never freezes again...

NativeScript: WebPacking

The NativeScript team released a cool plugin using the "WebPack" code to packup the entire code base and since it does things like tree shaking; your end result is a much smaller app.

Well I had an opportunity to test it over the last couple weeks for a friend of mine (Nathan Walker) as he is prepping to release a very very cool app.

However, the NS-Webpack plugin is unfortunately very (very) buggy; and odds are very (very) likely if you are doing anything beyond a very simple application; it will not work.   You can see a stack of bug reports in the repo for all of these issues I mentioned and some others; so hopefully these issues will soon be just a distant memory, and it will work as intended.

So many days later; and after much debugging, we can declare that we have smacked and cajoled webpack into shape and we were able to get it to actually webpack an application properly!

So here is the things you need to do if you want to webpack something while it is in its current state...

Fonts

The first thing you need to be aware of; is that on iOS if you are using any custom fonts; the automatic font registration is totally broken when webpack'ed.  The solution is to fallback to what we used to have to do on iOS; which is manually register the font.   The code I wrote for this project looks like this:

if (global.NSObject &amp;&amp; global.NSString) {
  var font = require('ui/styling/font');
  font.ios.registerFont('fontawesome-webfont.ttf');
}

Basically the if statement tests for iOS, then I manually require the font class; and finally the last line; I registered the font I needed.  You can repeat the last line for each font you are using.

Pathing Issues

The second issue is only if you use your screens/components in a subfolder type system the url pathing to find them breaks under webpack code.  So when you have something like this:

/app/components/blah/
-blah.js
-blah.html
-blah.css

and inside your blah.js you have code like this:
Blah = _decorate([
...
templateUrl: 'blah.html'
...

This will fail; ALL the JS is actually bundled into the webpack'd bundle file; so when it goes to try to find this file, the JS code is running from the root directory of your app.  Where your actual html file is not in the root.  So you have to change the path to be:
templateUrl: './components/blah/blah.html'

Pretty simple fix if you know about it; but man if you don't it starts crashing...

Crashing on Startup

The final issue is simple and complex at the same time.  NativeScript iOS runtime has some built in short-circuits for __extends and ALL the Native objects (i.e. like NSObject, NSString...) -- well Webpacking unfortunately changes the signature of the __extends function and so the runtime doesn't detect that the function is actually a __extends...  This causes the runtime to run code that isn't actually supported and so it, well, crashes...   This can be solved in one of two ways;

  1. You edit each of the plugins that are installed and manually strip out the __extends function.  (and then let the plugin author's know to disable creating the __extends in their plugin as this code normally is just pointless and a waste of space and memory, and in the webpack case it is now deadly -- So just add "NoEmitHelpers: true" to the tsconfig file).
  2. You add a simple plugin that I wrote to your main project directory; this plugin will automatically strip out all __extends while it is webpacks so that it doesn't matter if the plugin author forgot to set that flag; the simple plugin eliminate it.

/**********************************************************************************
 * (c) 2016, Master Technology
 * Licensed under the MIT license or contact me for a Support or Commercial License
 *
 * I do contract work in most languages, so let me solve your problems!
 *
 * Any questions please feel free to email me
 * Version 1.0.2                                      Nathan@master-technology.com
 *********************************************************************************/
"use strict";

function eliminateExtends(pre) {
    var i = pre.indexOf('var __extends = ');
    if (i === -1) {
      return pre;
    }
    var x = pre.indexOf('};',i);
    return pre.substring(0,i) + pre.substring(x+2);
}
module.exports = eliminateExtends;

You copy this code into an eliminateextends.js file in your root folder of the project; and modify your apps webpack's config file to use this as a loader plugin.

Please note this is not all the bugs in webpack; there are a couple others on the https://github.com/NativeScript/NativeScript-Dev-WebPack/issues repo that we didn't run into; but these were the only ones that we ran into for a iOS NG2 project.   So make sure you check out the bug list if you are still having issues...

Happy NativeScript-WebPacking!

NativeScript: Patreon Posts & Plugins

For those who are unaware; I've started doing paid content; see my post on "Why Patreon" to see the reasons.   I'm going to attempt to keep this post updated with plugins and posts that are available to those who are my patreon supporters.

Posts:

 

Plugins: