Reducing size of Hot code pushes for cordova clients

Hi,

I’m trying to load js packages/parts of my apps dynamically on demand but also I’m also trying to split my code into multiple .JS files in meteor.

My goal is mostly to make smaller Hot Code Push to my Cordova users using mobile phones.

Our app.js file has grown to 6,5mb and our mobile users are complaining their actions don’t get saved when the websocket is too slow, which usually happens when:
-We’ve pushed new versions and their 4G network is congested or in rural area

I could not find articles on how to split app.js in multiple files.

We’re using meteor 1.5.4

Regards,
Burni

Seems like code splitting is not being implemented in cordova as it is expected that the entire bundle is in the phone. The entire app is being run through a local internal server in the app

Ijrdavid,

I’m not sure if you’re saying what I’m trying to accomplish is not possible using Cordova?

In another thread(Code Splitting an Packages), JKuester kind of implied that the idea is to actually reduce the package size but he has not detailed how yet.

Regards,

Burni

I’m trying to load js packages/parts of my apps dynamically on demand but also I’m also trying to split my code into multiple .JS files in meteor.
My goal is mostly to make smaller Hot Code Push to my Cordova users using mobile phones.

The whole mobile environment is basically like the client environment, which I thought it would just make sense to use dynamic-import as much as possible. I think the hot code push for client code will only include the statically imported modules.

I think @rjdavid mentioned in another post a while ago, that they managed to reduce client bundle size to 1mb.

I am pointing to this strategy as I think there is a specific reason why there is only one app.js file (= the client bundle) that is initially loaded and it is to prevent loading time by using multiple initial files. You may rather load the module via dynamic-import on-demand means when the specific Template or component is required and not all just at one.

We’re using meteor 1.5.4

Cordova code splitting may have already been solved in later versions. Is there a specific reason that you are not updating your Meteor to 1.10.2 (which also updates cordova)?

Can you point to any material about Meteor Cordova supporting code splitting?

We are running a cordova app and would like to implement if it is indeed possible.

Correct me if I get this totally wrong but I thought that the “exact code splitting” via dynamic-import will also work the same in the Cordova environment?

Very interesting. I’ll try to figure out how dynamic imports work.

The reason we have not upgraded to 1.10.2 is quite a shame. Our senior developper who was in charge of these things left the company and while I was a good developper in other languages, I have not yet mastered all the ways of doing things with meteor/node/cordova.

And from what I understand, to migrate to 1.6.x, some syntax we’ve been using was deprecated and I have not yet put in the effort to understand what we have to modify in order to upgrade to 1.6 and then up to 1.10. Most documentation I find is old and now refers to 404 pages :frowning:

I didnt think dynamic-imports work in Cordova, by which I mean that the “dynamic” imports are part of the complete bundle - we looked into this before (back in 1.8, so maybe it changed). Would be happy to know that this has changed though as we’ve had the same issues.

I think you should talk to your current senior/lead/management and explain them that its crucial for update first and it will take time but in the long run it will make things much worse if you don’t. Especially from a security perspective this should get a high priority (if your app serves a crucial purpose in production).

Thanks Jan.
Actually we’re looking to hire a senior dev. so I’m the most senior one at this point. I don’t want to abuse your help and time but would you happen to know what breaking changes actually happend in the syntax between 1.5.4 and 1.6 ?

I remember he said something specifically about the syntax/structure of getmeteordata getting deprecated. We’re using this syntax here:

