TipsAndTricks/NPM: Difference between revisions
Henry Bruce (talk | contribs) |
Henry Bruce (talk | contribs) |
||
Line 69: | Line 69: | ||
</pre> | </pre> | ||
== | == NPM Modules Not Registry == | ||
The | The npm fetcher only supports node modules that already exist in the registry. but does not support mouldes in development. This feature is scheduled for development and in the meantime we have a work around. | ||
Let's use [https://software.intel.com/en-us/iot/software/ide/intel-xdk-iot-edition XDK daemon] as an example. | Let's use [https://software.intel.com/en-us/iot/software/ide/intel-xdk-iot-edition XDK daemon] as an example. | ||
Line 78: | Line 78: | ||
* Install it | * Install it | ||
cd xdk-daemon-0.1.3 | cd xdk-daemon-0.1.3 | ||
npm install | npm install --production | ||
* This will create dependencies in node_modules folders. | * This will create dependencies in node_modules folders. Sometimes dependencies are hierarchically installed, but we want a flat installation | ||
* Install flatten-packages | * Install flatten-packages | ||
sudo npm install -g flatten-packages | sudo npm install -g flatten-packages | ||
* Now flatten packages | * Now flatten packages and create tarball | ||
flatten packages . | flatten packages . | ||
tar cvjf node_modules.tar.bz2 node_modules/* | |||
* Now create recipe. The following shows a recipe snippet that does not include package meta-data, licence or tarball checksum details. | |||
** The node_modules tarball you just created must go in the files sub-directory. | |||
** SRC_URI includes the module source code (http://download.xdk.intel.com/iot/xdk-daemon-0.1.3.tar.bz2) and the node_module tarball (file://node_modules.tar.bz2) | |||
** inherit the npm class to do the hard work. | |||
<pre> | |||
RDEPENDS_${PN} = "nodejs bash" | |||
SRC_URI = "http://download.xdk.intel.com/iot/xdk-daemon-0.1.3.tar.bz2 \ | |||
file://node_modules.tar.bz2" | |||
inherit npm | |||
# npm class sets ${S} so we need to override it. This has to be done after 'inherit npm' directive | |||
S = "${WORKDIR}/${PN}-${PV}" | |||
</pre> | |||
== Building & dependencies == | == Building & dependencies == | ||
Revision as of 17:53, 9 August 2016
Background
JavaScript is becoming a leading programming language for IoT due to the popularity of Node.js [1] [2] [3]. However Node.js application packages (or modules as they are typically known) tend to have many dependencies and often are not very descriptive of what versions of these dependencies they require. Node.js modules are managed by a tool called Node Package Manager (NPM) which accesses a module registry to install dependencies. In previous versions of Yocto Node.js module recipes created the package by running npm in the do_compile task that would look something like this
SRC_URI = "https://github.com/gruntjs/grunt-cli.git" do_compile() { # changing the home directory to the working directory, the .npmrc will be created in this directory export HOME=${WORKDIR} # configure cache to be in working directory npm set cache ${WORKDIR}/npm_cache # clear local cache prior to each compile npm cache clear # compile and install node modules in source directory npm --arch=${TARGET_ARCH} --verbose install }
The problem with this approach is that the npm install command triggers download of dependent modules. As web operations are not expected in the do_compile task, proxy variables are not propagated so recipes must be extended to add configuration for handling corporate firewalls.
In Yocto 2.1 an NPM fetcher was added to greatly simplify the packaging of Node.js modules as well as helping you check your licensing requirements.
The fetcher is not yet documented in the bitbake manual [4], so this article will help you get the best out of it.
Creating NPM Recipes
Fetcher Syntax
The new npm fetcher uses the npm scheme, must have the registry as the path (usually registry.npmjs.org, but any registry can be used) and requires a name parameter to specify the module. Assuming recipe name and version match the module, the above recipe snippet could be replaced with the following
SRC_URI = "npm://registry.npmjs.org;name=${PN};version=${PV}"
Dependent Layers
The npm fetcher needs the native nodejs-npm package which is part of meta-oe. You must get the meta-openembdeed later from git://git.openembedded.org/meta-openembedded and add /path/tometa-openembedded/meta-oe to conf/bblayers.conf
Using devtool
Although npm recipes can be created manually, using devtool make the job much easier. Just run the follow for module grunt-cli, version 1.10.
devtool add "npm://registry.npmjs.org;name=grunt-cli;version=1.1.0"
Under the hood devtool runs recipetool create with the same fetch uri. Recipetool downloads each dependency and generates a recipe file. The recipe file is fairly simple but will contain every license that recipetool has found and include it in the LIC_FILES_CHKSUM. Many node modules have unclear licensing so you'll see "unknown" in the LICENSE field. Have a look at the modules not listed.
Recipetool will also create shrinkwrap and lockdown files for your recipe. Shrinkwrap files in npm are used to make sure that the full dependency chain of a node module is the same as the user expected. Many packages don't provide this so we create one on the fly, you can replace it with your own. Lockdown checks that the files recipetool downloaded are the same as the ones your users will download when using your recipe. This simply checks dependencies have not been changed and that your NPM registry is still handing out the same file.
Result will look something like this. Key entries are SRC_URI and inherit npm directive. You will have manually track down the unknown and missing licences, but apart form that recipe should be functional.
LICENSE = "ISC & Unknown & MIT" LIC_FILES_CHKSUM = "file://node_modules/nopt/LICENSE;md5=82703a69f6d7411dde679954c2fd9dca \ file://node_modules/nopt/node_modules/abbrev/LICENSE;md5=82703a69f6d7411dde679954c2fd9dca \ ... file://node_modules/findup-sync/node_modules/glob/nodeLICENSE_${PN}-findup-sync-glob-inflight-wrappy = "ISC" SRC_URI = "npm://registry.npmjs.org;name=grunt-cli;version=${PV}" S = "${WORKDIR}/npmpkg" SUMMARY = "The grunt command line interface" NPM_SHRINKWRAP := "${THISDIR}/${PN}/npm-shrinkwrap.json" NPM_LOCKDOWN := "${THISDIR}/${PN}/lockdown.json" inherit npm LICENSE_${PN}-findup-sync-glob-inflight-once-wrappy = "ISC" LICENSE_${PN}-findup-sync-glob-inflight-once = "ISC" ... LICENSE_${PN} = "MIT"
NPM Modules Not Registry
The npm fetcher only supports node modules that already exist in the registry. but does not support mouldes in development. This feature is scheduled for development and in the meantime we have a work around.
Let's use XDK daemon as an example.
- Make sure you in Yocto build enviorment which native-nodejs-npm installed
- Download module from http://download.xdk.intel.com/iot/xdk-daemon-0.1.3.tar.bz2
- Unpack it
- Install it
cd xdk-daemon-0.1.3 npm install --production
- This will create dependencies in node_modules folders. Sometimes dependencies are hierarchically installed, but we want a flat installation
- Install flatten-packages
sudo npm install -g flatten-packages
- Now flatten packages and create tarball
flatten packages . tar cvjf node_modules.tar.bz2 node_modules/*
- Now create recipe. The following shows a recipe snippet that does not include package meta-data, licence or tarball checksum details.
- The node_modules tarball you just created must go in the files sub-directory.
- SRC_URI includes the module source code (http://download.xdk.intel.com/iot/xdk-daemon-0.1.3.tar.bz2) and the node_module tarball (file://node_modules.tar.bz2)
- inherit the npm class to do the hard work.
RDEPENDS_${PN} = "nodejs bash" SRC_URI = "http://download.xdk.intel.com/iot/xdk-daemon-0.1.3.tar.bz2 \ file://node_modules.tar.bz2" inherit npm # npm class sets ${S} so we need to override it. This has to be done after 'inherit npm' directive S = "${WORKDIR}/${PN}-${PV}"
Building & dependencies
Some stuff here