Brian Lovin
/
Hacker News

Ask HN: How does one build large front end apps without a framework like React?

I had a mind-blown-moment when I learnt that Obsidian was built without any frontend JS framework. ( https://forum.obsidian.md/t/what-framework-did-the-developer-use-to-create-obsidian-desktop-application/30724/11 )

The benefits, I can see.

    JS frameworks move really quickly, and when we're working on a large, long-term project, it sucks when big breaking changes are introduced after only a couple of years. Sticking to slow-moving web standards (which are quite mature by now) increases the longevity of a project.

    And the stability also means that more time is spent on delivering features, rather than on fixing compatibility issues.

    There is also the benefit of independence. The project's success is not tied to the framework's success. And it also makes the project more secure, from supply chain attacks and such.

    Because there is no "abstraction layer" of a framework, you also have greater control over your project, and can make performance optimizations at a lower level.

    I feel not using a framework can even make us a better developer. Because we know more of what's going on.
There are benefits to using frameworks too, I'm not here to challenge that.

But this alternative of using none... it seems rarely talked about. I want to learn more about building large (preferably web-based) software projects with few dependencies.

Do you have any suggestions on how to learn more about it? Are there any open source projects you know which are built this way? It needs to be large, complex, app-like, and browser based. I'm more interested in the frontend side.

Thank you!

Daily Digest email

Get the top HN stories in your inbox every day.

Octoth0rpe

> JS frameworks move really quickly

React is a lot more stable than I think you're giving it credit for.

> And the stability also means that more time is spent on delivering features

Frameworks/libs also exist to save you time, thus letting you spend more time on delivering features. And fwiw, the obsidian team seems to agree in principle. Your link goes to a forum post of some kind, in which one may find a link to obsidian's third party deps: https://help.obsidian.md/credits#Third+party+acknowledgement...

These do not include React, but do include:

- i18next - lezer - moment.js

Plus a bunch of others. Why didn't obsidian write their own date lib and chose to use moment.js? Because it saved them time, despite the fact that moment.js does make changes, and many people are moving on from it in any case.

The idea that not using a frontend framework will let you focus on delivering features seems reductive, and the obsidian anecdote doesn't support the idea anyway.

Whatever you're building, it's never a bad idea to deeply understand the tradeoffs that using a library will bring. Obsidian probably couldn't accept the downsides of React due to them needing a bunch of custom renderers for content, which React makes harder. But that is likely a rare constraint for apps in general.

Generally speaking, libs like react exist to save you time and help you focus on delivering features.

actinium226

> React is a lot more stable than I think you're giving it credit for.

Hooks are only 5 years old. The docs were revamped 2 years ago and there's lots of dead links to the old docs page which has a scary warning "These docs are old and won’t be updated." Create-react-app was deprecated in February of this year and in their blog post they tell you to use frameworks like Next.js.

And then there's the ecosystem. Next.js introduced app router 3 years ago and lots of docs for libraries still assume you're using pages router. Remix is now react router v7, and I have no idea what's going on with all this Tanstack stuff. There's a new typescript compiler called "Speedy Web Compiler" which just came out in April and as a result Vite now has 4 options for creating a new React project: react, react-ts, react-swc, react-swc-ts

Meanwhile moment.js has had 5 releases in the last 4 years. 3 of them in 2022 and 2 in 2023.

Octoth0rpe

> Hooks are only 5 years old

7. Worth saying that React really only took off 9-10 years ago, so hooks are damn near the beginning of time for _most_ react devs.

> The docs were revamped 2 years ago and there's lots of dead links to the old docs page which has a scary warning "These docs are old and won’t be updated.

IMO those are not dead links. A link is 'dead' if it links to a page that doesn't exist. Links to old pages with warnings are appropriate in many cases. Many projects are using older versions of react, and devs need to look up info. Not sure this should be seen as a problem.

> Create-react-app was deprecated in February of this year and in their blog post they tell you to use frameworks like Next.js.

Not sure why this is a problem. A very early tool got deprecated, and the react docs recommend the current paradigm. It's not like they're changing their getting started guidance every month, or even every year.

> Remix is now react router v7

If this is a bitch fest about React, then the react docs and CRA are fair game, but remix isn't IMO.

actinium226

None of these are problems taken separately, but put together they're pretty frustrating. Hooks being 5 years old and being the predominant tool for certain tasks shows that the community only figured out how to solve a particular problem 5 years ago. Compare that, in terms of stability, to Python having coming up with the idea of packages a long time ago, and packages are now a stable part of the ecosystem (packaging is another story which I'll get to shortly).

