ESM Migration Phase 3 — dual ESM + CommonJS build#1531
Conversation
There was a problem hiding this comment.
Pull request overview
This PR advances the ESM migration by introducing a dual ESM + CommonJS dist/ build (via tsup) and updating package entrypoints/exports so downstream consumers can use either import or require. It also updates the web client implementation and renames/adjusts in-repo examples/demos to be type: module compliant.
Changes:
- Add
tsupconfiguration to emit dual ESM/CJS bundles into a flatdist/, with special handling for CommonJS “island” generators. - Update
package.jsonentrypoints/exports, publishing workflow, and packing script to publishdist/output and avoid tarball collisions. - Convert examples/demos/docs for
type: modulecompliance and adjustweb/client.jsto avoid top-levelawait.
Reviewed changes
Copilot reviewed 71 out of 75 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| web/client.js | Reworks Node WebSocket loading to avoid top-level await and keep CJS build compatible. |
| tsup.config.js | New dual-build configuration emitting flat dist/ ESM+CJS bundles with island externalization. |
| scripts/npm-pack.sh | Moves packed tarball output to ./pack/ to avoid polluting published dist/. |
| README.md | Updates Quick Start command to new example filename (needs build step alignment). |
| package.json | Points main/module/exports to dist/ dual outputs; adds build:dist and prepack; adds tsup. |
| example/topics/validator/validator-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-service-event-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-serialization-modes-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-raw-message.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-qos-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-observable-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-multiarray-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-message-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-json-utilities-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-example.mjs | Adds an ESM variant using top-level await. |
| example/topics/subscriber/subscription-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/subscriber/subscription-content-filter-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/README.md | Updates documentation references to .cjs examples. |
| example/topics/publisher/publisher-validation-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/publisher/publisher-raw-message.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/publisher/publisher-qos-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/publisher/publisher-multiarray-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/publisher/publisher-message-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/publisher/publisher-example.mjs | Adds an ESM variant using top-level await. |
| example/topics/publisher/publisher-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/topics/publisher/publisher-content-filter-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/timer/timer-example.mjs | Adds an ESM variant (contains minor typos in log strings). |
| example/timer/timer-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/services/service/service-example.mjs | Adds an ESM variant using top-level await. |
| example/services/service/service-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/services/service/getmap-service-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/services/README.md | Updates documentation references to .cjs examples. |
| example/services/client/getmap-client-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/services/client/client-validation-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/services/client/client-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/services/client/async-client-example.mjs | Adds an ESM async/await variant. |
| example/services/client/async-client-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/rosidl/rosidl-parse-srv-example.cjs | New .cjs rosidl parser example using rosidl_parser.cjs. |
| example/rosidl/rosidl-parse-msg-example.cjs | New .cjs rosidl parser example using rosidl_parser.cjs. |
| example/rosidl/rosidl-parse-action-example.cjs | New .cjs rosidl parser example using rosidl_parser.cjs. |
| example/rosidl/README.md | Updates rosidl docs to .cjs filenames and rosidl_parser.cjs. |
| example/rate/README.md | Updates documentation references to .cjs examples. |
| example/rate/rate-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/parameter/README.md | Updates documentation references to .cjs examples. |
| example/parameter/parameter-watcher-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/parameter/parameter-override-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/parameter/parameter-declaration-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/parameter/parameter-client-basic-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/parameter/parameter-client-advanced-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/message-introspector/README.md | Updates documentation references to .cjs examples. |
| example/message-introspector/message-introspector-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/lifecycle/README.md | Updates documentation references to .cjs examples. |
| example/lifecycle/lifecycle-node-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/graph/ros-graph-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/graph/README.md | Updates documentation references to .cjs examples. |
| example/error-handling/README.md | Updates documentation references to .cjs examples. |
| example/error-handling/error-handling-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/actions/README.md | Updates documentation references to .cjs examples. |
| example/actions/action_server/action-server-single-goal-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/actions/action_server/action-server-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/actions/action_server/action-server-defer-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/actions/action_client/action-client-validation-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/actions/action_client/action-client-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| example/actions/action_client/action-client-cancel-example.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| eslint.config.mjs | Updates lint globs to cover .mjs examples and treat .cjs examples as CommonJS. |
| demo/web/typescript/server.ts | Updates comments to match renamed JS demo filenames. |
| demo/web/javascript/static.cjs | Updates comments to match renamed runtime/static filenames. |
| demo/web/javascript/runtime.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| demo/web/javascript/README.md | Updates documentation references to .cjs demo scripts. |
| demo/web/javascript/index.html | Updates instructions to reference .cjs demo scripts. |
| demo/rosocket/server.cjs | Renamed to .cjs and adjusted import style (currently requires ESM entry). |
| demo/rosocket/README.md | Updates documentation references to .cjs demo scripts. |
| .npmignore | Stops ignoring dist/ wholesale; ignores pack artifacts and build-only files. |
| .gitignore | Adds pack/ to ignore list. |
| .github/workflows/npm-publish.yml | Builds dist/ explicitly before packing/publishing; updates publish path to ./pack/*.tgz. |
Comments suppressed due to low confidence (43)
example/topics/publisher/publisher-example.cjs:17
- This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/timer/timer-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
demo/web/javascript/runtime.cjs:21 - This demo script is CommonJS but requires the repo’s ESM entrypoint (
index.js). In Node 20,require()of an ES module throwsERR_REQUIRE_ESM. Require the generated CJS bundle from dist/ (afternpm run build:dist) or switch this script to dynamicimport().
demo/rosocket/server.cjs:30 - This demo script is CommonJS but requires the repo’s ESM entrypoint (
index.js). In Node 20,require()of an ES module throwsERR_REQUIRE_ESM. Require the generated CJS bundle from dist/ (afternpm run build:dist) or switch this script to dynamicimport().
example/topics/validator/validator-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-content-filter-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-service-event-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-serialization-modes-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-raw-message.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-qos-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-observable-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-multiarray-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-message-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/subscriber/subscription-json-utilities-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/publisher/publisher-content-filter-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/publisher/publisher-message-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/publisher/publisher-validation-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/publisher/publisher-raw-message.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/publisher/publisher-qos-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/topics/publisher/publisher-multiarray-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/services/service/service-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/services/service/getmap-service-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. If you want CJS examples to run, load the generated CJS bundle from dist/ (afternpm run build:dist) or convert the example to use dynamicimport().
example/services/client/client-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/services/client/client-validation-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/services/client/getmap-client-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/services/client/async-client-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/actions/action_server/action-server-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/actions/action_server/action-server-defer-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/actions/action_server/action-server-single-goal-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/actions/action_client/action-client-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/actions/action_client/action-client-cancel-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/actions/action_client/action-client-validation-example.cjs:17 - This CommonJS example uses
require('../../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/rate/rate-example.cjs:15 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/parameter/parameter-declaration-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/parameter/parameter-override-example.cjs:13 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/parameter/parameter-client-basic-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/parameter/parameter-client-advanced-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/parameter/parameter-watcher-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/message-introspector/message-introspector-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/lifecycle/lifecycle-node-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/graph/ros-graph-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
example/error-handling/error-handling-example.cjs:17 - This CommonJS example uses
require('../../index.js'), butindex.jsis an ES module (package.jsonhas"type": "module"). In Node 20 this will throwERR_REQUIRE_ESM. For a CJS example, require the built CJS bundle from dist/ (afternpm run build:dist) or switch to dynamicimport().
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const node = rclnodejs.createNode('timer_example_node'); | ||
|
|
||
| const timer = node.createTimer(BigInt(1000000000), () => { | ||
| console.log('One second escaped!'); |
| 'The next call will be ' + timer.timeUntilNextCall() + 'ms later.' | ||
| ); | ||
|
|
||
| console.log('Shuting down...'); |
| 2. Run a publisher example from this checkout. | ||
|
|
||
| ```bash | ||
| node example/topics/publisher/publisher-example.js | ||
| node example/topics/publisher/publisher-example.cjs | ||
| ``` |
Authored source is native ESM; external consumers using
`require('rclnodejs')` need a CommonJS build, so add a tsup dual build.
- tsup.config.js dual-emits ESM + CJS for the four public entries (".",
"./web", "./web/server", "./rosocket") into a flat dist/. The depth-1
layout keeps the native loader's `..`-relative paths to prebuilds/ and
the .node addon (resolved via `bindings`) correct.
- An esbuild plugin externalizes the rosidl_gen/rostsd_gen CommonJS islands
(they resolve their own template and generated/ paths from disk) and
rewrites each specifier relative to dist/ (./rosidl_gen -> ../rosidl_gen).
- A per-format footer hoists a lone `export default` to `module.exports`
so `require('rclnodejs')` returns the value directly (no `.default`).
Needed because engines.node >= 20.20.2 predates require(ESM). Named-only
entries (web/server/rosocket) are left untouched.
- package.json: main -> dist/index.cjs, module -> dist/index.js, and each
entry's exports gains types/import/require/default conditions; ./lib/*
stays ESM-only. Add build:dist (tsup) and prepack scripts; add tsup dep.
- .npmignore: ship dist/ (un-ignore) and exclude tsup.config.js.
- web/client.js: replace a top-level `await import('ws')` (unsupported in
the CJS output) with a lazy async resolver awaited inside connect().
Verified: dual build + require()/import smoke tests + functional
init/pub/sub/shutdown via the CJS bundle + 56 web tests + full mocha
suite (1356 passing) + eslint 0 errors.
The dual ESM + CommonJS build made ./dist the published tsup ESM+CJS build output and un-ignored it for npm. scripts/npm-pack.sh historically dropped its packed .tgz into ./dist, so its extracted `package/` tree and tarball would now ship inside the published package. - npm-pack.sh now writes to ./pack instead of ./dist. - .gitignore: ignore the new pack/ output dir. - .npmignore: belt-and-suspenders excludes for pack/, dist/package/ and dist/*.tgz so stale pack artifacts can never leak into the tarball. Verified: `npm pack --dry-run` ships only the 16 dist bundles + sourcemaps and no pack artifacts.
Add native-ESM versions of a few representative examples to complement the existing CommonJS ones (publisher, subscriber, async service client, service server, timer). They use `import rclnodejs from '../../../index.js'` and top-level `await` instead of `require` + `.then()`. The `.mjs` extension makes them unambiguously ESM regardless of the example directory's package type and avoids colliding with the existing `example/**/*.js` CommonJS eslint glob; `example/**/*.mjs` is registered in the ESM eslint block. Verified: node --check + eslint 0 errors; timer example runs to completion and the pub/sub pair round-trips messages under a sourced ROS 2 env.
Rename all 44 example/**/*.js to .cjs so they run under the package's
"type":"module" setting. Unwrap the default export when requiring the
now-ESM index.js (require('../../index.js').default); rosidl examples that
require the CommonJS rosidl_parser.cjs island are renamed only.
Update eslint CJS glob example/**/*.js -> example/**/*.cjs, the main README
run command, and all example README run-command references to .cjs.
The rosocket and web/javascript demos run straight from a clone (no npm
install) and use CommonJS (require/__dirname), which breaks under the
package's "type":"module". Rename them to .cjs and unwrap the now-ESM
default export when requiring index.js:
- demo/rosocket/server.js -> server.cjs (require('../../index.js').default)
- demo/web/javascript/runtime.js -> runtime.cjs (.default unwrap)
- demo/web/javascript/static.js -> static.cjs (builtins/__dirname only)
Update run-command and prose references in the demo READMEs, index.html,
and the web/typescript server.ts comment. The electron and typescript
demos are standalone projects that consume the published dual package via
its exports map (require + import both supported) and need no changes.
9d07bdc to
bc85a90
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 71 out of 75 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (4)
example/topics/publisher/publisher-example.cjs:17
index.jsis an ES module (package.json has"type": "module"and the file usesexport default). Requiring it from a.cjsexample will throwERR_REQUIRE_ESMin Node 20+, so this example won’t run as written. Useimport()from CommonJS (or point at the built CJS entry indist/) instead.
example/topics/subscriber/subscription-example.cjs:17- This
.cjsexample usesrequire('../../../index.js'), butindex.jsis ESM (export defaultundertype: module). In Node this will throwERR_REQUIRE_ESM, so the example won’t start. Load the module viaimport()(or require the builtdist/index.cjs).
example/topics/subscriber/subscription-service-event-example.cjs:20 index.jsis ESM, sorequire('../../../index.js')from this.cjsscript will throwERR_REQUIRE_ESM. Since this file already has an asyncmain(), the simplest fix is toawait import('../../../index.js')insidemain()and keep everything else the same.
demo/rosocket/server.cjs:31- This demo script is now
.cjs, but it stillrequire()s ESM modules (../../index.jsand../../rosocket/index.jsundertype: module). That will throwERR_REQUIRE_ESMat runtime. Useimport()to load the ESM entrypoints (or change these requires to target the generateddist/*.cjsoutputs).
|
|
||
| ```bash | ||
| node example/topics/publisher/publisher-example.js | ||
| node example/topics/publisher/publisher-example.cjs |
| @@ -52,6 +64,7 @@ | |||
| "lint": "eslint && node ./scripts/cpplint.cjs", | |||
| "test:asan": "bash scripts/run_asan_test.sh", | |||
| "format": "clang-format -i -style=file ./src/*.cpp ./src/*.h && npx --yes prettier --write \"{lib,rosidl_gen,rostsd_gen,rosidl_parser,types,example,test,scripts,benchmark,rostsd_gen}/**/*.{js,cjs,md,ts}\" ./*.{js,md,ts}", | |||
Build system
tsupdual build (tsup.config.js, new): authored source stays native ESM but tsup now emits both formats into a flatdist/—dist/index.{js,cjs},dist/web.{js,cjs},dist/server.{js,cjs},dist/rosocket.{js,cjs}. CJS-island generators (rosidl_gen/*,rostsd_gen/*) are kept external so their__dirname-relative template lookups stay valid; a CJS footer collapses the loneexport defaulttomodule.exportssorequire('rclnodejs')works without.default.package.json:main→./dist/index.cjs, addedmodule→./dist/index.js; everyexportssubpath (.,./web,./web/server,./rosocket) now hasimport/require/defaultconditions pointing at the dualdist/output. Addedbuild:distscript,prepackhook (builds dist before publish), andtsupdevDependency.scripts/npm-pack.sh: pack tarball now goes to./pack/instead of./dist/, so it no longer collides with the tsup-owned, publisheddist/.Source
web/client.js: replaced top-levelawait import('ws')with a lazy_ensureWS()resolver and made_WsLink.connect()async, so the CJS build (no top-level await) works; browsers still useglobalThis.WebSocket.Examples & demos (type:module compliance)
.jsto.cjs(example/**,demo/**) and updated their relative requires..mjsvariants for representative cases (publisher, subscriber, services client/service, timer).example/services/README.mdandexample/topics/README.mdto reference the new file names.Verification
npm run build:dist(tsup) produces both ESM + CJS bundles successfully;npm run lintclean;node --checkpasses on all renamed/new.cjs/.mjsfiles. (Native addon build still requires a sourced ROS environment — unrelated to these changes.)Fix: #1358