Skip to content

Commit b83aa44

Browse files
authored
Raise Node.js Minimum to 20.20.2 (#1478)
This PR raises the minimum supported Node.js version to `20.20.2` and includes the follow-up fixes from PR review. ### What changed - Updated the Node.js minimum across package metadata, CI, and docs. - Moved the Linux ARM64 CI lane to Node `20.20.2`. - Aligned install/prerequisite docs across the main README, build docs, npm README, benchmark docs, Electron demos, TypeScript demos, and JSDoc template. - Reconciled stale Electron demo guidance in: - [electron_demo/manipulator/README.md](electron_demo/manipulator/README.md) - [electron_demo/turtle_tf2/README.md](electron_demo/turtle_tf2/README.md) - Fixed prebuild packaging so Node and Electron binaries are generated and resolved separately: - [package.json](package.json) - [lib/prebuilds.js](lib/prebuilds.js) - [lib/native_loader.js](lib/native_loader.js) - [scripts/install.js](scripts/install.js) - [scripts/tag_prebuilds.js](scripts/tag_prebuilds.js) ### Tests - Added runtime-specific assertions to: - [test/test-native-loader.js](test/test-native-loader.js) - Added a focused helper test file locally: - [test/test-prebuilds.js](test/test-prebuilds.js) ### Validation ```bash npx mocha test-native-loader.js test-prebuilds.js ``` Fix: #1458
1 parent 01847d5 commit b83aa44

19 files changed

Lines changed: 158 additions & 64 deletions

File tree

.github/workflows/linux-arm64-build-and-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
strategy:
2121
fail-fast: false
2222
matrix:
23-
node-version: [16.X]
23+
node-version: [20.20.2]
2424
architecture: [arm64]
2525
ros_distribution:
2626
- humble

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Choose the path that matches how you plan to use rclnodejs:
4242

4343
### Prerequisites
4444

45-
- [Node.js](https://nodejs.org/en/) version >= 16.13.0
45+
- [Node.js](https://nodejs.org/en/) version >= 20.20.2
4646
- [ROS 2 SDK](https://docs.ros.org/en/jazzy/Installation.html)
4747

4848
Before installing, building, or running rclnodejs, source your ROS 2 environment:
@@ -86,7 +86,7 @@ rclnodejs ships with prebuilt native binaries for common Linux configurations si
8686
- **Ubuntu 22.04 (Jammy)** - ROS 2 Humble
8787
- **Ubuntu 24.04 (Noble)** - ROS 2 Jazzy, Kilted
8888
- **Architectures:** x64, arm64
89-
- **Node.js:** >= 16.20.2 (N-API compatible)
89+
- **Node.js:** >= 20.20.2 (N-API compatible)
9090

9191
Installations outside this prebuilt matrix automatically fall back to building from source.
9292

benchmark/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Performance benchmarks for comparing ROS 2 client libraries: C++ (rclcpp), Pytho
55
## Prerequisites
66

77
1. **ROS 2**: Install from [ros.org](https://docs.ros.org/en/jazzy/Installation.html)
8-
2. **Node.js**: v16+ for rclnodejs (from [nodejs.org](https://nodejs.org/))
8+
2. **Node.js**: v20.20.2+ for rclnodejs (from [nodejs.org](https://nodejs.org/))
99
3. **rclnodejs**: Follow [installation guide](https://github.com/RobotWebTools/rclnodejs#installation)
1010
4. **Build Dependencies**: For C++ benchmarks: `sudo apt install libssl-dev cmake build-essential`
1111

docs/BUILDING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Alternatively, you can build ROS 2 from scratch. Please select the platform you
1313
### Install `Node.js`
1414

1515
**Notice:**
16-
`rclnodejs` requires Node.js version >= 16.13.0.
16+
`rclnodejs` requires Node.js version >= 20.20.2.
1717

1818
I install Nodejs from either:
1919

electron_demo/car/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ This demo showcases how to use **rclnodejs** with **Electron** to create an inte
3030
Before running this demo, ensure you have:
3131

3232
1. **ROS2 installed** (Humble, Jazzy, Kilted, or Rolling)
33-
2. **Node.js** (version 16 or higher)
33+
2. **Node.js** (version 20.20.2 or higher)
3434
3. **rclnodejs built** and working
3535

3636
### ROS2 Setup
@@ -288,7 +288,6 @@ Extend the joystick commands by modifying the switch statement in `main.js` and
288288
### Common Issues
289289

290290
1. **"Failed to initialize ROS2" Error**
291-
292291
- Ensure ROS2 is properly sourced before running npm start
293292
- Check that rclnodejs is built correctly
294293

@@ -301,7 +300,6 @@ Extend the joystick commands by modifying the switch statement in `main.js` and
301300
```
302301

303302
3. **Topic Not Appearing**
304-
305303
- Verify ROS2 daemon is running: `ros2 daemon status`
306304
- Check topic list: `ros2 topic list`
307305

electron_demo/manipulator/README.md

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ An interactive Electron application demonstrating a two-joint robotic manipulato
1616

1717
## 📋 Prerequisites
1818

19-
- **Node.js** (>= 16.13.0) - JavaScript runtime
19+
- **Node.js** (>= 20.20.2) - JavaScript runtime
2020
- **ROS 2** (Humble, Jazzy, or newer) - Robot Operating System 2
2121
- **rclnodejs compatible environment** - Linux recommended (tested on Ubuntu/WSL)
2222

@@ -81,7 +81,6 @@ npm start
8181
### Interactive Controls
8282

8383
- **Joint Sliders**: Use the sliders in the control panel to manually adjust joint angles
84-
8584
- **Joint 1 (Base)**: Rotates the entire arm around the vertical axis (±180°)
8685
- **Joint 2 (Elbow)**: Bends the upper arm segment (±135°)
8786

@@ -105,13 +104,11 @@ npm start
105104
The demo includes visual indicators to help identify joint movements:
106105

107106
- **🔴 Red Markers**: Joint 1 (Base rotation)
108-
109107
- Red ring around the base joint
110108
- Red arrow showing rotation direction
111109
- "Joint1" text label
112110

113111
- **🟢 Green Markers**: Joint 2 (Elbow)
114-
115112
- Green ring around the elbow joint
116113
- Green arrow showing rotation direction
117114
- "Joint2" text label
@@ -285,10 +282,10 @@ manipulator/
285282

286283
### Key Dependencies
287284

288-
- **electron**: `^31.7.7` - Desktop application framework
289-
- **rclnodejs**: `^1.5.1` - ROS2 JavaScript client library (latest compatible)
290-
- **@electron/rebuild**: `^3.7.2` - Native module rebuilding tool
291-
- **three.js**: `r128` - 3D graphics library (loaded via CDN)
285+
- **electron**: `^40.1.0` - Desktop application framework
286+
- **rclnodejs**: `^1.8.1` - ROS2 JavaScript client library
287+
- **@electron/rebuild**: `^4.0.3` - Native module rebuilding tool
288+
- **three**: `^0.182.0` - 3D graphics library
292289

293290
### Debugging
294291

@@ -308,14 +305,13 @@ manipulator/
308305
npm start
309306
```
310307

311-
2. **Build errors with latest Electron**
308+
2. **Build errors with Electron**
312309

313-
- This demo uses Electron 31.7.7 for rclnodejs compatibility
314-
- Electron 38+ requires C++20, which rclnodejs doesn't support yet
315-
- The current versions are tested and stable
310+
- This demo currently uses Electron 40.1.0
311+
- If you change Electron or other native-module dependencies, rerun `npm run rebuild`
312+
- The versions recorded in `package.json` and `package-lock.json` are the tested baseline for this demo
316313

317314
3. **No ROS2 messages received**
318-
319315
- Check if ROS2 daemon is running: `ros2 daemon start`
320316
- Verify topic exists: `ros2 topic list`
321317
- Check message flow: `ros2 topic echo /joint_states`

electron_demo/topics/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ A minimal Electron application demonstrating basic ROS2 topic communication usin
2121

2222
## 📋 Prerequisites
2323

24-
- **Node.js** (>= 16.13.0) - JavaScript runtime
24+
- **Node.js** (>= 20.20.2) - JavaScript runtime
2525
- **ROS 2** (Humble, Jazzy, or newer) - Robot Operating System 2
2626
- **rclnodejs compatible environment** - Linux recommended (tested on Ubuntu/WSL)
2727

electron_demo/turtle_tf2/README.md

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ The turtle_tf2 demo showcases:
5151
### System Requirements
5252

5353
- **ROS2**: Humble, Iron, or Rolling distribution
54-
- **Node.js**: Version 18 or higher (for compatibility with latest Electron)
54+
- **Node.js**: Version 20.20.2 or higher
5555
- **turtlesim**: ROS2 turtle simulation package
5656
- **Electron**: For desktop application framework
5757

@@ -317,46 +317,39 @@ You can observe the following behavior by:
317317
### Common Issues
318318

319319
1. **"Cannot connect to ROS2" or "librcl.so: cannot open shared object file"**
320-
321320
- Ensure ROS2 is sourced: `source /opt/ros/$ROS_DISTRO/setup.bash`
322321
- **Critical**: Source ROS2 in the SAME terminal where you run `npm start`
323322
- Check if ROS2 daemon is running: `ros2 daemon status`
324323
- Verify ROS2 installation: `ros2 --version`
325324

326325
2. **"Turtlesim not responding" or "Failed to spawn turtle2"**
327-
328326
- Verify turtlesim is running: `ros2 run turtlesim turtlesim_node`
329327
- Check available topics: `ros2 topic list`
330328
- Ensure spawn service is available: `ros2 service list | grep spawn`
331329
- Try restarting turtlesim_node if spawn calls fail
332330

333331
3. **"No transforms detected"**
334-
335332
- Ensure demo is started: Click "Start Demo" button
336333
- Check TF2 tree: `ros2 run tf2_tools view_frames`
337334

338335
4. **"Dynamic frame not visible when toggling"**
339-
340336
- **Check if the demo is started**: Click "Start Demo" button first to initialize all broadcasters
341337
- **Look for an orange sphere near coordinates (2,3)**: The dynamic frame appears as an orange sphere orbiting around the red static frame
342338
- **Wait for circular motion**: The dynamic frame moves in a 2-unit radius circle, taking about 6 seconds for a full rotation
343339
- **The orange sphere is now bigger**: The dynamic frame has been made 3x larger for better visibility
344340
- **Check the transform list**: The dynamic frame should appear in the left panel's transform list with changing coordinates around (2±2, 3±2, 0)
345341

346342
5. **"3D visualization not loading"**
347-
348343
- Check browser console for WebGL errors
349344
- Ensure hardware acceleration is enabled
350345
- Try restarting the Electron application
351346

352347
6. **"electron: not found" or native module errors**
353-
354348
- Make sure you ran `npm run rebuild` after `npm install`
355-
- Ensure Node.js version is compatible (18 or higher)
349+
- Ensure Node.js version is compatible (20.20.2 or higher)
356350
- Try deleting `node_modules` and running `npm install && npm run rebuild` again
357351

358352
7. **"THREE is not defined" or script loading errors**
359-
360353
- Ensure Three.js is properly installed: `npm install three@0.155.0`
361354
- Check that `node_modules/three/build/three.min.js` exists
362355
- If issues persist, try reinstalling: `rm -rf node_modules && npm install && npm run rebuild`

lib/native_loader.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const { execSync } = require('child_process');
2020
const { NativeError } = require('./errors.js');
2121
const bindings = require('bindings');
2222
const debug = require('debug')('rclnodejs');
23+
const {
24+
detectPrebuildRuntime,
25+
getTaggedPrebuildFilename,
26+
} = require('./prebuilds');
2327
const { detectUbuntuCodename } = require('./utils');
2428

2529
let nativeModule = null;
@@ -35,6 +39,7 @@ function customFallbackLoader() {
3539

3640
const rosDistro = process.env.ROS_DISTRO;
3741
const arch = process.arch;
42+
const runtime = detectPrebuildRuntime();
3843
const ubuntuCodename = detectUbuntuCodename();
3944

4045
// Require all three components for exact match
@@ -58,16 +63,22 @@ function customFallbackLoader() {
5863
}
5964

6065
try {
61-
// Look for exact match binary: {ros_distro}-{ubuntu_codename}-{arch}-rclnodejs.node
62-
const exactMatchFilename = `${rosDistro}-${ubuntuCodename}-${arch}-rclnodejs.node`;
63-
const exactMatchPath = path.join(prebuildDir, exactMatchFilename);
64-
65-
if (fs.existsSync(exactMatchPath)) {
66-
debug(`Found exact match binary: ${exactMatchFilename}`);
67-
return require(exactMatchPath);
66+
const candidate = getTaggedPrebuildFilename({
67+
rosDistro,
68+
ubuntuCodename,
69+
arch,
70+
runtime,
71+
});
72+
const candidatePath = path.join(prebuildDir, candidate);
73+
74+
if (fs.existsSync(candidatePath)) {
75+
debug(`Found ${runtime} prebuilt binary: ${candidate}`);
76+
return require(candidatePath);
6877
}
6978

70-
debug(`No exact match found for: ${exactMatchFilename}`);
79+
debug(
80+
`No matching ${runtime} prebuilt binary found for ${rosDistro}-${ubuntuCodename}-${arch}`
81+
);
7182
return null;
7283
} catch (e) {
7384
debug('Error in simplified prebuilt loader:', e.message);
@@ -110,10 +121,11 @@ function loadNativeAddon() {
110121
}
111122

112123
const rosDistro = process.env.ROS_DISTRO;
124+
const runtime = detectPrebuildRuntime();
113125
const ubuntuCodename = detectUbuntuCodename();
114126

115127
debug(
116-
`Platform: ${process.platform}, Arch: ${process.arch}, Ubuntu: ${ubuntuCodename || 'unknown'}, ROS: ${rosDistro || 'unknown'}`
128+
`Platform: ${process.platform}, Arch: ${process.arch}, Runtime: ${runtime}, Ubuntu: ${ubuntuCodename || 'unknown'}, ROS: ${rosDistro || 'unknown'}`
117129
);
118130

119131
// Prebuilt binaries are only supported on Linux (Ubuntu)

lib/prebuilds.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2026, The Robot Web Tools Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
const PREBUILD_PACKAGE_NAME = 'rclnodejs';
18+
const SUPPORTED_PREBUILD_RUNTIMES = new Set(['node', 'electron']);
19+
20+
function detectPrebuildRuntime() {
21+
if (process.env.npm_config_runtime === 'electron') {
22+
return 'electron';
23+
}
24+
25+
return process.versions.electron ? 'electron' : 'node';
26+
}
27+
28+
function getTaggedPrebuildFilename({
29+
rosDistro,
30+
ubuntuCodename,
31+
arch,
32+
runtime,
33+
}) {
34+
return `${rosDistro}-${ubuntuCodename}-${arch}-${runtime}-${PREBUILD_PACKAGE_NAME}.node`;
35+
}
36+
37+
function getRuntimeFromGeneratedPrebuild(fileName) {
38+
const runtime = fileName.split('.')[0];
39+
return SUPPORTED_PREBUILD_RUNTIMES.has(runtime) ? runtime : null;
40+
}
41+
42+
module.exports = {
43+
detectPrebuildRuntime,
44+
getRuntimeFromGeneratedPrebuild,
45+
getTaggedPrebuildFilename,
46+
PREBUILD_PACKAGE_NAME,
47+
};

0 commit comments

Comments
 (0)