Revamping the docs is not a problem by itself, but take a look at Python or Django, their docs have the same look and feel for older versions of the code. It's totally a minor problem, and if it were the only one I wouldn't be complaining here, but with the plethora of problems it starts to feel like death by a thousand papercuts.

> Create-react-app was deprecated

Going back to Python packaging, while it's much better than C/C++ packaging, people still love to complain about it! That said, pip is not deprecated. For React to just abandon the idea of helping users to create a project and telling them to "go bother someone else about it" does not seems like something a stable ecosystem would do.

> If this is a bitch fest about React, then the react docs and CRA are fair game, but remix isn't IMO.

It absolutely is a bitch fest about React because I inherited a simple site that should have never used React in the first place and it makes it so hard to do simple things without reinventing the wheel, but anyway, I'd say the ecosystem is fair game now that CRA is deprecated and the docs themselves tell you to go to Next or Vite or React Router or Tanstack.

Anyway, the point is that while React might be relatively stable from the point of view of the larger javascript ecosystem, it's still way less stable than it should be and way less stable than browser APIs.

mind-blight

I'm gonna be honest, I've been developing with react for about 9 years across a lot of projects and companies. I've never used next.

Maybe I'm out of touch, but I don't understand why people think it's so tightly could with the ecosystem

Octoth0rpe

There is a large amount of what _might_ be described as astroturfing on the part of vercel to push Next. More charitably, vercel/the next community publishes a very large number of good tutorials/boilerplates/etc that are built on top of next.js.

sralbert

If you check the docs for how to create a react app the first thing they recommend is to use next.js.

Eric_WVGG

> Hooks are only 5 years old.

That is a long damn time in this industry, and class-based components still work just fine.

throwthrow0987

I preferred class based components. The pretend functional programming style of hooks is quite imperative when you prick a little beneath the surface, so classes were probably the right abstraction.

Magmalgebra

Most of your complaints are about things that are not React. Those are optional. I can still standup a vanilla React stack in an afternoon just as easily as I did 5 years ago and immediately start writing the exact same code and have it "just work".

thiht

I’d argue it’s easier than ever today, thanks to Vite

mickael-kerjean

> React is a lot more stable than I think you're giving it credit for.

That's until you have to use it in a real project, for a long time the go to solution was the facebook maintained CRA which is now deprecated. I have spent a lot more time than I'd like to admit migrating webpack versions when it was considered best practises to use class component with decorator but decorator never was standardised in the browser and was never able to get a clean project where running npm install would not give scary warning our project had high vulnerability that was dependencies of dependencies in CRA to the point that it got me wondered that even if the creator of react facebook can't get their shit together, the whole ecosystem is doomed. I have been outside the ecosystem for a year and looking at the shit show that is nextjs it seems things are even worse than before.

whizzter

I agree with the Next shitshow, but webpack/CRA was always shaky while Vite's sane defaults (and great reloading) has been a great improvement for us outside of the Next world and functional components now feels like a fairly non-error prone and simple way to work so I don't see that going away for a long time (and has already lasted a bunch of years).

I think the only shaky moving part for us right now is styled components being left behind due to the RSC changes, but there's both mostly source compatible rewrites as well as perhaps even better alternatives (vanilla-extract).

tracker1

Agreed... I quickly ejected from the couple CRA projects I've used and quickly switched to Parcel, then Vite as they matured as it's just a much better experience. Not nearly as bad as trying to update some of the testing frameworks.

mexicocitinluez

> the go to solution was the facebook maintained CRA which is now deprecated

Not only did they deprecate it, they refused to acknowledge it's existence in the new docs which is wild to me.

