Skip to content
This repository has been archived by the owner on Jun 14, 2023. It is now read-only.

Improve assets copy to android filesystem on first install & on update #8

Open
tdurand opened this issue Dec 16, 2020 · 3 comments
Open
Labels
enhancement New feature or request

Comments

@tdurand
Copy link
Member

tdurand commented Dec 16, 2020

Problem

In order to use nodejs-mobile , you need to first copy the node.js app files to the phone filesystem, you can't start node.js directly with the APK file. (todo when the App in first installed and anytime that the node.js app is changed (each app update) )

Right now we were using the "recommended" method from nodejs-mobile, which is to ship the app + node_module folder in the assets directory and recursively copy this to the phone file system https://code.janeasystems.com/nodejs-mobile/android/node-project-folder#copy-the-nodejs-project-at-runtime-and-start-from-there .

Problem with this is that with a big node_module folder with quite a lot of dependency like OpenDataCam , this means copy pasting 24,723 Files, 4,709 Folders and 142 MB .. And on top of adding 140 MB to the app size, copying lots of small files is slow.

"Out of the box" , the first app install takes 2min30s (and each update).

Two things we are looking to improve here:

  • App first install and subsequent update time needed: ie-> copy files faster
  • App dependency size: reduce that 142 MB -> have less files to copy

copy files faster

Turns out that there was a low hanging fruit here to improve this, instead of copy pasting all the files recursively which is slow, we create a zip at build time of the node.js app and then unzip it on the phone. ( idea from stackoverflow: https://stackoverflow.com/a/42415755 )

I've tried that : c1fcca4 and we get from 2min30s to around 20 seconds .. So this is already a huge win 🙌

Only downside is that we need to integrate that zipping on the build process. for now I'm doing it manually with this command:

zip -0 -r ../nodejs-project.zip .

Have less files (and less MBs) to copy

Thinking of having 24,723 Files, 4,709 Folders for 142Mb of files in the node_modules folder is a bit crazy.. when the client side part of the app (actually loaded in the browser) is max 5 MB .. the server side part has obviously node.js has a dependency but not even included in those 142 MB ( it is 142 MB + the 30-50 MB of node.js) ... My guess is that it might also be only 5 - 20 MB in the end...

Normally we never care about this because we do the npm install on the server and the size of the node_modules folder doesn't matter.. what matters is how much you send to the client ( see explanation here: vercel/next.js#14339 ) . Here we want to also reduce this to avoid.

  • having a huge app of 300 MB (which is not that prioritary)
  • speed up the time to copy the files a install time by reducing the files number & weight

One tool to our service for this is npm prune --production , which you can run after npm run build and delete all the node_modules dependencies that are listed as "devDependencies" in the package.json: https://github.com/opendatacam/opendatacam/blob/master/package.json#L43

Out of the box doing this already reduce a bit, down to 115 MB (121,226,417 bytes) and 22,298 Files, 4,231 Folders

What I need to do next is to improve this, by:

  • putting more things in the devDependencies, maybe some stuff are listed in the normal dependencies but not needed when running
  • remove some dependencies.. for example mongodb : Persistence Layer : MongoDB -> NeDB #7
  • maybe cherry-pick node_modules dependencies better than just with the npm prune (which is I think just copy/do not copy) , here is an analyse of the dependencies tree .. for example our node-moving-things-tracker is 10 MB because it ships MOT17 benchmark files... and the node.js is really using 3 javascript files, maybe 100 kB max 😉

image

image

@tdurand tdurand added the enhancement New feature or request label Dec 16, 2020
@tdurand tdurand changed the title Improve assets copy to android filesystem on update & on first install Improve assets copy to android filesystem on first install & on update Dec 16, 2020
@tdurand
Copy link
Member Author

tdurand commented Dec 16, 2020

Some trial and error progress notes:

Found out this project while looking into the "webpack" of node.js : https://github.com/vercel/ncc , it is from the same people doing next.js

It is supposed to be able to build your node.js app into a single index.js file (which is huge) containing all the node_modules dependencies you need.. then you just need to do: node index.js without needing the node_module folder.

This seems very much what I'm looking to do.. and I was able to make it work properly on a very simple example project that uses express: https://github.com/vercel/next.js/tree/canary/examples/custom-server .

Final app necessary files:

image

What you need to do is:

# create the .next  folder containing the client side code 
npm i
npm run build
# pack the node.js server side code in the dist/ folder
ncc build server.js
# this creates a dist/ folder with an index.js in it (18 MB with express.js)

# then you need to copy the client side code to the dist/ folder (so the index.js app can use it)
cp -r .next/ dist/

# then launching the app should work
cd dist/
node index.js

Also very important you need to disable the auto routing of next.js by hooking to next to node.js this way in your server.js file

const app = next({ useFileSystemPublicRoutes: false })

But while trying on OpenDataCam I run into a couple of issues:

  • On the development branch some code using the new class syntax with "private field" is failing when packing with ncc (this is not a big deal to change, just two files) , it is a known issue of the tool: Private class fields break build vercel/ncc#499

  • When fixing the issue from above (using master branch for now) then I run into a new error which is super cryptic

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
    at resolveDispatcher (/mnt/c/Users/tibod/Documents/GitHub/opendatacam/node_modules/react/cjs/react.development.js:1465:13)
    at useMemo (/mnt/c/Users/tibod/Documents/GitHub/opendatacam/node_modules/react/cjs/react.development.js:1520:20)
    at Provider (/mnt/c/Users/tibod/Documents/GitHub/opendatacam/node_modules/react-redux/lib/components/Provider.js:22:41)
    at processChild (/mnt/c/Users/tibod/Documents/GitHub/opendatacam/dist/index.js:470359:14)
    at resolve (/mnt/c/Users/tibod/Documents/GitHub/opendatacam/dist/index.js:470276:5)

Couldn't figure out how to fix this yet... related to ncc packing several copy of React I think in the big index.js ...

Also investigating I've seen someone trying the same thing but failing also (not for the same reason: vercel/next.js#8574 )

I will pause investigation for now as the priority is to get a beta out.. but this ncc tool is promising.... Also I think it might be a good time to get rid of express.js if we move forward with this.. as there are lightweights alternatives now..

@tdurand
Copy link
Member Author

tdurand commented Jan 6, 2021

Some update on this.. was able to make very good improvements on this, down to reducing the first load to 5 seconds, same as the subsequent opening of the app 🙌 , and reducing also the size of the app by 20-30 MB..

This improvement was made by adding a build step to statically export the whole front-end app and only ship this to the device instead of having the whole next.js dependencies and have the node.js making the front-end app render dynamically on the device... ( reminder: the slowness didn't come from rendering the app but from copying thousands of small @babel, react etc.. files )

This comes at the cost of increasing a bit the diff between the "opendatacam mobile" branch and the normal branch: opendatacam/opendatacam@development...mobile, documenting here some more changes for my future self

I guess in the future is it would be better to make this "webpack" for node : ncc solution work.. but in the meantime this is a good workaround that makes the experience way better.

@tdurand
Copy link
Member Author

tdurand commented Mar 7, 2022

Dropping this here as I though about this old issue, maybe will be useful at some point 😅 , next.js now has a standalone output mode that exports the necessary dependencies without needing to cherry-pick node_modules folder: https://nextjs.org/blog/next-12-1?utm_source=next-site&utm_medium=banner&utm_campaign=next-website#self-hosted-nextjs-improvements

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant