When packaging nodejs modules, often you face some complexities with the build process. Some common cases will be covered here. If you are new to node packaging, see Javascript/Nodejs/Npm2Deb/Tutorial

You can see these as a video playlist on debian.social.

Using quilt to modify upstream files

Example package to try: magic-string 0.25.7. Replace rollup-plugin-node-resolve with @rollup/plugin-node-rollup in rollup.config.js UsingQuilt .

Creates debian/patches/use-modern-rollup-plugins.patch

--- a/rollup.config.js
+++ b/rollup.config.js
@@ -1,6 +1,6 @@
-import buble from 'rollup-plugin-buble';
-import resolve from 'rollup-plugin-node-resolve';
-import replace from 'rollup-plugin-replace';
+import buble from '@rollup/plugin-buble';
+import resolve from '@rollup/plugin-node-resolve';
+import replace from '@rollup/plugin-replace';
 
 const plugins = [
        buble({ exclude: 'node_modules/**' }),

You can watch this video which shows a demo of these steps.

Configure rollup-plugin-node-resolve to find modules from system

Example package to try: magic-string 0.25.7.

Modify rollup.config.js UsingQuilt

Creates debian/patches/resolve-modules-from-system.patch

--- a/rollup.config.js
+++ b/rollup.config.js
@@ -4,7 +4,7 @@
 
 const plugins = [
        buble({ exclude: 'node_modules/**' }),
-       resolve(),
+       resolve({ moduleDirectories: ['/usr/share/nodejs']}),
        replace({ DEBUG: false })
 ];

You can watch this video which shows a demo of these steps.

Upstream repo does not have required tags

Manually downloading a git commit snapshot when the repo does not have tags matching with npmjs.com releases

We will have manually find a commit corresponding to the release version manually looking at commit messages or take the HEAD revision of master or a specific branch. We will have to add the commit date and hash to the upstream version to be able to update in case there are newer commits.

You can watch this video which shows a demo of these steps.

Exclude generated files from source package

Exclude generated files from the source package (repacking). Javascript/Repacking has detailed steps for how to do it.

You can watch this video which shows a demo of these steps.

Embed simple modules as a component

Embed a simple dependency as a component (ignore, group and checksum options in watch file). You can check Javascript/GroupSourcesTutorial for reading more on this part.

Example package to try: semver and Module to embed: @types/semver

Inside the package directory, run

$ add-node-component @types/semver

This will create or modify debian/{copyright,watch,gbp.conf}

debian/watch will have one more entry,

version=4
opts=\
dversionmangle=auto,\
filenamemangle=s/.*\/v?([\d\.-]+)\.tar\.gz/node-semver-$1.tar.gz/ \
 https://github.com/npm/node-semver/releases .*/archive/v?([\d\.]+).tar.gz

# It is not recommended use npmregistry. Please investigate more.
# Take a look at https://wiki.debian.org/debian/watch/
opts="searchmode=plain,component=types-semver,ctype=nodejs,pgpmode=none" \
 https://registry.npmjs.org/@types/semver https://registry.npmjs.org/@types/semver/-/semver-([\d\.]+)@ARCHIVE_EXT@ ignore

and it will create debian/gbp.conf,

[DEFAULT]
pristine-tar=True
filter=[ '.gitignore', '.travis.yml', '.git*' ]
component=['types-semver']

Now download the component using uscan

$ uscan --verbose -dd
$ dpkg-buildpackage

Now import the new orig.tar if you already have initialized the git repo or import the dsc if you are initializing the git repo now, which will import the component with the main module. You may need to delete upstream/7.3.4 tag if you imported this version earlier.

gbp import-dsc --pristine-tar semver/node-semver_7.3.4-1.dsc

This will install the component to /usr/share/nodejs/semver/node_modules/@types/semver but if we want this to be installed into nodejs root directory /usr/share/nodejs/@types/semver we can create debian/nodejs/root_modules file with

types-semver

Note: Remember to give the name of directory to install in root location and not the module name, pkg-js-tools will read package.json file in the directory and install it in the currest directory.

This will not track the component versions in the package version, for that we have the option to use group or checksum option for the component entry instead of ignore.

Example watch file using group option for the component (we need to also add group option to the main module)

version=4
opts=\
dversionmangle=auto,\
filenamemangle=s/.*\/v?([\d\.-]+)\.tar\.gz/node-semver-$1.tar.gz/ \
 https://github.com/npm/node-semver/releases .*/archive/v?([\d\.]+).tar.gz group

# It is not recommended use npmregistry. Please investigate more.
# Take a look at https://wiki.debian.org/debian/watch/
opts="searchmode=plain,component=types-semver,ctype=nodejs,pgpmode=none" \
 https://registry.npmjs.org/@types/semver https://registry.npmjs.org/@types/semver/-/semver-([\d\.]+)@ARCHIVE_EXT@ group

Now download the orig.tar

$ uscan --verbose -dd
$ gbp import-orig --pristine-tar ../node-semver_7.3.4+~7.3.4.orig.tar.gz

Also edit the version in debian/changelog to 7.3.4+~7.3.4

$ dpkg-buildpackage

This can be quite ugly and long when there are more than one component embedded, so we can use checksum option.

version=4
opts=\
dversionmangle=auto,\
filenamemangle=s/.*\/v?([\d\.-]+)\.tar\.gz/node-semver-$1.tar.gz/ \
 https://github.com/npm/node-semver/releases .*/archive/v?([\d\.]+).tar.gz group

# It is not recommended use npmregistry. Please investigate more.
# Take a look at https://wiki.debian.org/debian/watch/
opts="searchmode=plain,component=types-semver,ctype=nodejs,pgpmode=none" \
 https://registry.npmjs.org/@types/semver https://registry.npmjs.org/@types/semver/-/semver-([\d\.]+)@ARCHIVE_EXT@ checksum

Now download the orig.tar

$ uscan --verbose -dd
$ gbp import-orig --pristine-tar ../node-semver_7.3.4+cs~7.3.4.orig.tar.gz

Also edit the version in debian/changelog to 7.3.4+cs~7.3.4

$ dpkg-buildpackage

You can watch this video which shows a demo of these steps.

finding typescript definitions

Errors like Cannot find module 'assert' or its corresponding type declarations. during build may be resolved by adding build dependency to packages that ships type definitions like node-types-assert which is a virtual package providing type definitions for assert.

Search if there is a assert module or @types/assert module

$ apt-file find assert/package.json
node-assert: /usr/share/nodejs/assert/package.json
node-stream-assert: /usr/lib/nodejs/stream-assert/package.json

We can see there is a module assert.

Next check if the module itself ships a type definition

$ ls /usr/share/nodejs/assert/
assert.js  package.json

We can see this package does not include type definitions.

So check if some other package provides this type definition

$ apt-file find assert.d.ts
nodejs: /usr/share/nodejs/@types/node/assert.d.ts
nodejs: /usr/share/nodejs/@types/node/ts3.3/assert.d.ts

Now we found out nodejs package itself provides type definitions for assert, and see below steps to make these type definitions visible to typescript.

You can watch this video which shows a demo of these steps.

Using extlinks and extcopies options of pkg-js-tools for creating node_modules directory with symlinks or copies of modules installed in /usr/share/nodejs

typescript compiler (tsc) cannot find packages installed in /usr/share/nodejs (or other system directories) so we have to add them to node_modules directory during build. There is an upstream issue, but it has not been fixed yet.

We can create debian/nodejs/extlinks file when using pkg-js-tools or dh-sequence-nodejs in build depends and add the list of modules that should be linked to node_modules directory.

Example package to try: cosmiconfig

Create debian/nodejs/extlinks

@types/node
path-type
@types/parse-json
import-fresh

You can watch this video which shows a demo of these steps.

Avoid self build dependency loop or use alternate build dependencies

Sometimes we don't have the required build tool packaged, but an alternative is available. For example, browserify is not packaged and it has a large number of dependencies and the effort to package it is still not complete. But we already have browserify-lite, rollup and webpack in the archive. So we can look at the build scripts and convert the configuration to use these alternatives.

Most common build steps include, conversion of ES module format to commonjs, transpiling from newer versions of javascript, building typescript etc babel and buble can do transpiling from ES6+ and we use babel to bootstrap buble, even though upstream uses buble itself. See Javascript/Nodejs#Generated_Files for learning more about these build processes and tools.

Simple case of circular self build dependency (babel-plugin-lodash build depends on itself) is broken by using rollup to first convert the code to Commonjs from ES module format and then use the bootstrapped code for transpiling.

You can watch this video which shows a demo of these steps.