ComponentEmployersActive = React.createClass({
    getInitialState() {
        if (Meteor.settings.public.debug) console.log('client/components/main/Employers.jsx/ComponentEmployersActive(getInitialState)');
        return {};
    },
    mixins: [ReactMeteorData],
    getMeteorData() {
        if (Meteor.settings.public.debug) console.log('client/components/main/Employers.jsx/ComponentEmployersActive(getMeteorData)/subscribe: Publish_AssistantEmployers for AssistantEmployers');
        let employersHandle = undefined;
        if (this.props.currentUser.admin == true) {
            employersHandle = subsCache.subscribe("FAST_Publish_AssistantEmployers_ADMIN_ALL", Cookie.get('AssistantCookie'));
        } else {
            employersHandle = subsCache.subscribe("FAST_Publish_AssistantEmployers_EmployerDocument", Cookie.get('AssistantCookie'), window.global_current_employer._id);
        }
        let allEmployers = db.AssistantEmployers.find({state: "active"}, {
            sort: {
                statsLandingLast3Days: -1,
                statsFaceTimeTotal: -1,
                dateBeginOperations: 1
            }
        }).fetch();

        return {
            loading: employersHandle == undefined || !employersHandle.ready(),
            allEmployers: allEmployers
        };
    },```

I can't find much here that seems breaking or related to getmeteordata in articles related to upgrading or even in this forum:
https://guide.meteor.com/1.6-migration.html
https://github.com/nodejs/wiki-archive/blob/master/Breaking-changes-between-v4-LTS-and-v6-LTS.md
https://github.com/nodejs/wiki-archive/blob/master/Breaking-changes-between-v6-and-v7.md
https://github.com/nodejs/wiki-archive/blob/master/Breaking-changes-between-v6-LTS-and-v8-LTS.md

Thanks again ! It's really appreciated

I am not the React specialist here but https://atmospherejs.com/meteor/react-meteor-data is the actual component for connecting react with meteor, I think.

Maybe some React folks can help out here better?

We split code along three lines:

First, we defer loading the bulk of the application until after login. The login page loads the bits it needs along with all the router files. The router files use dynamic imports for anything their endpoints need. Given a successful login, the app imports code supporting the homepage and feed. Deeper elements get loaded as users drill deeper into the app.

This approach defers loading app-level code but the packages still are all loaded with the login page. Excepting the below, we have yet to find a way to defer loading of packages. While there might be 1-2 that that login does not need, it’s low priority for us because those that it does are the overwhelming majority of the codebase that lives in packages.

Second, we have enduser and admin/console sides to our application. The who, what and how for these is quite different. Importantly, the admin console is not part of our Cordova app so we don’t want all that code in there. Thus we split the code by building separate servers that apply different packages too. They of course point to the same Mongo and file store. Users can hop between the servers thanks to Meteor documentation.

@rjdavid is of course very right. All of your code – in our case all enduser code – is shipped with the Cordova app and served by a device-resident localhost. Hot code push (HCP) is refreshing that code, that served by the localhost, so it is pushing everything including anything referenced by dynamic import (hence why dynamic imports can’t use variables). While this is a large download, it certainly beats the alternatives :slight_smile:

Finally, we support white-labeling. As this is just reskinning the app, we don’t build separate servers for it. We use subdomain to identify a white-labeled request and then SSR to inject the CSS. White-labeling takes a little more though – in particular, you need different localhost port numbers and Meteor’s SSR does not support HCP. The latter requires using SSR client-side, i.e. not in the localhost but rather applying the client-side call the package makes available.

Wow – aren’t I chatty this morning? Regardless, I hope that helps.

1 Like

Hi GDC3!

That was very interesting. Thanks a lot for the depth of detail. We’re currently working on upgrading to meteor 1.10 and then we’ll probably work on dynamic imports to make the app lighter and load faster !

That surely helps! thanks

Just to summarize, dynamic imports have no effect in cordova.

Hi gdc3,

we’ve been having recent problems with our Cordova bundle. We added a module (aws-sdk s3) and it has grown from 7.7mb to 8.5… and on older iPhones, it does not load.

It’s a pure blank screen and there’s nothing shown in the console.

Since last year, have you found ways to make the cordova bundle smaller ?

Regards,

Burni

Meteor’s Cordova implementation will bundle all HTML and Javascript into the app because the localhost serves those (rather than your servers). Hot code push refreshes that code for the localhost.

While we defer most of the business logic with dynamic imports, this really only helps browsers. Also, packages are still sent with the login page. Conceivably we could defer some of these, but they’re mostly utilities so we don’t see the few kilobytes of savings as worth the effort.

I’d offer that 8.5Mb is not that big. It doesn’t feel like your problem is size. I’m not familiar with the AWS S3 SDK, but maybe it’s doing something — or expecting a minimum OS level — that is the root of your problem? FWIW IMHO I’d flow any storage thru your servers rather than direct from the app to an S3 volume.

Hope that helps, at least some :slight_smile:

gdc3,

that surely helps!! Thanks a lot. I’ll check into that for S3. Your intuition might be very good. I also felt that 8.5mb is not that much (I meant for the minified JS file only).

So, putting aws-s3 only on the server is very interesting. Would you know how to install an npm package that goes only in the server bundle without affecting the client ? I could not find a way so far.

It’s been installed through meteor npm install.

Your help is very much appreciated.

Regards,

Burni

Check how you import the aws-s3 package. It means that the file where you import the npm package is also being imported in the client. Ideally, you have a complete separation of files imported between client and server.

In our case, we have normally 3 folders: client, server, shared.

Hi, recently (I think this year) AWS finally split their large AWS SDK into smaller bundles.
I use this NPM “@aws-sdk/client-s3”.

However, I think you should use the “sling” principle and upload media from your client directly to S3 and avoid useless traffic via your Meteor servers.
You may find some inspiration here and if you put an hour into this package you can update it to use the new S3 client instead of the generic AWS SDK: https://github.com/Lepozepo/s3-uploader/tree/master/packages/client. You may also depend on specific Lodash packages in the client side instead of loading the entire library.
Very simply put, client requests upload signature from your Meteor server and uses the signature to directly upload to S3. Receive the file name from S3 and write your document record to Mongo.

Hi Paul,

I would have preferred to send directly from the client too but there seems to be a problem with Cordova when I add the @aws-sdk/client-s3 NPM. On older iPhones , users get a blank screen. And the XCode console shows no error message at all.

Don’t you get this problem too ?

So