It may have changed in the last year, but if you searched for "CRA", it would get 0 results. Again, mind-blowing considering it was the recommended way to build apps with React.

Instead, it was replaced with a section driving you towards adopting Next. Which then had to be whittled away at and updated to include other options all the while the React team acted hostile to any criticism of it. You either used Next or you were shit out of luck.

> I have been outside the ecosystem for a year and looking at the shit show that is nextjs it seems things are even worse than before.

My thoughts about CRA aside, you don't have to use the frameworks (I still don't). And if you remove Next from the equation, things are actually pretty cool. Suspense is cool, and you'll have to rip React Query from my cold, dead hands.

Octoth0rpe

These are good points, but many of them aren't specific to React, and in fact likely apply if you're rolling most of your own code. For example, the app that OP used to start the conversation uses webpack (https://help.obsidian.md/credits#Third+party+acknowledgement...).

> running npm install would not give you a dozen high vulnerability package

Yes, this is a serious problem, but mostly an npm messaging problem: https://overreacted.io/npm-audit-broken-by-design/

csande17

Dubious "regular expression denial of service" vulnerabilities seem like a general issue with the CVE bureaucracy lately. Like, maybe CVE-2020-10735 had a point that Python's default "int" type having unbounded size and a quadratic-time "str()" was a bit of a footgun, but now it's getting to a point where any use of backtracking in any context is just asking for a "high severity" ticket from the regex police.

thepianodan

> React is a lot more stable than I think you're giving it credit for.

I'm glad they take good care of backwards compatibility. React was the most common example, I didn't intend to target it specifically.

Not all frameworks are like this though. Svelte 5 introduced many breaking changes, with plans to deprecate the classic Svelte 4 syntax. So that forces many projects to spend time migrating to the newer version.

> The idea that not using a frontend framework will let you focus on delivering features seems reductive...

Agreed, appreciate the healthy arguments. :)

gg2222

Unrelated to the topic, but wow, they're still using moment? I thought it was kind of deprecated and been trying to use other libs.

dotandimet

I think most of the complaints about moment are that it's really big (because of i18n and timezones). Obsidian isn't a web page/app, so it doesn't need to optimize bundle size too much.

ohthatsnotright

It's unexpectedly mutable unless you've closely read the documentation, been bitten by the mutations, or are doing very simple date manipulations.

It's a great library, but it does need fewer footguns. date-fns is a good alternative.

lloydatkinson

> React is a lot more stable than I think you're giving it credit for.

A lot of the HN zeitgegist would have you believe React is the opposite, sadly.

CaptainOfCoit

The React ecosystem moves really quickly, and likes to re-invent wheels.

But React core APIs remain relatively stable, I've been using React the same way for many years at this point, and you can ignore the parts you don't like, like I'm ignoring hooks and haven't found a single use case where I needed them.

Tubelord

I learned React before hooks. Came from a mostly forgotten framework called ExtJS that used base JavaScript classes, so it was an easy transition.

Class based React is great. My old projects are cleanly structured, but harder to change. Class based React also lacks the composability you get with hooks.

adithyassekhar

Could you please tell me how are you avoiding hooks? You're not using useState or useEffects?

fud101

[flagged]

yawnxyz

I build a lot of micro sites, but I still use frameworks — like Deno (node alternative), Hono (for APIs), and Alpine.js (for tiny lightweight sites).

you don't have to though!

if you want to do more pure vanilla, understanding signals is really useful — this basically powers svelte's runs and react's hooks and whatever.

I love nanostores, a 286 byte (!) state manager that lets you build highly reactive pages w/o the weight: https://github.com/nanostores/nanostores

