Spec splitting

2024-12-19

Apparently there was a proposal that wanted to split up the spec into a core part and a ... "other" part. I have feelings on that and I'l share them with you. I kind of stopped following the TC39 closely a while back and only watch it from the side line nowadays so this kind of flew under my radar.

First, the proposal can be found here. I missed it initially but was reminded of it by the OTMT podcast here. My thanks.

My verdict


Let me start of with my vote on this.

I vote ... shrug. I abstain.

It's less about feeling indifferent about it and more that I'm torn about it.

I understand the call for the split. JS has been burdened by a lot of features in the past few years and not all of them have the same kind of traction or implementation difficulty.

Some are very laudable, like optional chaining (?.) and even coalescing (&&). Others less so, like async for of and bigint. I've complained myself multiple times that some parts of the spec are unnecessarily complex and even the best JS dev in your org would have a hard time explaining them.

For engines the burden of implementation is high. The browser war is far from over and JS engines are a big part of it. Both in terms of performance but also spec compliance. Nobody wants to go back to the IE6 era (although arguably history repeats itself anyways and aren't we again in a sort... okay I digress).

This means that whatever the TC39 comes up with, JS engines have to implement it and make it fast. Suck. It. Up. JS devs are spoiled for sure and expect nothing but bare metal perf in our JS apps.

The proposal is an attempt to relieve that burden by moving part of the spec to the tooling world aka userland. There would be a core spec (dubbed "JS0") that describes the JS core primitives and there's a supplemental spec (dubbed JSSugar) that describes all the syntax (and presumably non-syntax stuff) that can be implemented with those primitives. Browser engines would implement the core primitives so that's what the browser and environments like nodejs would give you out of the box. And the tooling space (babel, webpack, typescript, etc) would implement the rest and compile it down to those primitives. For example, a?.b can be implemented as a == null ? undefined : a.b.

In this world, the JS0 becomes more of an assembly language for JS on the web. No no, not WASM.

The split itself I don't care about. That's an implementation detail, a spec implementation detail, and it's kind of irrelevant to the developer (let alone end user) whether the language is defined in one or two massively highly complex docs.

The reasoning... I have a bone to pick with those.

JS Tooling


It's ironic that I'm even writing this. I've been professinally working in the JS tooling space for about 15 years. But it's the next quote that I whole heartedly disagree with.

Quoted from Slide 38 of the prezo:

> Developers have embraced tooling
> Authoring JS is now primarily intermediated by tools

This... is framing it wrong. We haven't "embraced" tooling. It was force fed to us. There is no alternative if you want to use new language features in development. This is the downside of our world due to how the engines are distributed, in particular browsers. JS authors don't get to pick the browser version so they have to support a certain baseline. An ever moving target.

Babel was required because it was the only feasible way to bridge the gap to start using ES6 proper in development. Case in point: we don't use Babel anymore because ES6 is widely available and it only took us 10 years to get there!

And yet, it's still kind of necessary in the React world (jsx). And it's still kind of necessary for the TS world. But again, we haven't embraced it. It's a forced kind of Stockholm syndrome. Yes, we like TS and whatever but omg wouldn't we want to just ditch all of it in favour of running raw JS in the browser? Let them strip the types and parse the jsx and move on.

Instead we get complex stacks that are incompatible with each other (try setting up jest with something other than babel), convoluted workarounds (.js .mjs type=module) and boundless frustration on either side of the very narrow happy path.

Vanilla JS


On the other side, I still do most of my personal projects in vanilla JS. I do like TS but then I'm forced to setup the TS toolchain, which anno 2025 is still annoying as heck (yes yes I know how to do it) and I shy away from it for personal projects. The 'ol "save and f5" routine works fine. (I don't write React so ymmv there)

Because types and jsx aside, you can write regular modern JS these days without the requirement of compilation tools. You can use syntax features from last year in the browser and node. You can use ESM. Everything will work fine.

For production you'll need a compilation step. Bundling, minification, optimization. But that's for production. In big orgs you'll have some kind of toolchain setup regardless because that's the tax for development at scale. But for personal development you only need them for cutting edge and for things not in the spec. And since things like jsx and ts are not "forward compatible" with the languagethey must therefor be compiled out. That's kind of sad.

Note that this whole idea does not apply to infra at scale. Tooling is a mandatory part of keeping your sanity when hundreds or thousands of devs work in the same code base.

Two sides


There's some irony that these tools help us unlock features in our language that we could otherwise not use because our target environment (node, browser, whatever) doesn't support it yet.

These tools definitely help to evolve the language. Test the waters, flesh out a proposed feature, before codifying it into the spec forever.

They also hold back traction for new users because they get overwhelmed with the required setup just to print their name in a browser.

After all this time, I'm convinced JS gained traction because it had an extremely low barrier of entry. You could just write it and it worked. And you could use the browser, which was very likely already on your system anyways. And there was no tool necessary other than some plain text editor.

This is still true today, btw. You can still write websites with HTML, CSS, and JS in plain text editors. Professionally you'd shy away from that for a myriad of reasons. But you don't hafta.

Consider someone who's interested in learning how to build a website. Where do you even start today? Googling for it yields you a million website builders (or sites with top x of website builders, ugh). But no pointers on how to get your browser to display your name with just notepad...

Had browsers shipped with Python it would be Python on top today (uh wait). Google tried to kill JS this way with Dart much later btw (and failed) but at that point the race was already won.

If JS had been burdened with compilation setups back then I don't think it would have had the same traction. Simplicity and lowest barrier of entry wins the race.

Risk of replacement


There's a hidden risk into codifying the spec in a core and sugar spec and forcing users to adopt a compiler of sorts just to write JS: they'll soon realize they can use any language if they have to use compilation steps anyways and stop writing JS entirely.

Now this is already the case today, of course. I've written a game entirely in Rust, using the html5 canvas API and compiling Rust code to WASM.

But by formalizing the requirement for compilation tools just to write JS you simply accelerate the decline of JS development. I'm not saying that's why Google is doing it (but they do have history against them on this, heh, so I wouldn't put it beyond them either). Just that the risk is there.

Is that a bad thing? In itself, no. I mean, do whatever. Right tool for the right job and all that. But for new people trying to learn how to build a website, it's absolutely a regression in DX.

JS in decline


All that said and done I'm a bit pessimistic on the future of JS, regardless of that risk.

On the one hand the new features being introduced into the language don't feel compelling to me. Making it more complex but who really uses or needs them? Is it progress for the sake of progress?

Tooling seems to mostly move away from JS, even when it comes to JS-related tooling. People realised that while you can move fast in JS, JS doesn't move as fast as other languages. So at this point it's more like good for prototyping a certain thing quickly but then building a robust implementation in another language like rust or go. And I can't blame them. The results speak for themselves. And heck, anyone worth their salt knew JS wasn't bare metal speed to begin with. Sure, there are some benchmarks where adding 1+1 can get you near C++ speeds. But as an application on a whole? Nah.

So the weight of JS dev (I don't think I'll ever say TS dev even though I include it) is shifting to general infra and front-end and away from tooling. And that makes sense. That's why I invested in learning Rust. Wasm is here to say. It's all fine.

Here's also where I'm starting to feel indifferent. As the JS tooling space is migrating to other languages, so am I, and so my feelings for how JS is organized are numbing. For insofar they ever mattered. Devs starting with JS are quickly lured to React, a trap which is hard to escape from. And systems programmers won't even bother with JS anyways.

My counter proposal


Rather than focus on splitting the spec and freezing progress for three years, maybe we can focus on codifying the syntax for jsx and ts?

JSX has been used in development for *checks notes* over 11 years! Can we perhaps take the de-facto standard, formalize it, and merge it with whatever E4X standard we already have. I mean, can we put it under a "use jsx" directive and move on with it?

Likewise but in a different way; can we perhaps figure out what TS syntactically needs in order to have it merge with vanilla JS and treat those parts as comments? Again, I for one am fine with a "use ts" or "use types" sort of directive if that helps us to eliminate the requirement of compilation steps just for development.

Would this counter the JS0 proposal? Nah, of course not. But it would eliminate the argument of "JS devs embraced the compile step" and move it under the more realistic "the spec is too complex so let's break it down" (:

I think the end result would benefit traction of JS and keeping the barrier of entry low, if anyone still cares about that. This means onboarding more people into the language and perhaps reversing the decline.

Final thoughts


As far as JS0 goes, engines can always do the split themselves if they aren't already. Build a robust foundation of JS primitives and anything else on top of that in a separate layer that leverages the fundamentals. It's like inception and user space is on the third level! Ok, more like the fifth or sixth level in that analogy.

I think the split, if it comes to pass, will hurt the language overall and indirectly accelerate its decline. But since I'm also moving away from JS, maybe that works out for me since I'm very proficient with the JS0 parts.

It's funny to me because the tool I'm building, Preval, is doing something similar where it breaks down regular JS and compiles high level syntax down to simpler syntax. Just like the ?. example above. My goal there was to simplify writing rules for optimizing the code, with the idea of attempting to reconstruct it back up in a final compilation step. My line of thought is similar to what the JS0 appears to accomplish. So I definitely understand the case being put forward here and am definitely a bit torn on my preference.

If the split does proceed then I'm curious what's gonna end up as core and what ends up as sugar. Time will tell.