Enjoy the process of building your framework. I had similar goals when I started my no tooling / no dependencies Reactive framework https://reken.dev, 2 years ago. And I loved every bit of it. My most complicated problems were reactive DOM elements based on nested loops and recursive components. Even though Reken does pretty much what I need and grew to 7kb compressed, I am not 100% happy with the scope of the application state, and it is simple but sometimes confusing. Perhaps your proxy approach can help me here.... I'll have to think about it more.
> My most complicated problems were reactive DOM elements based on nested loops and recursive components
Agreed, I've tried solving it by setting an attribute `sb-mark` which allows syncing just the branch of DOM elements that maps to that particular key in the reactive object.
This removes the need for VDOM diffing, but unless I use a `MutationObserver` external updates to marked branches will probably mess it up.
Haven't yet tested it for recursive components, it should work for nested loops.
> and it is simple but sometimes confusing
I understand what you mean, my approach has the aforementioned `sb-mark` attribute/directive which syncs primitives, lists, and objects.
I've started feeling that the convenience of having just one attribute to remember is supplanted by the confusion of its implications not being immediately apparent from context.
Your arrays and buttons example appears broken - after the first item is added to the todo list, typing new items in the input field leaves the add button looking disabled (although it works when you click it).
I think it only gets enabled when focus leaves the input field.
I made a similar library [1] using data-* attributes. It also supports nesting, looping and conditions. For event handling, I use function in object (a.k.a. method) while you support writing them inline.
Your way to support inline logic in the text and style is interesting.
New front end frameworks that claim leaps in simplicity feel like the violate some kind of no free lunch principle to me. If they’re that simple, then I’m willing to bet they make some use cases very difficult or impossible
Depends on the definition of simplicity. People say they want simple, but then really want easy. The most easy is always somebody doing the work for you. I got tired of hearing people mention easy when really they probably mean some combination of fearful and/or lazy, so I chose to define easiness:
If developers really wanted simplicity or to be done with work faster they would just learn the primitives of their environment: DOM, functions, and events. Most of the frameworks have APIs that are huge, so clearly simplicity isn't what's wanted.
I would argue rather that the amount of complexity that frontend web devs put up with is more of a Stockholm Syndrome situation. You can be much simpler than most mainstream frameworks, using only standard JS, CSS, and HTML, and acheive better results.
Using custom elements and shadow DOM like this post is a big part of that. Custom elements give you a built-in component module, shadow DOM gives you compositions and style scoping.
I think using proxies like this post is a challenging because proxies are very hard to get correct when dealing with methods, collections, object identity, privacy, etc. but it turns out that many applications do just fine with a simple Redux-like store / action / subscribe system for data.
I personally think the project I work on (https://lit.dev) hits a sweet-spot of simplicity vs complexity because it also gives component reactivity, declarative templates, embedded CSS, with standard syntax and no build tools required. In more than 400 LoC, but only by ~3x.
I've found that if they brag about how easy it is to get started, it usually ends up messy relatively quickly. On the other hand, if they brag about being easy to order when you have a lot of code, it's usually a bit harder to get started with.
It's like you get to chose one of "get started quickly" or "remain quick enough on the medium/long term"
I think a lot of stuff is taken wrongly in this article. First of all, React.js is a library that just provides a handful of hooks. "magical HTML and JavaScript" code is called JSX, and that is transpiled by Babel into not-so-magical nested function walls. Imperatively applying mutations to an application state inside a proxy object setter is, in fact, proactive and not reactive. Reactive implies that the renderers are pure declarative functions that are derived from data, so changing the data would result in a different renderer output based on a composition of these pure functions. So, in the end, React.js is just a library that brings a pure functional renderer to the web, and you even need a separate library, called react-dom, in order to manipulate the DOM itself with the outputs of React function. If you want to approach something similar to React, try to abstract away from DOM and HTML, and think in terms of a single pure data function, which returns a tree that can be then traversed into a set of UI elements.
This is extremely similar to https://jhuddle.github.io/ponys/ which I've been using quite happily. The `data-mark="foo"` convention is interesting, similar in spirit to ng:bind or knockout attributes.
Nice write-up, I look forward to seeing how Strawberry progresses. I keep a list of JS front end frameworks where no build step is required at https://unsuckjs.com/. I'll add this there (and a few of the others mentioned in the comments here).
As someone who started out in this profession in their early 30s, it was made clear very quickly, both by observation and shared wisdom, that it was completely possible to go one's entire career never getting below the level of gluing business code together with the adhesive of some framework, i.e. never learning how to design a system or think from the 'bottom' of a solution.
While its arguably more accessible than ever, you can quickly find yourself swimming in a shallow pool if you're not careful where your first job is, unless you have the free time and comportment to swim towards the deeper end on your own. And the larger magnitude that this occurs at, the greater the stranglehold of most devs to some well-funded framework and tooling.
So I applaud reminders like this that ask to just take a step back from time-to-time and maybe provide ourselves a new opportunity before reaching for $BIG_FRAMEWORK when the project is a few views w/ some buttons and an input on them. There has to be some balance between the utter pragmatism and curiosity and exploration that builds skills to have a healthy demo of devs.
I routinely see this second-hand classist complaint about 'JavaScript devs ruining software' (particularly w/ Electron in hand, even though the most used Electron apps are probably worked on by high-tier devs) but really the source of that concern is the market desiring that devs be more or less replaceable for the most part and the skillsets follow that. You can't break that without some disruption to the Framework-Industrial Complex.
They literally just described Svelte with that headline.
Front end framework: check
Reactivity: $check
Composability: check
No dependencies: once compiled, check
And pretty sure Svelte (or Qwik or Solid or even React) will perform better than the "dependency-free" custom components. The open secret in the front end world is that custom components as baked into browsers is slower and a major pain in the ass as an API. That's why it wasn't adopted widely and why it will likely never be adopted widely.
The funny thing about stories like these is that once you write the first general use code that isn't based on your specific task, you've created a dependency. Only this dependency isn't improved and maintained by a community or company; its maintenance is handled by you and your team. Maybe you take it on because the benefits outweigh the costs for your team. You improve and refine "just a few functions". Other folks like what you've done and ask to use it. Now they have a dependency on the "no dependencies" framework. Eventually you have to give it a name, and it gets popular.
A few years later, a developer decides they doesn't want any dependencies in their front end code anymore…
Kind of bending definitions to say svelte doesn't have any dependencies once compiled. Svelte itself is a dependency, and though complex and bundled there are svelte utilities included in the app that aren't code directly written by the user. Anecdotally, if also be very interested to see any example of a production Svelte project that doesn't pull in any other dependencies.
The article also calls out no build step, though it's not in the title. That's an important factor for the kind of project that isn't updated regularly and needs to work without any fuss after a year or two of going stale.
I'm a big fan of svelte by the way, been using it since pre-release 2.0 and still reach for it whenever I need a more complex state management or don't have the time to roll my own animation trigger utilities.
No, it is more Vue than svelte. Vue use proxies while svelte doesn’t. That being said I wonder if tying up with web components is a good idea. Cause if it was, other js framework author would have applied it
On a recent project, I’ve just been using JS template strings and .innerHTML all over the place.
I don’t necessarily recommend it, but it’s been a good reminder to me that most of the value React provides me is literally just html-in-JS. In many cases the complexity that comes from React effects and state is unnecessary, and directly mutating DOM nodes is sometimes a lot less painful. Sometimes.
This definitely works until you hit one of a few cases I can think of:
* Adding animations to elements. By blowing away the DOM and inserting new elements each time, you'll trigger any css `animation` for new elements entering.
* Stale data. If your template isn't re-run when some data changes for whatever reason, you'll continue to render the old data. You've got to manage the lifecycle of state updates yourself.
* To counter that, you might just re-run your templates when _anything_ changes. This works until you have a significant amount of data, then performance starts to become an issue.
This won't come up for many cases though, so for simpler apps it's definitely more than enough!
Very interesting. I think this explains a lot of the magic that happens under the surface in the frontend frameworks. I quite like the approach you are using to avoid a build step and also zero dependencies.
Very thin frameworks can avoid the complexities of React and hooks and useEffect and whatnot. Here's an app written with a 500-line "framework", notice how readable and maintainable it is:
https://github.com/wisercoder/eureka
I'm experiencing the trade off between simplicity and expressiveness for a lightweight frontend library that doesn't involve VDOM.
On one hand, a library [1] can be very concise (update dom from object, with looping and nesting supported).
On another hand, a library [2] can be very flexible and reactive (update dom from dom events).
However, when double-binding (a.k.a. bi-directional binding) is required (update dom from object and update object from dom), it seems more complex than I would consider it lightweight.
When double-binding is preferred, I'd rather go for angular / vue. Still exploring alternatives.
Why do we need a frontend framework? I am genuinely interested. The last project we used SSR and the sire ended up fast and snappy using a lot less energy than the previous similar project we used a JS based framework and we had all the functionality we needed.
I think the common argument is "complex interactivity". If you have sufficiently complex custom client-side interactivity (e.g. sending, receiving, manipulating and displaying data in the DOM without constantly reloading the page) then something like React or Vue is much easier and more maintainable than a bunch of custom JS. Logic for mutating and displaying data can also live on the backend and use SSR, but it has to live somewhere. I think people like SPAs because you can draw a convenient boundary at the server level by exposing a JSON API, and folks working in HTML, CSS and JS like the component model offered by frontend frameworks (I know I do).
There's also something to be said for consistency. When I walk into a React or Vue app, I can figure out what's going on and build on top of it quickly. Even if they are using a mish-mash of libraries (as JS apps do) the majority of the time you will see similar libraries and patterns used.
All that said, there are many monstrosities built upon SPA frameworks with poor performance that would likely provide better user experience if they were using SSR. But there were also many SSR monstrosities built before SPAs were in vogue.
Projects that don't need a lot of interactivity after rendering definitely don't need one and you can get away with rendering everything in the backend.
Other projects need some additional features that must be implemented in the frontend, but still don't need more than vanilla JS or jQuery.
Others might need more complex components, such as datepickers, carousels, interactive charts, interactive tables, accordions. But even those can be consumed from third-party components without a framework. A middle ground is writing your own encapsulated components.
However there are more complex apps that do benefit from frameworks. It's often because they have a lot of custom components and a framework really helps; and/or because they're not really divided into pages in a traditional web way, so rendering on the backend is significantly harder; and/or they have a lot of shared state between multiple areas of the screen, and not refreshing is easy than caching or re-fetching. All those among other reasons. Slack Web can benefit from this. Your daily CRUD not so much.
Whether people are using the right tools for each job is up for debate. And sometimes you'll have incorrect requirements. But there are definitely reasons to use more complex/flexible tools.
They were extremely useful before browsers had certain features, like web components of the Proxy api mentioned in the article.
Today the argument is usually based on highly complex apps, think complex dashboards accessible behind a login or browser-based apps for recording a podcast. Those are reasonable uses for client-side frameworks - the problem is they are often used for much more basic sites that just need a mobile menu, accordion component, or a dialog modal. All of these can either use entirely browser native HTML/CSS or easily built in JS without any dependencies.
I've worked on quite a few projects that would have had significantly worse user experiences if they were done in a purely SSR driven way:
* Chat applications, or anything where you need to have the UI react to incoming events from a socket.
* Applications where sensitive data lives in the client and you don't want to be liable for that passing through your servers.
* Anything dealing with video or audio (e.g. video chat, screen recordings.)
* Applications that are driven by peer to peer data.
* Applications with high interactivity (e.g. spreadsheets, heavy form validation, drag and drop UIs, graphic manipulation.)
It really depends on what your application is doing. If you're just a blog or an eCommerce site, it's definitely worth asking if you need a frontend framework. But for some applications it's absolutely worth it.
> The second main reason is the ability to define a component and reuse it without having to redefine it every time we need to use it. This is called composability.
Uhm, this isn’t strictly composability. Its reusability. Composability is distinct in that you’re architecting or designing components to be composed with one another. That is, they only know what they need to know and isolate domain. Also, their composition interface is the same as their output interface. A likely outcome is reusable components, but it’s not the goal necessarily.
This is great! I've been looking for a framework with exactly these goals. I've been using vanilla JS and custom elements and feeling like I'm writing too much boilerplate, but all the frameworks I've tried are too heavyweight.
I do not have astigmatism (or at least I think I don’t) but I notice that the rows of white letters stay burned in my vision, the contrast was so high it’s as if I am staring at small strong light sources.
I have astigmatism with the opposite effects. I wish more sites had dark modes. I have to use dark reader to ensure I can have a dark page but that doesn't always work.
hbroek|2 years ago
18al|2 years ago
Agreed, I've tried solving it by setting an attribute `sb-mark` which allows syncing just the branch of DOM elements that maps to that particular key in the reactive object.
This removes the need for VDOM diffing, but unless I use a `MutationObserver` external updates to marked branches will probably mess it up.
Haven't yet tested it for recursive components, it should work for nested loops.
> and it is simple but sometimes confusing
I understand what you mean, my approach has the aforementioned `sb-mark` attribute/directive which syncs primitives, lists, and objects.
I've started feeling that the convenience of having just one attribute to remember is supplanted by the confusion of its implications not being immediately apparent from context.
lelanthran|2 years ago
I think it only gets enabled when focus leaves the input field.
aabbcc1241|2 years ago
Your way to support inline logic in the text and style is interesting.
[1] https://github.com/beenotung/data-template
klysm|2 years ago
austin-cheney|2 years ago
https://github.com/prettydiff/wisdom/blob/master/Easiness.md
If developers really wanted simplicity or to be done with work faster they would just learn the primitives of their environment: DOM, functions, and events. Most of the frameworks have APIs that are huge, so clearly simplicity isn't what's wanted.
spankalee|2 years ago
Using custom elements and shadow DOM like this post is a big part of that. Custom elements give you a built-in component module, shadow DOM gives you compositions and style scoping.
I think using proxies like this post is a challenging because proxies are very hard to get correct when dealing with methods, collections, object identity, privacy, etc. but it turns out that many applications do just fine with a simple Redux-like store / action / subscribe system for data.
I personally think the project I work on (https://lit.dev) hits a sweet-spot of simplicity vs complexity because it also gives component reactivity, declarative templates, embedded CSS, with standard syntax and no build tools required. In more than 400 LoC, but only by ~3x.
capableweb|2 years ago
It's like you get to chose one of "get started quickly" or "remain quick enough on the medium/long term"
luisgvv|2 years ago
What makes it worse in the front-end framework world is that either:
1-Projects become convoluted with 3rd party libs to solve a problem
2-The framework maintainers eventually introduce APIs that aren't backwards compatible and existing ones stranded or deprecated
duxup|2 years ago
Generally they really can save a lot of time / needed structure.
legulere|2 years ago
gloosx|2 years ago
grncdr|2 years ago
joncfoo|2 years ago
adparadox|2 years ago
aabbcc1241|2 years ago
https://github.com/beenotung/html-template-lite
https://github.com/beenotung/data-template
https://github.com/beenotung/dom-proxy
spankalee|2 years ago
We're actually removing that in the upcoming 3.0 branch though.
imbnwa|2 years ago
While its arguably more accessible than ever, you can quickly find yourself swimming in a shallow pool if you're not careful where your first job is, unless you have the free time and comportment to swim towards the deeper end on your own. And the larger magnitude that this occurs at, the greater the stranglehold of most devs to some well-funded framework and tooling.
So I applaud reminders like this that ask to just take a step back from time-to-time and maybe provide ourselves a new opportunity before reaching for $BIG_FRAMEWORK when the project is a few views w/ some buttons and an input on them. There has to be some balance between the utter pragmatism and curiosity and exploration that builds skills to have a healthy demo of devs.
I routinely see this second-hand classist complaint about 'JavaScript devs ruining software' (particularly w/ Electron in hand, even though the most used Electron apps are probably worked on by high-tier devs) but really the source of that concern is the market desiring that devs be more or less replaceable for the most part and the skillsets follow that. You can't break that without some disruption to the Framework-Industrial Complex.
dxchester|2 years ago
Reactivity, composability, templates, etc with no dependencies, in ~150 SLOC.
ttfkam|2 years ago
Front end framework: check
Reactivity: $check
Composability: check
No dependencies: once compiled, check
And pretty sure Svelte (or Qwik or Solid or even React) will perform better than the "dependency-free" custom components. The open secret in the front end world is that custom components as baked into browsers is slower and a major pain in the ass as an API. That's why it wasn't adopted widely and why it will likely never be adopted widely.
The funny thing about stories like these is that once you write the first general use code that isn't based on your specific task, you've created a dependency. Only this dependency isn't improved and maintained by a community or company; its maintenance is handled by you and your team. Maybe you take it on because the benefits outweigh the costs for your team. You improve and refine "just a few functions". Other folks like what you've done and ask to use it. Now they have a dependency on the "no dependencies" framework. Eventually you have to give it a name, and it gets popular.
A few years later, a developer decides they doesn't want any dependencies in their front end code anymore…
_heimdall|2 years ago
The article also calls out no build step, though it's not in the title. That's an important factor for the kind of project that isn't updated regularly and needs to work without any fuss after a year or two of going stale.
I'm a big fan of svelte by the way, been using it since pre-release 2.0 and still reach for it whenever I need a more complex state management or don't have the time to roll my own animation trigger utilities.
rk06|2 years ago
hbroek|2 years ago
es7|2 years ago
I don’t necessarily recommend it, but it’s been a good reminder to me that most of the value React provides me is literally just html-in-JS. In many cases the complexity that comes from React effects and state is unnecessary, and directly mutating DOM nodes is sometimes a lot less painful. Sometimes.
wbobeirne|2 years ago
* Adding animations to elements. By blowing away the DOM and inserting new elements each time, you'll trigger any css `animation` for new elements entering.
* Stale data. If your template isn't re-run when some data changes for whatever reason, you'll continue to render the old data. You've got to manage the lifecycle of state updates yourself.
* To counter that, you might just re-run your templates when _anything_ changes. This works until you have a significant amount of data, then performance starts to become an issue.
This won't come up for many cases though, so for simpler apps it's definitely more than enough!
pkphilip|2 years ago
petilon|2 years ago
djbusby|2 years ago
Also, wondering if there are other tools for searching code and other internal Corp stuff on external services (GitHub/Lab, Google Drives, etc)
aabbcc1241|2 years ago
On one hand, a library [1] can be very concise (update dom from object, with looping and nesting supported).
On another hand, a library [2] can be very flexible and reactive (update dom from dom events).
However, when double-binding (a.k.a. bi-directional binding) is required (update dom from object and update object from dom), it seems more complex than I would consider it lightweight.
When double-binding is preferred, I'd rather go for angular / vue. Still exploring alternatives.
[1] https://github.com/beenotung/data-template
[2] https://github.com/beenotung/dom-proxy
datadeft|2 years ago
muspimerol|2 years ago
There's also something to be said for consistency. When I walk into a React or Vue app, I can figure out what's going on and build on top of it quickly. Even if they are using a mish-mash of libraries (as JS apps do) the majority of the time you will see similar libraries and patterns used.
All that said, there are many monstrosities built upon SPA frameworks with poor performance that would likely provide better user experience if they were using SSR. But there were also many SSR monstrosities built before SPAs were in vogue.
whstl|2 years ago
Other projects need some additional features that must be implemented in the frontend, but still don't need more than vanilla JS or jQuery.
Others might need more complex components, such as datepickers, carousels, interactive charts, interactive tables, accordions. But even those can be consumed from third-party components without a framework. A middle ground is writing your own encapsulated components.
However there are more complex apps that do benefit from frameworks. It's often because they have a lot of custom components and a framework really helps; and/or because they're not really divided into pages in a traditional web way, so rendering on the backend is significantly harder; and/or they have a lot of shared state between multiple areas of the screen, and not refreshing is easy than caching or re-fetching. All those among other reasons. Slack Web can benefit from this. Your daily CRUD not so much.
Whether people are using the right tools for each job is up for debate. And sometimes you'll have incorrect requirements. But there are definitely reasons to use more complex/flexible tools.
_heimdall|2 years ago
Today the argument is usually based on highly complex apps, think complex dashboards accessible behind a login or browser-based apps for recording a podcast. Those are reasonable uses for client-side frameworks - the problem is they are often used for much more basic sites that just need a mobile menu, accordion component, or a dialog modal. All of these can either use entirely browser native HTML/CSS or easily built in JS without any dependencies.
wbobeirne|2 years ago
* Chat applications, or anything where you need to have the UI react to incoming events from a socket.
* Applications where sensitive data lives in the client and you don't want to be liable for that passing through your servers.
* Anything dealing with video or audio (e.g. video chat, screen recordings.)
* Applications that are driven by peer to peer data.
* Applications with high interactivity (e.g. spreadsheets, heavy form validation, drag and drop UIs, graphic manipulation.)
It really depends on what your application is doing. If you're just a blog or an eCommerce site, it's definitely worth asking if you need a frontend framework. But for some applications it's absolutely worth it.
dclowd9901|2 years ago
Uhm, this isn’t strictly composability. Its reusability. Composability is distinct in that you’re architecting or designing components to be composed with one another. That is, they only know what they need to know and isolate domain. Also, their composition interface is the same as their output interface. A likely outcome is reusable components, but it’s not the goal necessarily.
mtlynch|2 years ago
spankalee|2 years ago
revskill|2 years ago
Example, RoR already provides powerful good library like SimpleForm. Now i want to turn this html form into a React form, how ?
oblib|2 years ago
lloydatkinson|2 years ago
spankalee|2 years ago
pier25|2 years ago
https://medium.com/@h_locke/why-dark-mode-causes-more-access...
If the issue is not wanting to spend a bit of effort to implement prefers-color-scheme then light mode is a much better default option.
vjerancrnjak|2 years ago
So I prefer black letters on light background.
geraldwhen|2 years ago
earthling8118|2 years ago
icemelt8|2 years ago
[deleted]
lolive|2 years ago