Nue.js: Rethinking Reactivity
nuejs.org
nuejs.org
- It re-renders on click
- It mutates pop/push/... to observe arrays
- Otherwise, you have to manually call `update()`
IMO, don't touch this. All of this has been tried before. It also looks like lists are unkeyed. If you receive another list from the server, you have to do the diffing yourself.
It's disappointing that a framework proclaiming to solve all issues of frontend dev, while evidently understanding none of them, will go uncriticised by HN.
This becomes a frequent issue in any app at scale.
If your app is at a small enough scale that it doesn't run into this issue, I would not recommend using a framework: just use vanillajs &/or some modular utility components.
If you're working on a small app & want to do it in a framework because you anticipate scale, use one with key support.
It's a common theme in benchmarking apps though, which will ultimately be the main reason for adding the key support.
I do.
You've now disqualified this entire framework over a single issue, number of items in a list.
Saying that you don't use lists, isn't helping.
1) In general, in the open-source community, there's a LOT of JS frameworks and many of them have caused developer frustration. This has lead to people being generally more skeptical of ANY new framework, just because there's so many & its considered a saturated space, so critique will be more strict.
2) With JS taking over as the "everything language", there's also some general backlash against JS itself.
3) On HN, this is even more pronounced for some reason.
However, apart from the above, most of the negative comments seem to just be direct replies to certain claims you've made on HN (keys unnecessary & the ES6 DSL): there aren't as many negative comments on the actual submitted website. Personally I quite like it - I particularly love the narrative history lesson & to-the-point inline examples; you're a great communicator. As for thte library, there's elegance in simplicity, & while the framework may not be practical at the moment for some applications, there's still value in using software that is essential grokkable.
Having said that: they key-optimization thing will be implemented. The more frequent issues get a higher priority. Maybe it's this one.
The page took about 2-3 seconds to load (mostly downloading the json data to render the page), but once it loaded, it rendered and more importantly, updated very quickly as new data would roll in. If I had to re-render the entire dom every time there was an update, the page would have been unusable.
It feels like you can't see past your personal use case. You're trying to convince HN that your framework is better than the top 4 projects out there and HN is pushing back and saying... umm... no.
I just do a replacement of the data retrieved from the server, and it all magically works because the ID's don't change.
I'm not sure this is correct. Almost all apps that I write that display live data are built by replacing the whole client-side array with updated server-side array data, and the other commenters seems to work similarly. With your current approach I'd have to write a complete diffing logic to modify the array in-place locally, especially if I don't want child components to be re-mounted.
This has big architectural implications, and it worries me a bit that you only see it as relevant for benchmarks.
Am I correctly reading that you just throw away and re-render the entire DOM?
In knockout (with typescript annotations), the equivalent would be:
let count = Knockout.Observable<number>(0);
And it's then much clearer when you want to access the value of the observable with count() or update it with count(1234) or count(x => x+1 ).( I may have hallucinated the ability to pass a function to the observable ).
The ceremony and huge verbose architecture astronaut frameworks has been tried before. But the people on this enterprisey very professional corporate busywork hype train are probably too inexperienced to rember the SOAPs and J2EEs and Enterprise Java Beans and dependency injection frameworks and Boosts to understand what drag they are to development and software quality.
It'll blow over again in a few years but it's quite sad that the same mistakes have to be repeated.
Thank you for Nue and bringing much needed simplicity and elegance to frontend dev! I'll be sure to at least try out Nue for the next frontend project that could benefit from a framework.
If you consider keyed lists and reactivity mechanisms to be "enterprisey very professional corporate busywork", then I don't know what to say to you.
Says the comment at the top of the thread criticizing the project.
Having just count=0 is stupid and you will learn it the same way as Svelte did. Comparing it like that when they explain all the issues in Svelte 5 is even more dishonest. Any variable can be state and/or be reactive and they arent marked? GL with that. You need to manually call update after fetching data, why?
I obviously disagree. This is not only compact, but also standards- based. It's an ES6 variable. I don't expect Nue to change here, like ever. Svelte internals are quite different.
Signals w/ getter/setter are incredibly nice for this.
I love your attitude. This library is not for me right now but I appreciate the pioneering. React also got a lot of hate in the beginning ("re-render on every change is insane"), people forget. Good luck!
I don't know if you've ever had spaghetti, because the ingredients _are_ meant to be mixed together. Maybe you were looking for another analogy?
Speaking of which, how do you interface with global variables in that case? Say I want to instantiate a global variable when the component is created, how do I do that?
Functional components on their own are not distinguishable from a good old Javascript function. I guess the presence of JSX and/or hooks give it away. I'd say it's half true that glancing at a random .js file it might not be immediately obvious if it's React or a function, but with some digging you should be able to find out by following the imports.
It's absolutely not an ES6 variable. count=0 may be valid ES6 but in a NueJS setup it's not parsed by the JS interpreter: it's preprocessed. What actually gets served and parsed by the browser is an entirely different piece of code & that makes it inherently changeable in future releases.
Also, while count=0 is technically valid ES6, most of the larger examples on the page are not; this is a DSL like any other, with all the drawbacks that brings. Masquerading as ES6 syntax won't fix that.
> Nue transpiler takes the code between the script tags and creates a true ES6 class instance from it.
the second phrase negates the first. It will be a ES6 variable, it isn't.
You'll see that the compiled code is pure JS and parsed by the JS interpreter on the browser, unlike the parent commenter states.
The argument being made here is that the pre-compiled code is not ES6. Of course the compiled code is - I can't see how that's relevant, that's the same for every JS FE DSL.
This is flatly untrue - multiple commenters have outlined why this is untrue above.
> Also not sure what in this discussion is relevant.
It's relevant because the original comment is advocating for Nue.js on the basis that the DSL is standards-based, which is untrue. Designing something that looks like a standard without actually adhering to that standard does not equate to being standards based, nor does it benefit from any of the advantages of a standards-based approach.
---
fwiw, while my use of the word "untrue" above seems strong, I want to state clearly that I don't believe you're deliberately trying to mislead anyone here. Your intent seems benign, but I would just suggest learning a little bit more about the approachs of various frameworks, templating systems & DSLs over the years.
On Nue.js case tho the count=0 is misleading as it is a class variable that can get a setter and getter but in Nue.js code it is a normal variable that can't have a getter/setter. So the code doesn't really do what it is supposedly doing.
If you want getters and setters, you'll use standard ES6
a normal "count = 0" used in the examples.
a Nue "count = 0;" isn't the same as a ES6 "count = 0;". It needs compilation. I think trying to convince developers of the opposite won't help much grow a community.
It is implied, it will be supplied by the framework after compiling the code. So no, it is not a ES6 class instance variable.
Let the bundler minify your JavaScript. Less characters !== simple.
Less characters in source code is obviously a better metric for simplicity than what there are on the minified code (Nue wins on both btw)
Especially now that self encapsulating modules are a thing and server side templating can fill in html's lack of import tags. Reusable components sound great in principle, but trying to replace one that's used in 30 different locations with small nuances in each spot leads to complete debugging hell, just like typical overzealous polymorphism.
Allegedly we're even getting optional typing soon, so TS will become obsolete as well.
I love vanilla JS. Are you referring to web components?
I'll be surprised if tc39 allows it.
1. Is wholly immaterial.
2. Is pure conjecture ("Dynamic typing is a good thing") that I happen to vehemently disagree with.
3. Also wholly immaterial.
In fact it's rare to see "material" reasons for using TypeScript. Mostly baseless claims how static typing is "obviously better".
But whatever...
The merits of ES6 are also present in typescript. Thus claim 1 is immaterial.
Claim two is rebuked by intellisense and very strongly argued against in a shared-code world.
Claim 3 is presumptive that TypeScript would be the only transpilation, despite nue itself being a transpiler. In addition to all the other bundling modern products use for treeshaking, minification, etc. This is an insignificant and thus immaterial point.
("justification" enough for you?)
Did you even read the FAQ?
I am interpreting the task as "how can we make people who favour strong typing favour not use strong typing?" - something that I just don't think is possible.
I guess the nearest experience you'll get is a zealous API convention that is inuitively consistent/discoverable, but then I would still favour a type system to remove that concern anyway.
2. Code completion can be done also without static typing. Also relying on code completion is a strong smell of a bad codebase. The "very strong arguments" rarely have any empirical basis.
3. Transpilers/compilers are bad and more transpilers are worse. I would prefer a pure browser framework though. A lot of projects would be and are fine without treeshaking, minification etc. And those are practically never needed for development where the compilation step causes most harm.
Less code is better and DRY is by far the most important principle in software engineering.
Sadly every second generation seems to have to learn the hard way that the mega enterprise architecture astronaut stuff is a huge waste of time and produces bad software.
Hence, I strongly encourage the author to compile to web components instead of a custom output to increase/achieve interop.
Would love to hear the details! Sample code would help a lot understanding the problem/solution. Thanks!
The HTML: <button @click=“count++”> {count} </button>
return (
<div>
<h2>You clicked {count} times!</h2>
<button onClick={() => setCount(count - 1)}>
Decrement
</button>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
)
Nue is the opposite side of the same coin. return el("div", { children: [
el("h2", { children: [safe`You clicked ${count} times!`]) },
el("button", { onClick: () => setCount(count - 1), children: [safe`Decrement`] }),
el("button", { onClick: () => setCount(count + 1), children: [safe`Increment`] })
]});
The "it's just javascript" part comes from having no hidden getters, setters or proxies littered in code that may or may not behave as how we expect, and not littering the html with react-specific attributes for iteration, events, etcIn any case, why market your framework with an equally poor comparison?
You can use all React features without any special tooling.
React is just JavaScript. React+JSX is JSX. This:
<button onClick={() => setCount(count + 1)}>{count}</button>
Is sugar for: React.createElement('button', { onClick: () => setCount(count + 1) }, count)
True, the JSX version is most popular, but it's trivial syntax sugar with no "magic." This is different then Angular, Vue, Svelte, etc templatesThan what? I couldn't imagine react being hard, maybe for novice developers that just start with programming in general.
> React and other frameworks spent so much effort abstracting the render loop
Considering how big is community adoption and teams that are working on big 3 frameworks, they're doing it not "just because" and not to make your app slower. There are reasons for this and this new library will learn them as well, just like svelte did with their reactive variables approach.
Most of the problems with data binding stem from the fact that there is not a prorammable understandable primitive for us to reason about it. Yet time and time again people try to hide such primitive behind some magic templates, hooks, runes and that kind of nonsense
This calls a referenced function:
@click="addFruit"
This executes an expression: @click="images.pop()"
What if I have a expression that returns a function that should be called? onclick="addFruit"
is not the same as onclick="addFruit()"it also has some additional things here:https://github.com/nuejs/nuejs/blob/a5c844494852cdbe3282fdc5... so might not work the same way, didn't spend much time to check it just a glance.
On the other hand, the unproductive critique in all the comments makes me think everyone forgot how hard it is try to make something better.
1. The problem is so basic, I get it done with useState/useReducer
2. I problem is complex, and needs something more explicit like RxJS, or I'll lose my mind.
The first example of the site would become:
<div>
<h2>You clicked {count} times!</h2>
<button id='decrement'>Decrement</button>
<button id='increment'>Increment</button>
<script>
count = 0
$('button#increment').on('click', () => { count++ })
$('button#decrement').on('click', () => { count-- })
</script>
</div> <div>
<h2>You clicked {count} times!</h2>
<button id='decrement'>Decrement</button>
<button id='increment'>Increment</button>
</div>
<script>
count = 0
increment.click(() => { count++ })
decrement.click(() => { count-- })
</script>Also debugging prod code will be a pain.
Cool tech demo but I would not use this for bigger projects
Nue will be absolutely fantastic for scaling large applications and teams!
Huh, I didn't know that. I still don't know that :)
everything inside "" should be string; otherwise it's confusing.
this is my personal preferences and it applies to any project
Nice to see people trying to push boundaries
Nue might not be a great option for building large scale web apps; it however could be a great way to add reactivity to simple websites. We don't need to have the full fledged webpack monstrosity for every little site.
Signed: a concerned Angular (the best framework there is in the whole world) developer