Description
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_
ornativescript_
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 introducepackage.json
- Move project properties into
nativescript
key in thepackage.json
- Extend
prepare
to copy the modules fromnode_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