Package Bundler
Github: GitHub - robertklep/package-bundler: Bundle a Node.js package into a single file.
This tool can be used to create single-file Node.js packages from existing (NPM-hosted) packages.
I’ll explain why this can be useful with an example:
At the moment I’m working on an app that depends on homey-api
. Just adding this package to my project made the installation time of my app (homey app run
) explode into multiple dozens of seconds.
The reason is two-fold: homey-api
and all its dependencies take up 7MB of disk space, and consists of about 3500 files (this is the main performance killer when it comes to Homey apps).
By bundling homey-api
into a single file, its size is cut down to about 600K, and just a single file. See below for a “benchmark”.
How to use
Follow the installation instructions on the Github page.
To bundle homey-api
, run the following command:
$ package-bundler homey-api
This will create a directory homey-api
in the current directory that contains the bundled file (index.js
). If you move this directory into your app directory, you can use it from your app code as a regular relative import:
// app.js
const { HomeyAPIApp } = require('./homey-api');
Don’t forget to remove homey-api
as a dependency of your app, otherwise it will still be uploaded:
$ npm uninstall homey-api
(if you for some reason want to remove the package(s) manually, don’t just remove them from node_modules
without updating package.json
, because you’ll get an error about missing requirements when you run homey app run
).
Some remarks
- It should be no problem to publish apps to the App Store with bundled packages like this.
- Not all packages can be bundled, especially packages that use dynamic imports.
- Not all packages have to be bundled. Just pick the ones that are large and/or consist of a lot of files.
- A bundled package always requires a relative import, so if you want to use it from a driver/device file, you need to use something like
require('../../homey-api')
(or possiblyrequire('/homey-api')
). - Instead of placing bundled packages directly in your app directory, I would suggest placing them in a subdirectory (say
modules/
) to keep things nicely separated. Adjust your import paths accordingly. - I haven’t tested this script very well and wrote it mainly for my own purpose. If you run into any issues, hit me up.
“Benchmark”
Let’s test how long it takes for homey app run
to install/start/stop an app that does absolutely nothing other than loading homey-api
.
- Unbundled:
$ time homey app run
✓ Pre-processing app...
— App archive size: 6.9 MB, 3521 files
✓ Running `my.test.app`, press CTRL+C to quit
✓ Uninstalling `my.test.app`...
✓ Homey App `my.test.app` successfully uninstalled
homey app run 1.71s user 1.11s system 6% cpu 40.349 total
- Bundled:
$ time homey app run
✓ Pre-processing app...
— App archive size: 703 KB, 10 files
✓ Running `my.test.app`, press CTRL+C to quit
✓ Uninstalling `my.test.app`...
✓ Homey App `my.test.app` successfully uninstalled
homey app run 0.77s user 0.16s system 13% cpu 6.631 total
So the unbundled version takes 40 seconds, the bundled version takes 6 seconds. And that’s including uninstallation too, which is relatively slow. The time until the app is uploaded, installed and started takes about 35 seconds unbundled, and 2 seconds bundled.