After reading the tutorial at https://vanjs.org/tutorial I was about to open an issue suggesting that they include constants with the SVG and MathML namespace, so that this:
Svelte 5 builds upon these signals / derivations as well, and I guess a bunch of other libraries.
It would be time for them to get together and standardize on a signals library at this point that could be adopted to be a web standard and help interoperability between web components built with different frameworks.
I fully agree with the sentiment, but Svelte does not seem like a natural leader on that front since their version is a JS superset. Already a bit off the map for interoperability.
Solid's attempt feels more promising since it's building on existing native functionality (proxies / getters), and has intuitive, low-footprint usage (just function calls and reference comparisons).
Edit: It seems I'm not up to speed in fact, I hadn't seen Svelte 5 and runes yet, which are not compile-time. I will need to give it another try. I agree in general that signals and signal-based APIs are the future and definitely better than hooks at least, and a single agnostic standard would be good for everyone.
I tried solid and I didn't find it intuitive. Having your data behind proxies introduces more ceremony when splitting / combining props. I felt I was just moving the trade-off React makes when feeding a deps list to hooks to a different location. The proxies also made things hard to debug and you have to be careful about the language features you use with them.
I also have often have smaller deps lists in React's useEffect when wanting to call a callback on the props because of some local state changes. I wouldn't want the effect to fire because the callback changed however. I'm not sure solid even supports that in its createEffect since it is all automatic.
It is really an odd flex. As soon as you need a transpiler, which many modern JS devs are going to want and need for the benefits they provide (Typescript being huge) then using JSX seems a benefit not a problem to solve.
Not needing to use a transpiler is genuinely the thing that excites me most about VanJS.
If you're not a daily JavaScript developer, any form of transpiler / build mechanism seems almost guaranteed to break in the gaps between when you are working on a specific project.
The projects I have that are transpiler/build free are SO MUCH more pleasant for me to intermittently hack on!
Sure, I think that's a very real consideration, but if you're not a daily JS developer, I'm not sure why you'd use a function-call syntax to build up a template either. Something like Alpine.js where you just mark up your server side HTML is a lot easier than putting a bunch of logic into JS to build up a template. Or you could use lit-html or a million other things. This is an idea that's been done a million times but never catches on because it's not better than the alternatives.
1. How easy is it to support loops?
2. How easy is it to compose (defining small components that can be used in larger components)?
3. How easy is it to make the UI reactive to client-side state changes?
You can trim down those notes a lot, like instead of `npm install`, I write a shell script called `script/prepare-env`, instead of various scripts written in a package.json file, I've standardized on `script/start`, `script/build`, and `script/deploy`. Now, no matter the language or package manager used, my workflow is the same.
And you could clean up the GitHub Actions file by just passing the base url to your build script, IE `BASE_URL="/${{ github.event.repository.name }}/" script/build`.
I mean no offense, these notes aren't that extensive, and most of the content is for setting up GitHub Actions / GitHub Pages. npm install / npm run dev / npm run build aren't very esoteric, and can all be documented inside the repo.
I'm actually a little shocked to find out you're a co-creator of Django.
The title of that page is "Serving a JavaScript project built using Vite from GitHub Pages" - that's what those notes are meant to cover, the Vite part is a subset of what I learned in that particular TIL.
Thanks for the BASE_URL environment variable trick - that was very non-obvious to me! I found the documentation for that just now: https://vitejs.dev/guide/env-and-mode
I'm not sure what you mean by "trim down" those notes - if anything I'm always looking for ways to bulk this kind of document up, in order to capture as many of the details of how things work as possible.
JSX does seem to fit that niche better than any other alternative I've tried. It pulls off a rather remarkable trick of avoiding the "uncanny valley" that you usually get from starting with a language and contorting it to do something different.
JSX manages to feel just about right: it's plain-old-HTML when you want it to be, and plain-old-Javascript when you need an out.
Still... I wouldn't mind writing in a truly standard language. You're "really" writing the DOM, and HTML and DOM are this godawful bastardization of a user-interface description language. I'd be slightly less grumpy to have a good DOM-writing library, and deal with its ugliness, rather than mix-and-match the domain-specific-language in with my actual coding language.
I'd written myself a good Java version of this type of thing, and I found it kinda pleasant -- especially since it let me do HTML structure checking via the Java type checking. Typescript is -- God help me -- actually a pretty good language, and I'd be OK with actually writing my user interface structure in it, with the help of a good library.
At least then I'm writing in only one language. That saves me time to go out and learn the godawful bodge of CSS to make it look pretty.
Html 5 has displaced XHTML for decades. And notably, XHTML is not html. <br /> is valid html5, but the trailing slash is meaningless. In JSX, it's required.
JSX is still a dependency with different variants which can cause issues. For example, SolidJS uses JSX but a different variant of JSX, which is a bit more slimmer (innerHTML instead of dangerouslySetInnerHTML).
I experimented with VanJS integrating into Astro. No plugin was needed & getting the SSR HTML is as simple as calling `.render()`.
I wrote a fork of VanJS called relementjs & took this concept further, using `.toString()` instead of render. Now SSR components can be rendered inside a template string.
JSX is redundant, at best. VanJS demonstrated ordinary JavaScript syntax is as good as JSX, if not better. How can something feel sugar-ish if it's actually more verbose than ordinary JS code? Plus, you can't really execute JSX code in browser's developer console.
> How can something feel sugar-ish if it's actually more verbose than ordinary JS code?
I personally find XML much easier to parse than a lot of nested callbacks and I especially like that content is always inside tags, rather than another argument as part of the library's functions. p("Hello, world") is readable enough, but as soon as you start adding html attributes, it becomes less legible to me:
I'm certain some people probably prefer the former over the latter, but I much prefer how JSX/XML reads. I can immediately tell where the content starts and in formatted code, I think it's a lot easier to see visually where things start and end, because of closing tags, instead of just a parentheses.
Feels weird to seem to seriously represent your framework as being about size without including a comparison to preact - the obvious choice for a react developer looking to reduce their footprint.
Preact claims 3kb on their site, and for a 3-4x savings you're going to need to be fairly compelling. I don't mind paying a modest cost for 10x or 100x improvements, but (call it Stockholm syndrome) I like react syntax
Modern reactive UI frameworks get away from maintaining virtual dom. If you want minimalist vdom preact is a great choice. If you'd like to part ways with vdom while keeping jsx, try svelte or solid-js
At least with solid, you can't do `const a = <jsx>` without caveats. Instead you have to store it as `const a = () => <jsx>` (which isn't quite the same, having problems managing state/renders). In React I was optimizing things by storing vdom in state/memo & then interpolating that exact vdom. Or sharing vdom in multiple places. Without vdom you can't throw jsx results around so haphazardly
In solid there's also managing batching updates to reduce rerenders since it eagerly updates dom. It feels like one needs to be more meticulous
The flipside of this is that in React you are paying the cost of active vdom all the time, even when it doesn't pay off by optimizing large batched updates. In Solid, you sometimes have to optimize for some eager updates, true. That will have to be done at some point, though, when the situation calls for it - in either a specific or a general way. It feels natural to shift that optimization to the state layer, and completely eliminate the need for vdom, at the expense of some more thought and active, upfront work. It's a similar tradeoff to spending more time crafting static typing that works well, versus forgoing static types. The tradeoff seems to have good effect too - Solid seems much faster than React both on paper and in practice (my personal experience).
If you know JS (or any other C family language), the syntax is not new.
It's about getting rid of a flawed syntax.
But it'll probably never happen because people are used to it and oblivious to change.
Unless of course if one of the FAANG publishes it as their New FrameWork [tm], then everybody will jump on it, and people that don't are seen as "not modern".
This looks great! I love having the ability to bring existing React/JSX knowledge and be productive with VanJS, while also ditching the transpilation and build tool wildness that has afflicted the ecosystem.
React and JSX were needed in 2013, but with the power and convenience packed into new ES standards and supported by modern browsers, React and JSX should be viewed as bloated polyfills at this point.
It’s really heartening to see things trending back toward single script tags that help you avoid build tools, churn, and dependency hell. To that end, I’m leaning toward htmx for my own project, but what you’ve come up with looks really enticing as well.
Dev: "All the legacy crap is too bloated obnoxious to use and has to much overhead, packaging, and training required to do even smiple things. I'm going to invent a simple lightweight framework from scratch that uses first principles to stay clean."
Time passes framework starts to get used
Random user: "I need to be able to dynamically modify table spacing in Elbonian based languages, whilst allowing for non-standard viewports to dyanmically load partial DOM changes while asynchronously displaying a cat falling over gif animation and the only way to do it in the framework is a bloated hack, any serious enterprise tool needs this, until you get it this is just a toy"
Dev: "Well I guess that makes sense"
Time passes: Hundreds of these random edge cases pop up, og dev is tired, the project gets moved to a committee, usually some drama pops up for several reason that have more to do about posturing than the framework itself
New dev: "This framework is bloated complicated and has too many dependencies and layers of abstraction. After all what purpose on earth is there for me to have to configure whether or not I am using Elbonian derived language encodings that nonsense. I'm going to write my own framework that is lightweight and simple and does what I need it to without all this extra crap"
The library looks nice dx wise but complete lack of any lifecycle hooks is a bummer. I get that minimalism is the core theme but to use any js ui lib that is not explicitly built around the same reactivity model you need to hook into component lifecycle.
If I want to do something like initialize codemirror when my component attaches to dom, I need an event/hook for that. I can't do that solely based on state subscription?
One huge benefit to VanJS is it's simplicity. It is far easier to fork than most other UI component libraries. I did it writing relementjs & rmemo. I encourage others to fork it as well. VanJS is well written. You get a reactive state management library (on the browser side) & a UI renderer in < 150 LoC. Very impressive. I encourage anyone interested to experiment with this. It has been very fruitful for me.
This is cool, though I think a table-stakes example that is missing is how to do a network request. I see the stargazers example but that entire component is awaited, which doesn't mirror the common case of async fetch in response to user input, in which the response is fed to sub-components.
The stargazer example leaves me with questions like- are components both async and non-async? What if the component re-renders due to other state changes, is my network request fired more than once? Do I have a "component coloring" problem where once one subcomponent is async, the entire parent hierarchy has to be?
Im sure there's answers to these questions if I read the docs, but as a curious passer-byer an example mirroring this common ui pattern would answer a lot of questions for me!
Hmm, maybe! Is that the idiomatic way to do async? I was thinking something along the lines of this, which react devs will have written a variation of plenty of times :)
You can do with VanJS in this way as well. `set...` functions in React map to `....val = ...` in VanJS (which I think is more intuitive). But the `Await` component is a good abstraction so that you can specify what to show when the resources are being fetched and what to show when there are errors while fetching the resources.
State management seems a bit counter intuitive at a glance.
I found this statement to be confusing; https://vanjs.org/tutorial#state-val-is-immutableWhile you can update State objects by setting the val property, you should never mutate the underlying object of val itself.
Then beneath is an example of the following;
const text = van.state("VanJS")
...
input({type: "text", value: text, oninput: e => text.val = e.target.value})
Which looks like a mutation - after reading a bit more around it is clearer that .val has a setter; but at a glance it just isn't obvious what is happening which I feel isn't intuitive.
States are mutable whose value can be get/set via the ".val" property. However, the value of the states should be (ideally) an immutable object (or primitives).
It's too late for me. I, like Douglas Crockford, am completely done with JavaScript [1].
HTMX, LiveView, WASM, Dart, ClojureScript, Kotlin, ScalaJS, Dioxus -- There are lots of options folks. We don't need to surrender to the tyranny of JavaScript.
does it mean I have to add many things that are already in vuejs and react if I decide to use vanjs? what vanjs really brings to the table? the existing SPA frameworks are indeed super heavy and anything light and can get daily work done easier will be nice.
after trying react for years I now switched to htmx with a simple backend, until there is a simpler to learn and use SPA(no SSR please) somewhere.
A lot of the heft of React comes from its optimization and reconciliation code. Looking at the examples on the homepage, I’m struggling to see how this framework would efficiently make updates. It seems like it would just need to update the entire component tree down on any update. For any sufficiently large app this becomes very slow very quickly.
VanJS is a lot faster than React: https://vanjs.org/#performance. UI re-rendering in VanJS is kept at the local level as much as possible, which can be achieved without even the need of vdom
The whole “small footprint” thing is always weird to me. I understand that lots of people really want to squeeze efficiency out of every single kb but Im struggling to see where this is helpful. A single image, a single pixel from the marketing team, the actual application code, the page, etc are all going to dwarf the framework.
Coming from living in third world countries where I had to ration data transfer, at speeds ranging equally from 50kbps to 1mbps, I appreciate these efforts greatly
The framework is fundamental for all the rest of the stuff. You transfer it before the majority of the site's content. The faster it arrives, the faster your site is usable. It's also always in use. A badly sized image can cost a few MB, but that's a trivially addressable problem on one page of your site. The framework being 10x its required size is a huge development hurdle to overcome.
Your local mom-n-pop laundry place's website probably doesn't need these types of efficiencies, but if you're running a large ecommerce site, time-to-interactive is an important metric which can cost a lot of money.
I worked at a startup where we reduced the app size by moving to preact from react. The thinking was that it would be beneficial for the low powered mobile users but what we actually saw was increased retention and engagement from all segments as the app was a lot more snappier and didnt chug on every click/tap
I had until very recently a limited data plan for my cell phone in Europe, a plan similar to the one most of my friends have. The only websites that remained reliably accessible once I'd hit the 2Gb limit were HN and i.reddit.com (RIP). 90% of all other websites just time out.
If anything, I wish we could force the marketing team to compress their images better.
Tangetial: I'm not a huge dwm/suckless guy, but I have it on my Raspberry Pi. I love how instantaneous everything feels. Compared to 14-core, 32GB work laptop running Windows which I will forever loathe because how slow and buggy everything is. Same for websites (e.g. HN, libreddit vs reddit etc.)
I think this is why, for me, the future of JS are resumable frameworks like Qwik and Marko 6 – you get all the benefits of NextJS + React (composable UIs, state management, server-side code, etc) with no hydration, which is a big cause of sluggishness with web apps.
Your code only executes when needed, and only that specific chunk of functionality.
> (A rule that can be told by words, is not the rule that should universally apply)
I'm curious where the dev got that translation or if they made it themselves. I have translated it before like "No method that can be explained is universally applicable" but I haven't seen many other translations like that.
Here is the break down of my understanding about the philosophy described in 道德经:
1. There might be some universal rules about the world.
2. There are limitations in human's understanding and human language.
3. For all the rules that can be described in human language (which is subject to the limitations in 2), they can't hold universally.
Putting into the context where the words are cited. Any claim (in human language) about programming like "you should program in this way" is most likely not universally sound.
Of course a philosophy book 2000+ years ago can be interpreted in a different way. Happy to see the elaboration of your understanding "No method that can be explained is universally applicable".
The word dao literally means “road” but by the time of the DDJ, it had come to mean “way of doing something” and “speech that explains how to do something”. Interestingly, in Greek “method” is meta + hodos and hodos means “road” so it’s an etymologically appropriate translation.
道 (dao) means "the way of doing thing" in modern-day Chinese as well. For instance, 王道 means the "the way of governing". 路 is more common for the literal meaning of "road", though 道 has a meaning of both "road" and "waterway" as well.
This looks great. But I replaced my last JavaScript use-case (fading image slideshow) with a css solution today so you will have to make this exciting journey without me.
The author seems to be chasing the small size trophy at any cost...to the point where he's using "var" instead of "const" because it saves a few bytes. Not indicative of someone serious...
The author works as a back end engineer @ Google. I appreciate his "outsider" approach as it is quite a bit simpler than other UI libraries & even reactive state management libraries such as Nanostores. I'm sure if he were in a different development role, his technique would be refined to account for full stack development use cases.
I don't mean to throw any shade on Tao. He is very talented & his approach is beneficially novel. I just don't think he as much experience what life is like as a full stack (or front end) developer as many here.
I forked his work to create relementjs & rmemo. Tao didn't want to support server side reactivity & I heavily use it. Also, Andrey (maintainer of Nanostores) didn't want to add my PR for autosubscriptions due to the complexity cost that would be added to Nanostores...So I wrote my own set of libraries. I hope library simplicity trends more because it is very nice to work with simple libraries.
Tao's approach is sound. He just relies on the DOM to manage the reactive state, so SSR reactivity would require a different approach. I ended up using WeakRef, which is significantly smaller than the approach used by traditional reactive state management libraries.
Why do people dislike JSX? For me the lack of JSX is a negative point. Why would I want to write nested functions everywhere? JSX is HTML on steroids, but it can be just HTML if you wish it.
Is this the main argument? I think the simplest answer is boundaries. Taking into account how much nesting is involved in writing HTML, it's a clear benefit having a named boundary vs a closing parenthesis.
Too much nesting usually signals that you should decompose it to smaller components.
Same as with regular code and functions — overly deep nesting screams bad code.
Honestly, JSX is just a verbose way of calling functions / constructing objects, which is probably OK if it was a language of its own (XML/HTML) — and even then, JSON/YAML won over XML — but makes little sense being embedded in a language which had functions & object literals from the get-go (JS)!
The only reason JSX exists is because it was a cool marketing feature to convert existing PHP/HTML developers to React. And React succeeded mostly because of that. Not because JSX is cool technology-wise (it isn't). But because it hit the right spot in the right time.
<1KB is great and all, but part of the problem is that as soon as you add render blocking JavaScript you're adding a network round trip and JS on the critical path. <1KB might not feel like much, but it's not going to be very different than 10KB. Once you throw in non-trivial product code it doesn't matter at all.
Either you should statically/server generate your site, or you have rich content that needs a client side app and you should pick a framework with rich features.
If you're worried about an extra network round-trip, <1KB is small enough that you could inline the entire framework into the <head> section of your document.
With bundler like esbuild, all JS code, including 3rd party libraries can be bundled into a single file. You don't need an extra round trip for a library.
Is there a reason they compare bundle sizes with for example jquery when every framework ends up importing jquery anyways, since animations are a headache and are often readily available already with jquery?
The fact that you have to manually maintain the binding between states and UI elements and propagate state changes to UI elements is exactly the thing offered by VanJS, or other popular reactive frameworks (despite with a much larger bundle size)
In the example I linked, the VanJS state cannot contain an element reference.
This would lead to unexpected results. So you have to be careful with state management, regardless of whether it's automated or not. There are similar pitfalls, including performance issues, with any state management system, hence dedicated state management solutions like Redux exist to address this.
The core of the argument is that complexity sometimes cannot be avoided. You can quickly wind up with moving this complexity elsewhere, e.g. by pulling in an additional library dependency. This results in having to learn, master and manage additional dependencies. Whether that's fundamentally better than the explicit and straight forward way depends on the scope of the project and its specific requirements. There's no silver bullet in any case and pros and cons with every approach.
Tbh I can't follow your logic here. You mentioned that in VanJS there are things that need to be careful with. But the same is true for other frameworks, even for plain Vanilla JavaScript. Thus what exactly the point that you're trying to make?
Complexity can't be avoided for extremely complex use cases. But that doesn't mean a simple solution that can work for most of the use cases has no value.
Technically, every element that's not in the shadow DOM is a global. But yes, there's plenty of ways to implement this and an argument to had for most of them.
Why do people even reinvent this wheel every few months? Does the <1KB size even matter with modern caches and HTTP2? Does the amount of written lines of code matter when there's modern linters and tooling?
Anyone can build a "reactive" type framework by following tutorials online now, they're super in vogue.
Is my cynicism here warranted, or am I just jaded from 20 years of watching pendulums swing left and right and watching the wheel be reinvented over and over?
You're jaded. Look at this as someone completing the exercise to understand reactive frameworks by implementing a toy implementation. Like when someone implements yet another lisp. Maybe you disagree with it getting to front page, but then don't upvote & move on. There'll always be some amount of front page content someone considers crap & it's best if we don't collectively fill every comment thread disparaging about it
For privacy reasons, resources are no longer cached across origins, so the size does matter (though arguably 1KB more or less makes absolutely no difference on any webpage that has a medium-sized image, especially if you have SSR for the first paint).
But the better reason why these projects exist is for experimentation and iteration. It's not like everyone who uses React will switch to this over the holidays, but maybe in five years some of the ideas in here will become more mainstream, and a future version of React (or a different framework) may adopt them.
Because it's a different threat model: Separating caches per-origin prevents a site A from seeing what resources you requested on site B.
But something like Decentraleyes prevents site A from seeing what resources you requested on site A.
(Or rather, whichever CDN provider site A is using.)
You could have both at the same time, but they are orthogonal. As for why it's not in browsers, assuming good intent, I'd think it's because it requires you to bundle a whole lot of libraries with the browser for it to be useful as a local CDN. If browser vendors decided which JS frameworks are bundled with the download and which ones are not, I'm not sure if that would help decentralisation!
I think your cynicism is warranted for you. Like if you're not looking for a new framework and you are interested in the new, shiny JS refactor, don't bother. I live a happy life, using the same framework and never looking at all the other stuff.
But at one point our big contenders were also shiny and new, and I am glad someone less cynical than me was willing to put them to the test.
The amount of code matters when the lowest-performing Androids on the market have an order of magnitude less single core performance than a modern iOS device. V8 parse times have got much better over the last few years (they used to be a big bottleneck) but you’ve still got major execution cost leading to bad user experience.
The code size is a poor proxy for performance though. React likely has some areas which are much more performant just because of development efforts, even if it's larger. If we want performance, that's the metric that should be public and clear.
>Does the amount of written lines of code matter when there's modern linters and tooling?
So long as JavaScript is interpreted it matters a whole lot on mobile devices.
The amount of code delivered and executed on the device has a huge bearing on performance on lower end devices. Unless you're on some $1000+ phone and arguing from a place of privilege.
Let them reinvent it. You are not required to learn it right now. If it really manages to become widely used you can learn it then. If not well the guy is spending his own time on doing something he likes.
Except... the huge amount is photos and fonts and whatnot. As you can see on the vanjs size, the biggest framework Angular weights 85 kB and it will be cached.
Compared to what Angular also brings in functionality, i don't see size of the framework as an argument anymore.
Consider Hackernews:
hn.js comes with 21,4 kB.
The Y logo on the upper left is a 46,32 kB SVG!
What should i care about 1kB minimal framework or 85kB all-included framework?
Skillset, maintenance burden, compatibility matter.
People feel unsolved problem for them and want a better solution for them individually. As you said “anyone can” so “anyone will”. Just ignore posts like this ;). After 20 years of experience just pay attention to v1 of anything :)
The problem is not size. The problem is installation, configuration, dependencies, transpilation, IDE setup, etc. And here you have the plain old notepad with browser - nothing else...
While literally literally does not mean figuratively, people often use literally to say figuratively with extra emphasis, to the point where some dictionaries literally⁰ list figuratively as a secondary meaning for literally.
Yet another example of language evolving through variations in common use that take hold.
--
[0] literally literally, not figuratively literally
This thing is tight!
Just for fun, I ran their minified code through ChatGPT to see if it could deobfuscate it. It did a pretty good job of guessing sensible variable names for things: https://chat.openai.com/share/9dac0b13-7b24-409a-9cc1-494667...