flexible tools like tinybase (https://github.com/tinyplex/tinybase) and unstorage (https://github.com/unjs/unstorage) are also super useful

tools like this lets you build highly reactive, engaging sites that load for under 50-100kb

actinium226

+1 for nanostores. It's great that it works standalone, but what's also nice is that they have tools to let you use it with React. It's much cleaner and more intuitive than React contexts which is how you're supposed to do global state in React, I think.

mickael-kerjean

The frontend of my main OSS work was made is plain es6: https://github.com/mickael-kerjean/filestash

The frameworky code is under 100 lines of code, heavily inspired by what I think is a good idea from React: "components are pure function", the simplest example of the about page beeing visible here: https://github.com/mickael-kerjean/filestash/blob/master/pub...

Since the whole project was migrated over from React, I was able to improve performance to a degree that would have been impossible using React, it's a breadth of fresh air to open the performance and memory tab and to be able to optimise things from there to get 60FPS no matter what whilst preventing massive ram usage because those frameworks runs all sort of code that is out of your control. Also because there is no build system, I was able to introduce plugins to be able to patch frontend code via patch applied dynamically by the server to create features like the recall button to recall data stored on glacier when using S3, dynamic patching of the icons to apply branding and many other things that I would have had to fork entirely before

Anyway, I hope our industry would go more often the vanilla route, es6 is ready for prime time and solve all the pain point we had while internet explorer was still a thing

hecanjog

> es6 is ready for prime time

I hope this becomes common knowledge! There was a period somewhere between when the web platform didn't have good tools to make web applications (plus DOM manipulation was slow) and the mainstream adoption of es2015 in browsers when it made sense to do things like create a virtual DOM to allow for unavailable features at the expense of performance. It did have its place, but we don't need it anymore.

Remove a layer. In 2025 ES6 is ready for prime time, indeed.

thepianodan

Exactly what I was looking for! Thank you! :)

hecanjog

The modern web platform is capable and not bad at all to work with directly. I love seeing projects like HTMX and the recent hyperflask etc showing the way, but you don't need to buy into a project to follow this path, just use the web platform.

Edit: for a more practical example, you don't need to go down the web components rabbithole just for native reactive components, MutationObserver can watch for your template fragments entering and exiting the DOM and run your init/destruct routines on them. Now you can just push HTML back from the server with fetch or xmlhttprequest or whatever, and as soon as your component's HTML enters the DOM it will be "hydrated" by your init routine via MutationObserver. Honestly, add some event signaling and XHR and you're further along to a smooth SPA-like experience than you might think.

andirk

Web components, copy/paste CSS that does crazy stuff, all of these Web APIs [0]. However, Vue is my go-to. It's just reactivity with files that don't break "separation of concerns". Plus a community if I get stuck. However however, making something super slim bare bones is the most rewarding.

https://developer.mozilla.org/en-US/docs/Web/API

lemonwaterlime

First, I decide if I think the app will have lots of client-side interaction. As a shorthand, the question is “Does my idea seem like a spreadsheet, Google Maps, or a video game with lots of interactive clicking?”

If the answer to that question is “No”, then I’m not conceptualizing a SPA and don’t need a framework.

If the answer is “Yes”, I’d ask where I think that interaction will manifest in the experience and if I can isolate it.

If I am not looking at a SPA use-case, then my focus is on using vanilla HTML and Modern CSS with a tiny bit of javascript (as a scripting language versus as a programming language [1]). Then the remainder of the focus is on data modeling (CRUD), auth flows, and business logic development (what the application will do).

Beyond vanilla HTML, Modern CSS, and a tiny amount of javascript, if I need further client-side interactivity, I would consider something like htmx.

If I need interactivity beyond that, then we’re into SPA territory, but at this point the requirements and application have evolved to that point since we initially said we weren’t building that kind of thing.

Overall, the idea is to progressively iterate on the application, keeping the architecture and dependencies reigned in and aligned with the core objectives.

[1] JavaScript as scripting vs programming language: what I mean by this is JavaScript as a language with many warts is not so bad if its scope is kept small. I believe the issues with JavaScript arise when it is pushed to do too much. This then leads to needing to use Typescript as a matter of pragmatism. I aim to never get to the point of using so much JavaScript that I then need Typescript. I would say using it as a scripting language (to fill in gaps that Modern CSS and HTML cannot handle today) greatly minimizes the need for this progression.

kethinov

Vanilla JS is very powerful and has the features you need to build SPAs without a big framework. Proxies and mutation observers are great for maintaining state, Updating the DOM yourself is fine, view transitions are awesome, etc. The only thing that's hard is routing, but there are lots of small dedicated JS libraries to handle that. Here's one I made that gives you the Express API on the frontend: https://github.com/rooseveltframework/single-page-express

whizzter

If you're using Proxies and mutation observers you've probably created your own micro-framework. I wrote something like petite-Vue / Alpine as an excersice and it's really not much to them.

Our_Benefactors

VanillaJS has no inbuilt type checking and your project will collapse under the weight of itself once reaching a certain size.

austin-cheney

What are you talking about with this talk of implosion? It sounds like boogieman nonsense from small children scared of the dark. I prefer to use vanilla JS when writing large SPAs and it works just fine.

There is a stereotype from the outside world that a great many programmers are autistic. The irrational fear of not using a framework for code in the browser is one of those cases that really screams the stereotype for all to see.

If you are using TypeScript there is inbuilt type checking for the DOM, because TypeScript ships with a very good data type library that describes the DOM in excellent detail.

Our_Benefactors

> What are you talking about with this talk of implosion? It sounds like boogieman nonsense from small children scared of the dark. I prefer to use vanilla JS when writing large SPAs and it works just fine.

It’s absolutely not and it absolutely doesn’t. Inheriting a VanillaJS project is often a nightmare because it screams “inexperienced developer” not to use a framework, so the code quality and build processes are often extremely low quality and undocumented.

simquat

A few years ago I rebuilt a 3D model checker for the building industry and intentionally avoided a full frontend framework to keep the UI performant.

I wrote a small internal mini-framework to follow the MVC pattern and Web Components for reusable elements. I also used external libraries: three.js for 3D rendering, sql.js for handling the 3d's models meta-data in a performant way, and @tanstack/virtual for virtualizing large lists and tables.

The biggest benefit was finer control over performance. The main downside was a less comfortable developer experience — it’s harder to find polished, ready-made vanilla-JavaScript components, so you implement more yourself.

ngc6677

1. web-components https://developer.mozilla.org/en-US/docs/Web/API/Web_compone...

2. router https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern...

The rest should be code organization, not even a build tool.

Can check this example https://github.com/radio4000/components

bob1029

Also, ES modules:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...

You basically have the same capability you have in python or other ecosystems if you can be bothered to attempt what the OP suggests. Determining an appropriate way to organize your code is actually a really hard problem to solve if you've been leaning on 3rd parties to solve it for you. It's definitely a skill worth developing. Once you have it you will begin to dislike the organizational suggestions of others because they'll never fit your problem as well as a hand tuned strategy.

gwbas1c

IMO: It's good to know how to manipulate the DOM directly. Any complicated web app will always hit some kind of corner case where you need to bypass your framework and manipulate an element. For example, the spinner that you see on https://manage.onopti.com/ is disabled with a pure DOM call once WASM + Blazor is started up.

That being said, as many other comments rightly point out, (for most projects,) if you work directly in the DOM you'll end up recreating what most frameworks do for you. It's really only "worth it" when you can strongly justify it: IE, if you're making a charting library that can handle thousands of datapoints, or a rich degree of interactivity that a usual business web site doesn't have.

But for a typical interactive website: Use whatever framework your peers at your company will be comfortable with.

sehugg

Spritemate is built with TypeScript + Vite + JQuery, and has a pretty organized structure: https://github.com/Esshahn/spritemate (I do not condone its use of the 'any' type everywhere tho)

I wouldn't use JQuery for a new project, as you can do almost everything it does with straight DOM manipulation. But there are still some strategic vanilla JS/TS packages that come in handy, e.g. clipboard, mousetrap, file-saver, split.js.

Web Components with Lit is kinda fun, though you'll have to deal with DOM shadow roots or disable them.

I would challenge that using a framework leads to less security. In vanilla JS you've got to use something like dompurify religiously to avoid XSS bugs, and you're tempted by the shiny candy-like innerHTML attribute.

thepianodan

Thanks for the reference! Yep, part of why I made this post is to see how I can avoid the innerHTML attribute. Do you think Obsidian's use of dompurify is closely related to their choice of going vanilla?

bestest

It depends on the target product.

I'm working with JS for already 25 years. Tried all of the frameworks, and continue on doing it. And every time I try something new, the refactoring flow turns most of them into NextJS (if it's very UI rich or customer facing or something very web-oriented), or Vite+React+Tailwind (client) and Hono (backend) if it's more of a tinker toy needing more custom solutions.

The boilerplate with NextJS is cleanest (compared to all the other frameworks) and API is the most straightforward one, and you can safely ignore the vendor lock in. Its just a pretext to hate on NextJS. They all have some kind of a "vendor" lock in. Be it a vendor-or-a-specific-approach-or-whatever-lock-in.

And Vite+React+Hono — simplest to set up for quick experiments, and very powerful with minimal boilerplate. Will probably create a starter for this one, as I have been using this stack quite a lot lately.

EDIT:

You can pretend vanilla JS is all you need, but then your app grows, then you suddenly need types, and state, and more events and their handlers, and SSR or something else. Thus React has been the most stable bet for quite a while for me now.

culi

> The boilerplate with NextJS is cleanest (compared to all the other frameworks) and API is the most straightforward one, and you can safely ignore the vendor lock in. Its just a pretext to hate on NextJS. They all have some kind of a "vendor" lock in. Be it a vendor-or-a-specific-approach-or-whatever-lock-in.

The vendor lock-in on NextJS is certainly much more egregious than other frameworks. They have their own undocumented build flag to give different build outputs that Vercel uses vs the build outputs that are documented. Hosting nextjs on your infrastructure is not as simple as sticking it into a docker file as with most frameworks

And I would also push back on the idea that every framework has vendor lock in. Remix was so focused on "using the platform" that it basically willed itself out of existence. It's no longer even a framework. Just part of the react-router library. I've also used Astro which is a framework of similar complexity and feature richness as Nextjs and certainly has no "lock in". At least as far as

TimTheTinker

I'm curious if you've tried Lit on the frontend, and if so, what you think about it.

bestest

I have tried it. And would like to reiterate – everyone should use what they like.

But for me Lit is too OOP. It feels like Angular. And that all in turn feels like Java. It's just so heavy and constrained (not saying it's a bad thing though). Too much boilerplate for me.

The whole paradigm is different and does not match my preferences. And while subjective, I do believe React with TS, Tailwind, zod, react-query and zustand is the best stack delivering the best balance of boilerplate and code-delivery and easy of use and entry level and dx.

brendanmc6

I've abandoned Next.js and React for Elixir / Phoenix. I am able to build a perfectly pleasant user experience with just a sprinkle of vanilla JS via Phoenix hooks.

The fact that I have been able to build a multi-user collaborative editor experience without a single additional dependency is incredible. I previously worked for a well-established and well-funded React team who had this feature on their roadmap for half a decade but still find it too daunting to implement.

Phoenix was a great reminder that a lot of the "frontend engineering" we find ourselves doing as React developers just isn't necessary with the right backend. It's HORRIFIC to look back at all the yakshaving I've done in my career already. Wrangling types (GraphQL, codegen libraries), wrangling queries and data-fetching (react-query, SWR, server components), fiddling with middleware (serverless functions, getStaticProps, CDNs). I've seen teams outright abandon testing because the hours they invested just weren't catching any of the bugs that mattered.

I'm not doing any of that anymore. I'm spending that time refining the core data model, improving test coverage, thinking about go-to-market and making money.

Phoenix may not be a good choice if your product has reached that level of maturity and product-market fit where you really should care about "microinteractions", fine-tuned animations, or advanced use-cases for an SPA like offline support and highly-optimistic UI. But I would argue that even mature products don't truly need these things. Just look at the GitHub UI. I've spent a truly astronomical number of hours in that UI and never wished I had WYSIWYG text editing, or animated skeleton UIs, or the dozen other things that the React community tells us we need.

juliend2

I'm curious what is specific to Phoenix that made this so productive for that project? Is the frontend using something like HTMX?

shawa_a_a

