[HN Gopher] Building a front end framework - Reactivity, composa...
       ___________________________________________________________________
        
       Building a front end framework - Reactivity, composability with no
       dependencies
        
       Author : 18al
       Score  : 132 points
       Date   : 2023-05-14 12:26 UTC (10 hours ago)
        
 (HTM) web link (18alan.space)
 (TXT) w3m dump (18alan.space)
        
       | lloydatkinson wrote:
       | Lost me at web components. What a miserable DX and inconsistent
       | mess that is.
        
         | spankalee wrote:
         | What's inconsistent about them?
        
       | grncdr wrote:
       | 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.
        
         | joncfoo wrote:
         | This is really neat! I'm going to take it for a spin in a
         | simple CRUD internal app.
        
       | imbnwa wrote:
       | 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.
        
       | revskill wrote:
       | This is good progress. I hate that i can't do progressive
       | enhancement on pure html form with Frontend Framework.
       | 
       | Example, RoR already provides powerful good library like
       | SimpleForm. Now i want to turn this html form into a React form,
       | how ?
        
       | es7 wrote:
       | 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.
        
         | wbobeirne wrote:
         | 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!
        
       | pkphilip wrote:
       | 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.
        
       | mtlynch wrote:
       | 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.
        
         | spankalee wrote:
         | Have you tried Lit yet? It gives you a reactive base class and
         | declarative templates. Plain JS and no build step (or you can
         | use TypeScript).
        
           | mtlynch wrote:
           | I played with it a little bit when you told me a few months
           | ago it supports buildless.[0]
           | 
           | The thing that dissuaded me is that it seems like it forces
           | me to write my template HTML in strings, so I lose VS Code
           | syntax highlighting and Prettier auto-formatting. I tried
           | looking for VS Code / Prettier plugins but didn't see
           | anything.
           | 
           | Is there a way in Lit to write the templates in regular HTML
           | rather than a string?
           | 
           | [0] https://news.ycombinator.com/item?id=34828992
        
       | lolive wrote:
       | Yet another people denying React Hooks has won...
        
       | petilon wrote:
       | 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
        
         | djbusby wrote:
         | Less Framework and more Library it feels like.
         | 
         | Also, wondering if there are other tools for searching code and
         | other internal Corp stuff on external services (GitHub/Lab,
         | Google Drives, etc)
        
       | ttfkam wrote:
       | 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...
        
         | _heimdall wrote:
         | 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.
        
           | ttfkam wrote:
           | Fair points.
        
         | hbroek wrote:
         | I love Svelte for all these reasons. But in the end, was turned
         | off by the required tooling.
        
       | hbroek wrote:
       | 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.
        
         | 18al wrote:
         | > 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.
        
           | hbroek wrote:
           | > This removes the need for VDOM diffing, but unless I use a
           | `MutationObserver` external updates to marked branches will
           | probably mess it up.
           | 
           | Similar in Reken. It controls all the DOM; DOM updates
           | outside Reken will get stuff out of sync. After a model
           | change, all managed DOM gets directly updated by a generated
           | controller. It does check the DOM first if a textContent or
           | attribute change is necessary. Most DOM state checks are
           | cheap. Another optimization is that all hidden DOM trees get
           | skipped; Great in SPA apps with multiple pages.
        
         | lelanthran wrote:
         | 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.
        
           | hbroek wrote:
           | Thanks for pointing that out. Yes had rewritten it a will
           | need to use a different event to enable the button if there
           | is an update in the input field.
        
         | aabbcc1241 wrote:
         | 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.
         | 
         | [1] https://github.com/beenotung/data-template
        
           | hbroek wrote:
           | Very cool, it seems we almost came up with the same approach
           | of components/templates. In your framework, it is referenced
           | with a data-template attribute. In Reken, I use a data-
           | component attribute.
           | 
           | One of the design goals for Reken was to not have to context-
           | switch while coding, to not lose my train of thought (Guess
           | my short-term memory is limited). Hence try to add everything
           | inline in the HTML file. Also I'm working on a tailwind-like
           | css inlining framework (compatible with Reken). Together
           | these give me dynamic DOM and styling inline.
        
       | pier25 wrote:
       | Please don't make websites dark mode only. This is terrible for
       | accessibility. I have astigmatism and can't read more than a few
       | paragraphs.
       | 
       | 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 wrote:
         | 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.
         | 
         | So I prefer black letters on light background.
        
         | earthling8118 wrote:
         | 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.
        
         | geraldwhen wrote:
         | Maybe this is why I cannot read dark mode websites at all. Even
         | coworkers with dark mode themes on their IDE are completely
         | inscrutable to me.
        
       | oblib wrote:
       | This is certainly new to me and something I'm going to play with
       | a bit. Thank you for sharing this here.
        
       | datadeft wrote:
       | 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.
        
         | muspimerol wrote:
         | 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.
        
           | datadeft wrote:
           | This is the most useful comment so far. I tend to agree.
           | However, I still think that most frontend project are
           | perfectly fine with mostly HTML + CSS and a tiny bit of JS.
        
         | whstl wrote:
         | 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.
        
         | _heimdall wrote:
         | 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.
        
         | wbobeirne wrote:
         | 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.
        
           | datadeft wrote:
           | * Applications where sensitive data lives in the client
           | 
           | Isn't JS the worst kind of solution for security related
           | things?
        
       | klysm wrote:
       | 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
        
         | capableweb wrote:
         | 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"
        
           | bitL wrote:
           | Not always, some can hit the sweet spot of being simple in
           | all phases of development and quick to learn. They are super
           | rare though and their lessons are forgotten; industry often
           | standardizes on inferior things with better marketing.
        
             | karpierz wrote:
             | What are some examples?
        
               | arcanemachiner wrote:
               | I think Alpine.JS hits this spot pretty well.
               | 
               | https://alpinejs.dev/
        
               | ipaddr wrote:
               | jQuery
        
             | balder1991 wrote:
             | [deleted]
        
             | balder1991 wrote:
             | > industry often standardizes on inferior things with
             | better marketing.
             | 
             | It standardizes to what's cheaper on their eyes, sometimes
             | in a very short-sided way, but also companies that work for
             | profit never know if a project will still be running in the
             | next quarter, right? It makes me think that open source and
             | for profit companies should have very different
             | considerations when it comes to choosing frameworks or
             | technologies for their solutions. I should probably gather
             | more info on that and expand it into a blog article.
        
         | legulere wrote:
         | Web components weren't as widely available as they are now when
         | most web frameworks were written.
        
         | spankalee wrote:
         | 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.
        
           | Freedom2 wrote:
           | Do you have an example of a complex widget being implemented
           | in a simpler way with better results? I see this sentiment
           | often here, but most examples are toy examples or frivolous.
        
         | duxup wrote:
         | I feel like the only things that provide " leaps in simplicity"
         | as far as web dev goes are basic css frameworks.
         | 
         | Generally they really can save a lot of time / needed
         | structure.
        
         | luisgvv wrote:
         | The law of leaky abstractions - as systems become more complex
         | eventually you rely on more abstractions that try to hide
         | complexity.
         | 
         | 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
        
           | balder1991 wrote:
           | When discussing this problem with ChatGPT it indeed said the
           | best solution for this is for frameworks to be designed in a
           | way that encourages extensibility: so a framework should
           | stick to its core principles but allow "plugins" to extend
           | its functionality for very specific use-cases. But I
           | understand there's always a trade off here, as simplicity in
           | the framework shifts the complexity to the application.
        
         | austin-cheney wrote:
         | 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:
         | 
         | 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.
        
           | balder1991 wrote:
           | Thanks for sharing this. I've been recently into the concept
           | of Digital Gardens where you evolve concepts and expand them
           | over time (instead of the traditional chronological blogging
           | style) and this is exactly the result that I imagine a page
           | should look like when matured enough.
        
       | aabbcc1241 wrote:
       | 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.
       | 
       | [1] https://github.com/beenotung/data-template
       | 
       | [2] https://github.com/beenotung/dom-proxy
        
       | adparadox wrote:
       | 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).
        
         | aabbcc1241 wrote:
         | Would you also add these js library to the list? They don't
         | require build step as well.
         | 
         | https://github.com/beenotung/html-template-lite
         | 
         | https://github.com/beenotung/data-template
         | 
         | https://github.com/beenotung/dom-proxy
        
           | adparadox wrote:
           | I added `dom-proxy` because that looked like the closest to a
           | complete solution from a quick skim. Let me know if you want
           | to swap for another one, though.
        
         | spankalee wrote:
         | Lit 2.x is compatible with IE11, btw.
         | 
         | We're actually removing that in the upcoming 3.0 branch though.
        
           | adparadox wrote:
           | Thanks for the correction. Just updated it to be accurate...
           | for now. :)
        
       | dxchester wrote:
       | Nice writeup. We're working on a framework with similar goals,
       | here: https://github.com/frameable/el
       | 
       | Reactivity, composability, templates, etc with no dependencies,
       | in ~150 SLOC.
        
       | dclowd9901 wrote:
       | > 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.
        
       ___________________________________________________________________
       (page generated 2023-05-14 23:00 UTC)