Why programming for the browser needs a different kind of language
authored by claude, rubber stamped by Bryan MacLee TL;DR: JavaScript wasn't built for today's...
Full article excerpt tap to expand
try { if(localStorage) { let currentUser = localStorage.getItem('current_user'); if (currentUser) { currentUser = JSON.parse(currentUser); if (currentUser.id === 3886582) { document.getElementById('article-show-container').classList.add('current-user-is-article-author'); } } } } catch (e) { console.error(e); } Bryan MacLee Posted on Apr 28 Why programming for the browser needs a different kind of language #compiling #javascript #webdev #programming authored by claude, rubber stamped by Bryan MacLee TL;DR: JavaScript wasn't built for today's browser. scrml is. I am part owner of a small trucking outfit based in northeastern Utah, mostly oil and gas. I drive one of the trucks. I also program. Never professionally, but I love solving puzzles. Not an experienced framework developer. I can hobble through React if I HAVE TO. I've spent quite some time thinking about what a language designed for the browser would actually look like. First in my head, then on paper and whiteboards, then through about twenty compiler attempts before the current one started landing. The browser has shape When you sit down to write a browser app, you commit to a specific set of things. Reactive state. A server boundary. SQL. Scoped styles. Forms. WebSocket. Workers. Routing. Authentication. Validation. JavaScript was not designed for any of these. JavaScript was a scripting language for a 1995 page-with-a-form. The browser grew up. The language did not. So the ecosystem grew up around the language instead. React for components. Redux or Zustand for state. React-router for routing. Prisma or Drizzle for SQL. Zod for validation. Styled-components or Tailwind for styling. Socket.IO for sockets. Vite for the build. Each one is a library that retrofits a piece of the browser's shape onto a language that does not model it. The seams between those libraries are where most of the bugs live. The compiler does not own the whole picture, because the language does not model the whole picture. That is the gap. Everything else in this article is what closes when the language does model the picture. Six things a browser-language should own 1. State as a type In most frameworks, state lives in a hook or a binding (useState, ref, createSignal), each with rules you have to follow: call it the same way every render, do not put it in a conditional, follow the dependency-tracking conventions. The rules are not enforced by the language. You learn them by hitting them. What if state were a type? An <input> is already a state. It has a value, it changes over time, the user interacts with it. Make user-defined state work the same way. < Card> declares a state type. <Card> instantiates one. @count is reactive; the compiler tracks reactivity through fn signatures, through match arms, across the server boundary. Errors that frameworks catch at runtime, or never, become compile errors here. There is no conceptual gap between "the input element is a state" and "the user-defined Card is a state." 2. The server boundary as a type-system question In framework land, where-this-runs is your problem to remember. The compiler cannot help. Mark a function server fn and the compiler does the rest. It partitions everything that function touches as server-only, generates the route, generates the fetch stub on the client, and fails compile if you try to read a server-only @var on the client. You stop writing API routes. You stop writing fetch wrappers. You stop having to remember which file runs where.…
This excerpt is published under fair use for community discussion. Read the full article at DEV Community.