http4s/http4s-dom

Create a `http4s-dom-circe` module?

Closed this issue · 7 comments

Why, when we already have http4s-circe from the main repo already crossing for Scala.js?

Because http4s-circe uses Jawn for parsing. This makes sense there, because it enables a pure cross and also supports fancy features like parsing streams etc.

But, a Jawn dependency is bloat and almost definitely less performant. The idea here is to offer a light-weight circe integration module that uses JS-native JSON.parse instead (via circe-parser).

Considerations:

  1. Does Jawn measurably increase JS size or hurt performance? Probably, but would be good to actually verify this.
  2. Does this module even belong in dom? Browsers care most about JS size, but everyone cares about performance, which is also at issue. There's an argument this belongs upstream.

My kneejerk reaction is to think about upstream, but then I'm not sure if that implies a jawn-enabled circe http4s module and then we still have two.

I'm not sure if that implies a jawn-enabled circe http4s module

Not sure I follow, but we already have this upstream in the main repo for both JVM and JS. This issue is more about a JS-only integration that can use platform-specific optimizations (but wouldn't be able to support all the fancy features of the current decoders).

I was thinking if we were trying to make http4s-circe something that pulled in a circe-core that didn't include jawn, how we'd get jawn support. I'm speaking without remembering Circe's modules boundaries, so don't take me too seriously.

Ah, gotcha. Hmm. You're right, we can just pull in circe-core without a Jawn dependency. The current http4s-circe integration is built pretty tightly around Jawn (via http4s-jawn). Relaxing that would certainly be helpful.

I think abstracting this out upstream could get us where we need to be. Scala.js is nice in that (unused) dependencies impose no penalty, because their source is dead-code-eliminated at runtime. So an unused Jawn dependency is no harm.

After working on the docs, I'm tempted to add a circe-parser dependency and implement our own Json encoders/decoders as implicits inside of org.http4s.dom._. It would be very lightweight and battery-packs-included sort of thing.

Edit: another advantage of this is that it could be accomplished with circe 0.14.x, not the 0.15.0-M1 which we need for jawn.js.

The following sourcemap from http4s/http4s#6211 suggests that together jawn and circe-jawn contribute no more than 15 KB. In a world of 120 KB scala-java-time in a minimum 1 MB app, that seems too small too matter.

https://armanbilge.github.io/http4s/6e167bb6f6abe33e47b10d269ec8f40506309042.html

I'm hard-pressed to believe performance is a real issue in the browser, when dealing with reasonably-sized JSON responses. When dealing with lots of JSON I would think jawn's support for streaming parsing is the real win.

Finally, circe-jawn.js will be in circe 0.14.2. So the 0.15.0-M1 issue will go away soon.

Closing, but definitely still interested to hear if anybody legitimately wants this and why :)

One more follow-up: seems that the Jawn parser may outperform the JSON.parse method in many situations. See