Skip to content

Enable NPM as package manager for NativeScript projects #362

Closed
@ligaz

Description

@ligaz

A common use case for NativeScript developers is the ability to install pure JavaScript modules from NPM. Currently this process is cumbersome and it is not straightforward how to require modules that have dependencies due to the nesting of node_modules folders. The end goal is that npm install ... should work out of the box.

Relying on 'standards'

In order to support this a couple of things have to be changed in the CLI. Currently we create a project file .tnsproject that stores the app id (bundle identifier) along with the currently used version of each runtime. We plan to replace this file with package.json that will be compatible with NPM package json format. Here is the structure of a simple app following this rule:

my-app/
|-- app/
|-- |-- App_Resources/
|-- |-- tns_modules/
|-- |-- ...
|-- platforms/
|-- node_modules/
`-- package.json

Preparing for a better world

Assuming we have package.json in the root of the project will allow us to support npm install lodash --save which will install lodash into node_modules folder and save it as dependency in the package.json. All good but how lodash will end-up in the tns_modules folder of the app? This is where the second significant change will come into place. We will extend the prepare command to recursively transform the node_modules folder contents into tns_modules in the native platform project. This transformation should exclude all modules defined in the devDependencies section of the package.json.

Open questions:

What should be the way to add NativeScript specific properties to the project.json?

  • prefixed with tns_ or nativescript_ Example:
{
  "name": "myapp",
  "version": "10.3.1",
  "tns_id": "org.nativescript.myapp",
  "tns_platforms": {
    "ios" : "0.9.2",
    "android" : "0.9.0"
  }
}
  • in a designated nativescript key. Example:
{
  "name": "myapp",
  "version": "10.3.1",
  "nativescript": {
    "id" : "org.nativescript.myapp",
    "platforms": {
        "ios" : "0.9.2",
        "android" : "0.9.0"
    }
  }
}

Should we require NativeScript tailored modules published to NPM to have nativescript as an engine?

Example:

{ "engines" : { "nativescript" : ">=0.9 <0.10" } }

or

{  
  "engines" : { 
    "nativescript-android" : "0.9.0",
    "nativescript-ios" : "0.9.3" 
  }   
}

This will give us a couple of advantages:

  • We can warn (or error) the user if the module is not compatible with currently used runtime versions.
  • (Future) We can implement a Node compatibility layer in the runtimes that will be able to load Node dependent modules from node_modules folder by providing shims for all Node APIs.

Tasks

  • Remove .tnsproject and introduce package.json
  • Move project properties into nativescript key in the package.json
  • Extend prepare to copy the modules from node_modules into platform native project 'tns_modules'
    • Flatten nested dependencies
    • Do not prepare devDependencies.
    • Make sure we do not degrade the performance during prepare when copying the modules. We can consider things like symlinks or broccoli.js kind of infrastructure.
  • Guard the new code with tests
  • Implement an upgrade procedure for the old projects

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions