-
Notifications
You must be signed in to change notification settings - Fork 382
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] convert to ES Module format #475
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like these changes. I've been thinking about starting this myself, but never got the time to do it
|
||
module.exports = ROSLIB; | ||
export * from './core/index.js'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to hardcode .js
for all imports? Is that mandatory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is mandatory by default in Node.js ESM, and very useful in browser ESM when using common types of web servers.
Webpack 5 now requires it by default too, to be compatible with official ESM spec and (most) browser applications (more on "most" below).
Some tools have historically automatically appended the extensions when performing lookup, but that has always been non-standard in the spec despite how standard it has been in build tooling.
The ES Module spec doesn't provide any sort of specification on file extensions, it only specifies that import specifiers are URLs, and the meaning of a URL depends on the server that receives that URL during a request.
In a browser, if your site is served with a regular average static file server, if you try to import './core/index'
the browser will try to fetch
the file 'current-file-folder/core/index'
and not 'current-file-folder/core/index.js'
(because to a URL the file extension has no particular meaning). Because of this, you'd need one of two options to make it work in most web apps:
- a build step that adds the
.js
extensions to the source code, thus a regular static server (which is what most web apps have) will have no problem looking up the files - or use a special static server that automatically appends
.js
when performing file lookup that way source files do not need to have.js
extensions
The vast majority of static file servers do not append .js
extensions, and adding extra build steps is less desirable than not, so as you may now imagine writing .js
extensions in the source files is the simplest way to be the most compatible everywhere.
…tput with Rollup instead of Browserify TODO: Some shims for Node.js were disabled to get this initially building for the browser.
I just pushed an update that completes initial ESM format, and builds the output in three formats: ESM, CJS, and UMD. The The new The new
I haven't done any testing yet (adde TODOs to the OP). This change should be considered a breaking change (because for example someone on an older version of Node without ESM will otherwise experience a break on their next |
var WorkerSocket = require('../util/workerSocket'); | ||
var socketAdapter = require('./SocketAdapter.js'); | ||
import WebSocket from 'ws'; | ||
// import {WorkerSocket} from '../util/workerSocket.js'; // TODO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO I disabled some shims to get it to compile for browsers first. These need to be re-shimmed using Rollup.
Also another question I have is, is WorkerSocket actually useful? Has there been performance gains from this? I'm initially skeptical because fetching from network is a non-blocking operation. Does the data handling (from the browser engine, before finally passing that data to JS) have a big cost that the worker is putting on a separate thread?
Is there a benchmark somewhere? (I'm generally weary of complexity unless it really helps)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think (but I'm not sure) that the CPU heavy work is decompressing the messages. Suppose you are sending a pointcloud with png based message compression. This work will then happen in a worker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be good, but unless I overlooked it, it seems to me that only the WebSocket network requests run in the worker, and it passes the data back to the main thread to do whatever with it (like decompress the PNG). I don't see the decompressPng.js
file being imported in the worker, I think I see it only postMessage
ing data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mvollrath pointed out in issue 382 that #317 is why we need WebSocket in a worker.
@@ -4,7 +4,9 @@ | |||
"description": "The standard ROS Javascript Library", | |||
"version": "1.1.0", | |||
"license": "BSD-2-Clause", | |||
"type": "module", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the main breaking change (major version bump)
@trusktr already thanks for your efforts. Could you please enable GH actions for your repo. At the moment we only run on pushes, no PRs. But I think we should revert that. |
As far as I know, forked repositories automatically inherit GitHub Actions from their upstream repos (because they inherit the EDIT: Ah, I see there's also the option to enable them for my fork. |
Alriiiiiight, tests are running (https://github.com/trusktr/roslibjs/runs/3606731719?check_suite_focus=true). Tomorrow is update-from-jshint-to-eslint day! It'll be nice to have the same tooling setup in both roslib and ros3d. |
eslint is working, build is working (but the output is not tested yet). I got rid of gruntify-eslint, and tried grunt-eslint but didn't use it; both were getting in the way so I simply used |
I think the idea of being compatible with native browser ESM will have to wait, but at least the code will be essentially ES format with the import/export syntax, while the output |
I would advise to keep the changes focussed on one topic as this makes it easier to review. Please create additional PRs for aditional topics (such as changing and fixing linting) |
That's what I thought initially, but the new syntax broke After putting ESLint into place, there were very minimal code changes (just some missing semicolons, and a few unedfined vars, but all else stayed the same due to the lax rules that came from the ros3d repo). I also thought about code formatting (f.e. with Prettier), but then that would cause changes everywhere and thus any change in develop unnecessarily conflict with this PR, so I definitely held off on that idea. I think it would be nice to do that later if you all are interested in that. |
I have mocha tests passing locally on my end now, just need a little more work on the karma side (this time shimming |
|
||
/** | ||
* Message objects are used for publishing and subscribing to and from topics. | ||
* | ||
* @constructor | ||
* @param values - object matching the fields defined in the .msg definition file | ||
*/ | ||
function Message(values) { | ||
export function Message(values) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we can see in this file and others for example, even with the ESLint update, the main source code changes are the import statements, not much else changed.
package.json
Outdated
"time-grunt": "^2.0.0" | ||
}, | ||
"dependencies": { | ||
"cbor-js": "^0.1.0", | ||
"eventemitter2": "^6.4.0", | ||
"object-assign": "^4.0.0", | ||
"pngparse": "^2.0.0", | ||
"socket.io": "^4.0.0", | ||
"socket.io": "trusktr/socket.io#bf4bd150cff3c043c1f60ddf347e1b3ef0f1339a", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not ideal (see socketio/socket.io#4100). The alternative would be to update the socket.io
import sites to import from a local file that shims the missing default function ((srv, opts) => new Server(srv, opts);
) in Node.js, but in the browser just uses the io
global.
- TODO Make the custom shim file for socket.io so as not to have a custom version in package.json
src/util/shim/socket.io.js
Outdated
|
||
function thro() { | ||
throw new Error('transportLibrary "socket.io" is not supported in browsers. Set the `transportLibrary` option to "socket.io" only if you are use roslib in an environment like Node.js or Electron.') | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is totally wrong, I didn't realize socket.io works in a browser too.
- TODO Update this so that it exports the global stuff from a global
io
variable from the global-script-tag version of socket.io.
Alrighty, the base |
// Installs cbor-js in a global CBOR variable so that our shim/cbor.js shim picks it up. | ||
'node_modules/cbor-js/cbor.js', | ||
|
||
{pattern: 'test/*.test.js', type: 'module'}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type: 'module'
makes the scripts be loaded via native browser <script type="module">
, and thus the passing tests are exercising the new roslib.esm.js
output file in browser ESM.
Gruntfile.cjs
Outdated
}, | ||
karma: { | ||
options: { | ||
singleRun: true, | ||
browsers: process.env.CI ? ['FirefoxHeadless'] : ['Firefox'] | ||
browsers: process.env.CI ? ['ChromeHeadless'] : ['Chrome'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I switched to Chrome because I was having issues getting the importmap
polyfill working in Firefox:
- SyntaxError: import not found, and no hint as to which file this happens in. guybedford/es-module-shims#186
- request: clarity on installation in the README guybedford/es-module-shims#187
I decided to just get this all working natively first, then we can polyfill importmap
in Firefox later if we still want to. But MS Edge is now built on Chromium, so at least the tests currently cover a large user base.
…e-lock.json is not useful for libraries (it does not get published with libraries), and having it reduces chances of us catching (during development or on CI) breaks in our library due to accidental in-range breaking changes in dependencies
179e506
to
d3799a5
Compare
* develop: Bump mocha from 9.1.1 to 9.1.2 (RobotWebTools#480)
908bee6
to
eedbe41
Compare
1c5a6b9
to
42d6590
Compare
@MatthijsBurgh @Rayman I'm getting
in the GitHub Action: https://github.com/trusktr/roslibjs/runs/3726509544?check_suite_focus=true This doesn't seem to be related to my changes, as (I think) I have not touched anything related to the Docker ROS setup. I think that part should just work. Any idea? Sidenote, it says |
This allows people to install the package from a git repo (f.e. `npm install roslib@github-username/roslibjs`). by performing the `build` process in the `prepare` script. `prepare` is not only is executed before the `publish` script during publish (so that case is still satisfied), but `prepare` is also executed by `npm` during the `install` process. During `npm install` `devDependencies` are installed in a temporary folder, so those dependencies are even available to the `prepare` script. The end result is that someone can fork the repo, and easily install it, without having to publish the package under a new name, and without having to build and commit build artifacts into the repo (this is why the build artifacts were recently added to `.gitignore` in this repo a few commits back). People who rely on global variable script tags can still use URLs like `https://unpkg.com/browse/roslib@1.1.0/build/roslib.js` in their script tags src attributes, or just download such files to the app locally.
@trusktr what is the status of this? I really appreciate your work and would like to merge this when ready. |
…#475) Bumps [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/HEAD/packages/node-resolve) from 13.0.6 to 13.1.1. - [Release notes](https://github.com/rollup/plugins/releases) - [Changelog](https://github.com/rollup/plugins/blob/master/packages/node-resolve/CHANGELOG.md) - [Commits](https://github.com/rollup/plugins/commits/node-resolve-v13.1.1/packages/node-resolve) --- updated-dependencies: - dependency-name: "@rollup/plugin-node-resolve" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Public Changes
None
Description
Converted to ES Modules (still ES5 classes though)
I'm doing this so that ros3d will be as close to fully ESM-compliant as possible (related PR in ros3d to convert to
class
syntax: RobotWebTools/ros3djs#438).We may be able to complete that ros3d PR without this one (the source won't be as ESM-compatible, but the build output will be). We can complete both of these PRs without being 100% native ESM-compatible, but at least a lot closer (replacing all dependencies with ESM-ready versions would be the biggest step needed).
This is part of my longer term modernizing goal which includes the following in no particular order:
TODO
bson
in browsers