They're probably using some features of LiveView; I'm not too familiar with how HTMX works, but with LiveView you can define all of your logic and state handling on the _backend_, with page diffs pushed to the client over a websocket channel (all handled out of the box).

It comes with some tradeoffs compared to fully client-side state, but it's a really comfortable paradigm to program in, especially if you're not from a frontend background, and really clicks with the wider Elixir/Erlang problem solving approach.

https://hexdocs.pm/phoenix_live_view/js-interop.html#handlin...

Hooks let you do things like have your DOM update live, but then layer on some JS in response.

For example you could define a custom `<chart>` component, which is inserted into the DOM with `data-points=[...]`, and have a hook then 'hydrate' it with e.g. a D3 or VegaLite plot.

Since Phoenix/LiveView is handling the state, your JS needs only be concerned about that last-mile JS integration; no need to pair it with another virtual DOM / state management system.

https://hexdocs.pm/phoenix_live_view/js-interop.html#client-...

brendanmc6

The big win for me has been the built-in PubSub primitives plus LiveView. Since the backend is already maintaining a WebSocket connection with every client, it's trivial to push updates.

Here is an example. Imagine something like a multiplayer Google Forms editor that renders a list of drag-droppable cards. Below is a complete LiveView module that renders the cards, and subscribes to "card was deleted" and "cards were reordered" events.

```

  defmodule MyApp.ProjectLive.Edit do
    use MyApp, :live_view
    import MyApp.Components.Editor.Card

    def mount(%{"project_id" => id}, _session, socket) do
      # Subscribe view to project events
      Phoenix.PubSub.subscribe(MyApp.PubSub, "project:#{id}")
      project = MyApp.Projects.get_project(id)

      socket =
        socket
        |> assign(:project, project)
        |> assign(:cards_drag_handle_class, "CARD_DRAG_HANDLE")

      {:ok, socket}
    end

    def handle_info({:cards, :deleted, card_id}, socket) do
      # handle project events matching signature: `{:cards, :deleted, payload}`
      cards = Enum.reject(socket.assigns.project.cards, fn card -> card.id == card_id end)
      project = %{socket.assigns.project | cards: cards}
      socket = assign(socket, :project, project)
      # LiveView will diff and re-render automatically
      {:noreply, socket}
    end

    def handle_info({:cards, :reordered, card_change_list}, socket) do
      # omitted for brevity, same concept as above
      {:noreply, socket}
    end

    def render(assigns) do
      ~H"""
      <div>
        <h1>{@project.name}</h1>
        <div
          id="cards-drag-manager"
          phx-hook="DragDropMulti"
          data-handle-class-name={@cards_drag_handle_class}
          data-drop-event-name="reorder_cards"
          data-container-ids="cards-container"
        />
        <div class="space-y-4" id="cards-container">
          <.card
            :for={card <- @project.cards}
            card={card}
            cards_drag_handle_class={@cards_drag_handle_class}
          />
        </div>
      </div>
      """
    end
  end
```

What would this take in a React SPA? Well of course there are tons of great tools out there, like Cloud Firestore, Supabase Realtime, etc. But my app is just a vanilla postgres + phoenix monolith! And it's so much easier to test. Again, just using the built-in testing libraries.

For rich drag-drop (with drop shadows, auto-scroll, etc.) I inlined DragulaJS[1] which is ~1000 lines of vanilla .js. As a React dev I might have been tempted to `npm install` something like `react-beautiful-dnd`, which is 6-10x larger, (and is, I just learned, now deprecated by the maintainers!!)

The important question is, what have I sacrificed? The primary tradeoff is that the 'read your own writes' experience can feel sluggish if you are used to optimistic UI via React setState(). This is a hard one to stomach as a react dev. But Phoenix comes with GitHub-style viewport loading bars which is enough user enough feedback to be passable.

p.s. guess what Supabase Realtime is using under the hood[2] ;-)

[1] https://bevacqua.github.io/dragula/ [2] https://supabase.com/docs/guides/realtime/architecture

Daily Digest email

Get the top HN stories in your inbox every day.

Ask HN: How does one build large front end apps without a framework like React? - Hacker News