android icon indicating copy to clipboard operation
android copied to clipboard

[FR] Customize metadata generation to avoid adding unnecessary unused JS wrappers

Open mbektchiev opened this issue 5 years ago • 6 comments

Is your feature request related to a problem? Please describe. Currently, the whole Android SDK and all native libraries used in a {N} app are included in the metadata binary files. In order to reduce app size and improve startup performance, we should allow app/plugin developers to specify which entities (e.g. Java packages) need to actually be accessible from JavaScript.

Additional context Things to consider:

  • This will be a breaking change because every plugin and every app which directly call into native code will need to start stating their native dependencies
  • Multiple such dependency lists coming from all plugins and the app should be merged. Maybe some changes in the CLI will be necessary as well.
  • There should be a way to allow everything to be included (like it's been before this feature)

An idea for UI which helps generate these lists from @shirakaba: Polyfill.io shows one user interface by which one could generate a package by specifying only the libraries that one needs. Maybe something like this could be applied to the NativeScript runtimes: https://polyfill.io/v3/url-builder/

Corresponding feature request in iOS runtime is: https://github.com/NativeScript/ios-runtime/issues/1209

Implemented in {N} CLI with: https://github.com/NativeScript/nativescript-cli/issues/5220

mbektchiev avatar Sep 19 '19 10:09 mbektchiev

Not necessary to be a breaking change. It could be done only if the user wants it.

vmutafov avatar Sep 19 '19 10:09 vmutafov

Implementing this could also allow capability based security of some kind in order to mitigate malicious plugins.

vmutafov avatar Sep 19 '19 10:09 vmutafov

Sure, the app can have the final word. But what happens if some plugin adds such a configuration and the app hasn't?

But you're right, it's not necessary to be a breaking change -- we can still generate all metadata if the app hasn't turned on some switch.

mbektchiev avatar Sep 19 '19 10:09 mbektchiev

How about implementing this feature:

  • to generate metadata for everything (native SDK and native libraries) except specified libraries?
  • the app to have the only word, i.e. no plugin configuration?

vchimev avatar Sep 19 '19 14:09 vchimev

Seems to be too limited in functionality and will require more manual work by everyone who decides to opt for it, as users will have to take into account all their plugins' JS implementation and the underlying native APIs it uses.

mbektchiev avatar Sep 20 '19 07:09 mbektchiev

Config requirements

It seems like it comes down to this:

  • Both plugins and apps can either explicitly state their native API dependencies or leave them unspecified.
  • If both the plugins and app leave those native API dependencies unspecified, then we'll simply have to provide the whole runtime.
  • If one or more plugins leave those native API dependencies unspecified, then we'll need to make a decision based on the app's configuration.
  • We should ideally have a strategy for dealing with multi-purpose plugins that specify more dependencies on native APIs than the user knows they will actually be calling (i.e. because the user might only be using one limited sub-module of the plugin).

Potential approaches

We then have a question of how the app's configuration is interpreted, in the case that it is explicitly given. There are three simple approaches:

  • =: the list describes exactly all the APIs needed, but this will be cumbersome for the user to assemble (as they'd have to take into account all their plugins).
  • &&: the list describes all the APIs that are needed by the app, and will be intersected with those needed by the plugins. Again, this would be cumbersome for the same reasons as before.
  • ||: the list describes all the APIs that are needed by the app, and will be unioned with those needed by the plugins. If any plugin doesn't specify its native API dependencies, then we'd unfortunately have to bundle the whole runtime.

I think the || approach is most attractive, as it entails the least inspection of plugins and the least amount of consideration.

If we additionally allowed some way to override, at app level, the specified native API dependencies of all plugins used by the app, then we'd be able to solve both the issues of multi-purpose plugins and the issues of older plugins that lack explicit native API dependency declarations.

Config file format

For each plugin

So maybe each plugin should have a file, tnsNativeDependencies.js. I'll be using iOS APIs as examples here, because I'm not familiar with Android, unfortunately. Here we'll be focusing on a plugin called nativescript-syntax-highlighter (the name will become relevant in the following section).

Note: I haven't looked too closely at what the exact native dependencies of nativescript-syntax-highlighter should really be, so please just take this as a conceptual example rather than a real-world one.

module.exports = {
    /* The plugin's native API dependencies.
     * These will be used implicitly unless overridden by the app. */
    "__self__": [
        /* Foundation and CoreFoundation will be pretty common,
         * so we may want to agree on a minimal implicit set.
         * But that's a separate discussion. */
        "Foundation",
        "CoreFoundation",
        "UIKit",
        "WebKit"
    ]
};

For the app itself

Apps that don't call native APIs other than via the plugins wouldn't need to specify their own tnsNativeDependencies.js file (a union of all the native API dependencies specified in each plugin would implicitly be taken). But by specifying one at app level, they'd be able to override configs specified by plugins, and detail any native API dependencies used purely by the app.

module.exports = {
    /* The app's native API dependencies.
     * These will be unioned with those of the plugins. */
    "__self__": [
        "AVFoundation"
    ],
    /* Here we override the dependencies specified by a plugin. */
    "nativescript-syntax-highlighter": [
        "Foundation",
        "CoreFoundation",
        "UIKit",
        /* In the case that we know that we're not going
         * to use any of the WebKit-related features  */
        // "WebKit"
    ]
};

Thoughts?

shirakaba avatar Sep 20 '19 10:09 shirakaba