From Fedora Project Wiki


Use of swappable -bin packages for managing NodeJS symlinks

Summary

We aim to move away from manual management of /usr/bin/node, /usr/bin/npm, and similar symlinks to leveraging swappable nodejsXX-bin, nodejsXX-npm-bin packages.

Owners

Current status

Detailed Description

This is a part of a larger iteration in a way we package NodeJS for Fedora and RHEL. The other parts are Changes/NodejsNodeModulesPath and Changes/NodeJSMetapackages. This change deals specifically with the management of the non-versioned symlinks in system paths.

Currently, the NodeJS packages (streams) provided in Fedora are all installable in parallel, by virtue of moving any potentially conflicting bits into versioned equivalents and/or versioned directories. For one example of many:

%install
mv %{buildroot}%{_bindir}/node %{buildroot}%{_bindir}/node-%{node_version_major}
...

One of the streams is designed as the "default" one, and that stream then ships manually created non-versioned symlinks to the renamed paths:

%if 0%{nodejs_is_default}
ln -srf %{buildroot}%{_bindir}/node-%{node_version_major} %{buildroot}%{_bindir}/node
...
%endif

By using bin packages, we can iterate on this idea and gain several benefits outlined below.

Feedback

  • Dan Čermák and Vitaly Zaitsev pointed out in the mailing thread that update-alternatives does not really work on immutable systems, such as Silverblue.

    Vitaly then offered an idea to introduce "swappable" packages, such as nodejs22-bin and nodejs24-bin, that would contain the symlinks and could be swappable via dnf swap nodejs22-bin nodejs24-bin. Leveraging weak dependencies and the fact that "If adding the package would lead to an error dnf will by default ignore the dependency" (source), this looks like a viable alternative.

    We'll try to experiment with it in a dedicated COPR and see what we can get working.

    The testing COPR and the corresponding source code branch is now available. We also have a repository for testing scenarios related to this approach; feel free to suggest more of those!

Benefit to Fedora

  1. No matter which stream you install, you'll always have /usr/bin/node and other non-versioned names available. The versioned names will be also present, if you want to be specific in your scripts.
  2. There is no "official Fedora endorsement" on which NodeJS stream should be "best" or "default"; if you as a system administrator have multiple streams installed, the decision of which should be the default is up to you.

The second item will also give us the maintainers greater freedom in introducing new streams and obsoleting the old ones without worrying too much about how to switch the "default" in the middle of the distribution life cycle. This is not a big pain point for Fedora, where the length of the life of a single version matches the length of upstream NodeJS LTO support pretty closely, but becomes much more important in longer-living downstream distributions (e.g. RHEL).

Scope

  • Proposal owners:
    • Port the manual symlink creation and management to -bin packages.
    • Ensure the streams behave consistently and no conflict is introduced.

User Experience

Users will be able to install any number of streams and switch where /usr/bin/node points by using dnf swap feature:

# dnf install nodejs22 nodejs24
Package             Arch   Version                   Repository                                                          Size
Installing:
 nodejs22           x86_64 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives 293.6 KiB
 nodejs24           x86_64 1:24.4.1-8.fc43           copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives 297.7 KiB
Installing dependencies:
 ...
 nodejs22-npm-bin   noarch 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives  12.8 KiB
 ...
Installing weak dependencies:
 nodejs22-bin       noarch 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives 138.8 KiB
 ...
# dnf swap --allowerasing nodejs22-bin nodejs24-bin
Package           Arch   Version          Repository                                                          Size
Removing:
 nodejs22-bin     noarch 2:22.17.1-3.fc43 copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives 138.8 KiB
Removing dependent packages:
 nodejs22-npm-bin noarch 2:22.17.1-3.fc43 copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives  12.8 KiB
Installing:
 nodejs24-bin     noarch 1:24.4.1-8.fc43  copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives 138.8 KiB
Installing dependencies:
 nodejs24-npm-bin noarch 1:24.4.1-8.fc43  copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives  12.8 KiB

Transaction Summary:
 Installing:         2 packages
 Removing:           2 packages

Users will need to take greater care of what their symlinks points to; some of the update scenarios might even result in removing the symlinks altogether. For example, removing a stream from which the current -bin packages originate (including on i.e. Fedora system-upgrade) will not install a replacement automatically:

# dnf install nodejs22 nodejs24
... same result as above
# ls -l /usr/bin/node
lrwxrwxrwx. 1 root root 7 čec 28 02:00 /usr/bin/node -> node-22
# dnf remove nodejs22
Package             Arch   Version                   Repository                                                          Size
Removing:
 nodejs22           x86_64 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives 293.6 KiB
Removing unused dependencies:
 nodejs22-bin       noarch 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives 138.8 KiB
 nodejs22-docs      noarch 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives  48.8 MiB
 nodejs22-full-i18n x86_64 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives  30.4 MiB
 nodejs22-libs      x86_64 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives  79.2 MiB
 nodejs22-npm       noarch 1:10.9.2-2.22.17.1.3.fc43 copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives   9.3 MiB
 nodejs22-npm-bin   noarch 2:22.17.1-3.fc43          copr:copr.fedorainfracloud.org:jstanek:nodejs-bin-alternatives  12.8 KiB

Transaction Summary:
 Removing:           7 packages

# ls -l /usr/bin/node
ls: cannot access '/usr/bin/node': No such file or directory

When using nodejs and/or npm as a build-time dependency, care needs to be taken to specify that the -bin package should be installed as well. The suggested way to do this would be to use BuildRequires: <main package>, <unversioned_path>…; e.g.:

# Do not care which stream will get installed; use metapackage
BuildRequires: nodejs, /usr/bin/node, /usr/bin/npm
# Needs a specific nodejs major version/stream, but wants unversioned commands
BuildRequires: nodejs24, /usr/bin/node, /usr/bin/npm

Dependencies

  • Should not cause any problems to dependant packages.

Contingency Plan

  • Contingency mechanism: Revert back to manual symlink management and go back to the design phase.
  • Contingency deadline: Beta Freeze.
  • Blocks release? We aim to do the rebuilds in Koji side tag and merge it atomically; so NO.


Documentation

Release Notes

The packages nodejs24-bin, nodejs22-bin, and nodejs20-bin, along with their npm counterparts nodejs{24,22,20}-npm-bin are currently available.

Depending on which -bin packages are installed - node and npm commands will be configured to be pointing to different NodeJS versions.

Use # dnf install nodejs24-bin or equivalent to install node command that will run NodeJS v24.x. Use # dnf swap --allowerasing nodejs24-bin nodejs22-bin to change the NodeJS version used.