question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

This seems like something people have been asking for, so I ported the js client to a pair of libraries, cometd and cometd-transport-jquery. They’re implemented in ES6, transpiled to CommonJS-compliant ES5 and publishable to npm (they use a UMD preamble so they work with AMD and as a final fallback will drop a CometD reference on window). I basically copy-pasted the existing jQuery variant of the implementation, so I’m wondering:

  1. Is this alright, license-wise?
  2. Can I publish them to npm?
  3. Would you prefer to keep it under your own control?

Tangentially, I’m wondering if it would be possible to implement the callback and long-polling transports without using jQuery or another heavyweight library. It seems that the core library has a hard dependency on XHR objects (though not extensive – it could be removed), so using a new API like fetch isn’t currently possible (double tangent: reworking the core CometD API to accept a promise for data instead of an XHR would make it much more pluggable). One could probably create XMLHttpRequests manually, but that was out of scope for this change so I let it alone.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:32 (17 by maintainers)

github_iconTop GitHub Comments

3reactions
seansfkelleycommented, Apr 18, 2016

While I agree that the Javascript community is notoriously fickle and changes its mind quickly, I think waiting for the right solution to emerge while sticking to design patterns that were current when this project was started will end up shooting you in the foot.

I think also you’ve conflated ES6 with other transient technologies, so before I go further, I want to clarify: ES6 is the language standard. It’s not a passing fad in Javascript, it’s not optional, and most browsers already support a considerable amount of the ES6 standard (the rest is coming down the pipe, though it’s generally supported by transpilers like Babel, which is why I transpile in the version I ported). ES6 was a long time in development, and incorporates many lessons from the recent past of Javascript development. Conflating it with (e.g.) Typescript is like conflating Java 8 with Groovy.

ES6 neatly and succinctly addresses many of your concerns, which is why now is a good time to transition the library. I’ve listed out what I think your complaints are, with short explanations for each.

  • Javascript packaging tools are myriad and there is no clear standard (AMD, CommonJS, etc.). Until recently this was true. With the advent of ES6, however, import-export/packaging-consuming syntax and tools have standardized on a derivative of the CommonJS syntax and are now officially built into the language. Rest assured that a full-on ES6 implementation will require the least maintenance going forward on this front.
  • Package managers are myriad and there is no clear standard. This is orthogonal to the problem I’m trying to solve. Given that we have collectively agreed on how to package and consume modules, where those modules come from is less relevant, as long as they adhere to the standard. I have many times consumed modules directly from a Github repo or even (for testing purposes) a local file or CDN, though in general npm is the de facto standard.
  • Promise implementations (and other environment features, like fetch) are myriad and there is no clear standard. ES6 defines a standard implementation for both Promise and fetch. Between those two, you can implement most (all?) of the non-Websockets behavior you need. See also the note on polyfills.
  • Package managers don’t support pluggability/extensibility of the libraries they host. I’m not sure what you mean by this. The onus for modularity is on the module author, not the package manager. I think the registerTransport pattern that already exists in CometD is actually a very reasonable way to handle modularity. You get the pluggable modules from your package manager, and then plug them all together in your code. If you really want to have a configurable implementation that includes all the available bells and whistles (which I discourage), you can have another package that is just that and is implemented by gluing together all the other packages behind some configuration interface.
  • Polyfill frameworks like jQuery are necessary for browser backwards compatibility. Polyfills in general are, yes, but depending on an entire UI framework because no one knows or cares how to actually use XMLHttpRequests natively (and no one does, because they’re awful) is way overkill. The jQuery version of the library merely uses $.ajax; there are several other XHR polyfills available which are considerably smaller and do not require a fork of the library for every UI framework.

A couple of things about the version that I propose above:

  • It’s implemented in ES6. This wasn’t actually that big a change, and it’s quite valuable because I instantly get access to a lot of powerful tooling. It detaches me from any particular packaging implementation or target language version and sets me up for the future.
  • It’s packaged in UMD. I sympathize with the million different import syntaxes. I implemented it in ES6 for forwards-compatibility, but transpile to ES5/UMD to add support for AMD/require/browser globals, with very little actual work on my end. The tooling here is very good.
  • It’s modularized. I split out jQuery because, as mentioned above, it is a very, very heavy dependency to incur for such a small set of behavior. cometd-es6 and cometd-transport-jquery together implement the existing jQuery version almost exactly (minus putting a CometD instance on $), but it also means I can add support for new frameworks with very little code.
  • It’s set up for further, more powerful modularization. After factoring apart these two libraries, I realized that the interface that CometD really wants for transports is a function with a standard set of arguments (probably XHR-like, with some CometD specifics) that supports async and possibly cancellation. In other words, a function that returns a Promise. I imagine a future version of the library where you install something like cometd-core and you can pick and choose the transports you want: cometd-transport-fetch, cometd-transport-websockets, cometd-transport-jquery, etc. There is marginally more setup cost, it’s true, but as alluded to above I’m not a fan of a mysterious and preconfigured instance dumped on $.cometd. You can still do that, if you want.

In general you’re dissatified with the current state of Javascript tooling, but as you can see from the above responses, the language itself is moving to a place where these problems are mitigated or entirely solved. The best way forward, and what I tried to do above, is to lean very heavily on the features of ES6 (seeing as ES6 is The Standard), then use libraries and build tooling to transpile into something that is cross- and backwards-compatible.

Lastly, your example at the end. Yes, you would have to port and publish the extensions somewhere. This is not actually very hard; ES6 is a superset of ES5 so all you’re likely doing, if you publish this to npm, is fiddling with import statements and dependency declarations (which is actually an improvement over the current state, where it just looks for stuff on window). As a bonus, you won’t have to implement tedious framework-specific wrappers around every extension.

One possible way to implement extensions and transports would be to have separate repos for each. If they really are must-haves, it’s not unreasonable to package some nice default ones in the main repo though, leaving any future ones to be implemented in their own repos. You can even publish multiple artifacts from a single repo, which is rare but not unheard of. This may be the proper model for extensions, so that consumers can pick and choose the ones they want. In any case, you won’t have combinatorial numbers of repos for every possible configuration. The configuration is expressed by the declared dependencies and glue code in the consumer, not in the published artifacts.

0reactions
fergardicommented, Jul 21, 2021

About the support of custom transports in Typescript, maybe anybody here can help me out with https://github.com/cometd/cometd/issues/1057?

Read more comments on GitHub >

github_iconTop Results From Across the Web

CommonJS vs. ES modules in Node.js - LogRocket Blog
js has stable support of ES modules. This article won't to cover much on the usage of both module formats, but rather how...
Read more >
CommonJS Notes - RequireJS
There are some CommonJS systems, mainly Node, that allow setting the exported value by assigning the exported value as module.exports. That idiom is...
Read more >
CommonJS modules | Node.js v19.2.0 Documentation
CommonJS modules are the original way to package JavaScript code for Node.js. Node.js also supports the ECMAScript modules standard used by browsers and ......
Read more >
CommonJS (cjs) and Modules (esm): Import compatibility
CommonJS works in Node but does not work in browsers; ESM is supported by all modern browsers and the latest versions of Node,...
Read more >
How the module system, CommonJS & require works
Learn how the Node.js module system & CommonJS works and what does `require` do under the hood.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found