Ask HN: Help me pick a front-end framework
I'm thinking of building a text-annotation based app _alone in my spare time_. The core usage loop is about viewing and interacting with "visual markup" applied to a body of text. So lots of tooltips/hoverbars I guess.
Some notes about my needs:
- This would be by far the most complex GUI I've ever built.
- Relatedly, I expect to get the UX design horribly horribly wrong and start from scratch at least once.
- I also suck at making things look pretty and also don't find this problem very rewardinging to think or read about.
- All of the above point towards a framework that is pretty easy to get started in and prototype quickly.
- Because of limited time, and low confidence in UX design decisions, I would often follow the path of least resistance and the end product would be heavily influenced by the tools I used to build it.
----
- Despite what I said about quick rampup I'm fine with learning new languages.
- Weak typing is a deal-breaker. If using JS, must have good TypeScript integration or similar. (Does anyone still write plain JS?)
------
- I don't think I'll want a native desktop app but an iOS/Android version could make sense. But I'll never have time if this can't share most of the code with the web version.
-------
- I don't really have the discipline for manual testing. Luckily I also find it satisfying to over-invest in test automation. I don't really know how this is done in frontend land but good tooling would be a big plus.
-----
- I'm happy to sacrifice one or more of the other requirements in favour of tools that are likely to be maintained 10 years from now.
----
What are HNs thoughts?
180 comments
[ 2.4 ms ] story [ 224 ms ] thread"Well, let's say you can shave 10 seconds off of the boot time. Multiply that by five million users and thats 50 million seconds, every single day. Over a year, that's probably dozens of lifetimes. So if you make it boot ten seconds faster, you've saved a dozen lives. That's really worth it, don't you think?" [1]
[1]: https://www.folklore.org/StoryView.py?story=Saving_Lives.txt
You could find plain JS to be sufficient for this. I'm guess you're highlighting the text a popup will come up and you submit to a server?
If you really want to use a framework, Svelte could be a good choice. If you want to stay with safer choices then React with Mobx, or something else that uses subscriptions to bypass React's default rendering. The other thing you could do is test out each one and figure out what you like the best, because some of it is subjective.
MUI also can be slow if you put dynamic stuff in the sx component property. Tailwind has the very nice property that there's no dynamic CSS generation at runtime.
https://homechart.app/blog/tech-stack-ui/
Working alone, there is no easier setup than Laravel and (probably for you) Vue + Inertia. Vue is a major player with lots of available packages and it’s pretty simple to get setup with Laravel for a database and backend. If you need help getting started, Laracasts is unmatched in terms of tutorial quality.
The other path is to use React. If you think you want a job in front end development, spending time in react will broaden your eligible job set by a significant margin. I personally don’t like react, but it’s going to dominate front-end for the next five years at least.
Best of luck!
- TypeScript for language. Gives you an insanely expressive type system that is a step up from Python duck typing (which you seem familiar with after perusing your GH).
- React for framework. Frontend experts will shit on it for being non-performant or having a poor UX, but the community is massive and you'll have a ton of support both in terms of people that can help you when you're stuck and libraries that do a lot of work for you.
- Jest for code testing and Cypress for integration testing. The obvious tools for the job.
- Chakra UI for a UI framework. Has all the bells and whistles, DX is great, and there are plenty of escape hatches for non-default behavior.
- TipTap for text editor. This is the _most_ at risk of not being supported in 10 years, but I still see it as a low risk because they have a solid monetization strategy in place.
- Electron for the desktop app. If you _really_ don't want to use Electron then use Tauri (what we use at my company). It uses the native browser engine so package sizes are ridiculously small and it's insanely performant.
- Don't worry about the mobile apps for now. At the very most, just make it a web app that has responsive theming for mobile.
Good luck and have fun!
OP this is an interesting and rather niche area, you will want to be making use of the selection API[0] and figuring out a good way to make it reactive to integrate with react and your data model.
[0]: https://developer.mozilla.org/en-US/docs/Web/API/Selection
Also, look for React Testing Library to complement Jest.
1. I know GitHub stars aren't everything, but Playwright has 41.9k at the moment, and Cypress has 40.5k.
2. Playwright is backed by Microsoft, and given how happy I've been with how they manage Typescript, that makes it a pretty safe bet to me.
3. Cypress is much older, so I discount a lot of the blog posts in my evaluations. In fact, I count such things against it sometimes, because oftentimes when I'm hunting for a solution to a problem, all I can find are outdated answers. I run into this a lot with AngularJS and Angular.
4. Playwright is included in most of the recent comparison articles I've run across. I don't really keep track of these, but searching again I quickly ran across 2 examples:
TypeScript + React + a good UI library like Chakra will do most of the legwork for you.
For anything where you need to reach into the HTML/JS/CSS, find the right place in the React lifecycle (usually useEffect, useRef, and callbacks).
Prefer closures (I mean: small, local functions), strictly-typed TS interfaces, and async/await for everything. Avoid classes, fancy patterns, ORMs, function overloading, etc. Keep it simple.
Check out RunTypes for TypeScript. It will make moving data into & out of your codes breeze. Just JSON.stringy on one end and JSON.parse then MyRunType.check on the other end.
https://github.com/facebook/lexical
TS, in my experience, has limited benefit when it comes to building a UI, and frontend JS is heavily married to UI programming. For guaranteeing UI functionality, writing years is a better use of one's time. What's more important with UI development is the ability to change visual components fast, and TS often gets in the way of that because it's strict as a feature.
Someone who is deep into TS may have the experience such that they are an exception, and can really benefit from using TS across the board. Since the OP is asking for a frontend framework, I would not assume they are one of these exceptions.
Where TS really shines, IMO, is in business logic and library code, because that's where concrete expectations and promises typically lie. TS is also really good for writing backends for similar reasons.
This might be most appropriate for the OP:
Frontend: Some TS for logic that's well separated from the UI, but don't try to make TS work within code that is rendering stuff. Major frameworks put in lots of effort to support TS in the view layer and, with some exceptions, it usually comes with caveats
Tests: Use JS. Your tests should not be an app in and of itself.
Shared libraries: Use TS only if you prefer it or if other entities are using it, in which case TS helps your code fulfill it's promise to third parties.
And if the OP really ends up hating Typescript, then they should just not use it. TS is not a requirement.
I’m really not sure what problems you have in mind here. I’ve found TS to be really useful with very few caveats.
The biggest problem you’re likely to hit in TS is when things subtly lose their strong typing accidentally -- for example, you need to use some API that works with untyped JSON blobs. But the you’re no worse off than if you were just using plain JS in the first place.
TS is especially great when you’re using libraries with good type annotations -- your IDE can give you useful live typechecking and autocompletion, even if your own code is in JS!
In React code, TS is really good because you can statically check your prop types. There is a little bit of a learning curve to doing that both correctly and tersely, but I think it’s more than worth the effort.
As the OP specifically said they wanted strong typing, TS seems like an obvious choice over vanilla JS. I suppose you could consider other things like Flow or Reason, but TS is the most widely-used by far.
What problems specifically do you have with TS on the frontend?
For a beginner, my experience is that TS is a good way of discovering and working with the complexity and feature set of HTML and web browsers.
The benefits to using Typescript are immense.
- Install Yarn (package manager) - Run: yarn create react-app THE_NAME_OF_YOUR_APP --template typescript - start hacking
Every time people tell me "I just don't make type errors" I look through their issue tracker and find them everywhere.
Forcing you to be clear and explicit about types and handling cases where "undefined" could exist is a good thing.
It might take longer to develop but I've definitely seen I get fewer run time errors once it builds. No more staring at a blank page and checking the developer console for an undefined that's brought everything to a halt.
[1] https://github.com/arijs/vitesse-modular-naiveui
But my real advice is go kick the tyres. Try hello world in half a dozen candidates.
Take a thin vertical slice through your app, and try implementing in your short list of frameworks.
It will be worth the investment
React.
Never "how can I do the most maintainable code", "how can I write good code".
https://dev.to/jxxcarlson/making-an-elm-desktop-app-with-tau...
I also agree with other comments that you should postpone worrying about iOS/Android apps for now. Targeting those platforms adds a lot of complexity and will slow you down. So you should avoid them unless your app really only makes sense as a native mobile app.
If down the road you do decide that you want native mobile apps, I recommend using React Native with Expo. Transitioning from React to React Native is relatively easy (from a concepts perspective). But React Native doesn’t use HTML or real CSS (although it’s heavily inspired by it), so you will need to rewrite a lot of your code and change all of your dependencies over to React Native-compatible versions. With React Native, you can have a single code base that targets web, iOS and Android so you don’t need to maintain multiple versions of your code.
If you don’t like React Native for some reason (e.g., it’s made by Meta), you can also look into Flutter which is made by Google.
Unless your job is going to require a framework, it’s really not necessary.
Maybe I’m the old curmudgeon who is more concerned about putting out something that works and get customers/revenue quickly, than messing around with the latest Javascript toolchain to ensure it builds in Docker.
You csn get a ton done with Javascript and Tailwind or DaisyUI. In fact almost 90% of what you need.
And with the advent of new backend frameworks like Liveview that patch the dom, I believe things like Angular, React, Vue are on the dying list.
Respectfully disagree. Mirroring your state in the DOM on your own is incredibly easy to get wrong. Doesn't matter if it's react, svelte or vue, any such framework will greatly simplify the UI parts. Aside from that though, I agree you can (and probably should) avoid most deps.
I find it funny that people think mirroring the DOM will magically make your web app performant. I've visited plenty of React sites that are sluggish, bloated, load slowly and a pain to use. I've also visited plenty of plain ol' HTML/CSS/JS sites that are snappy, load quickly, and fast enough. No framework or clever algorithm will save you from crappy code ;)
I actually think vanilla JS / TS might be the best fit, here. You’ll probably be writing a lot of plain JS anyway based on my understanding of the description, so I’m not sure a framework buys you much.
I highly recommend Tailwind for CSS and Playwright for testing the real UI.
Angular with the Angular Material components library would be very "batteries-included". You don't have to decide how you store state, what testing framework to use, etc. Angular provides sane defaults for most things. And it also ticks your TypeScript requirement.
> Relatedly, I expect to get the UX design horribly horribly wrong and start from scratch at least once. I also suck at making things look pretty and also don't find this problem very rewardinging to think or read about.
With angular material, you'll get pre-built and pre-styled navigation menus, form inputs, etc. Wiring them up to your TypeScript code will be a breeze but it'll be tough to customize them if you're going for somewhat unique / unusual behavior or styling. And occasionally you'll need something commonplace like a time picker and the library won't have that.
> I don't think I'll want a native desktop app but an iOS/Android version could make sense.
The simplest route to putting your app in the app store / play store is called a Progressive Web App (PWA). For which you basically need a config json and some icons. The gotcha is that PWAs have virtually zero access to native features.
> I don't really have the discipline for manual testing. Luckily I also find it satisfying to over-invest in test automation. I don't really know how this is done in frontend land but good tooling would be a big plus.
Angular uses Jasmine by default for unit tests. You can test both the business logic and UI interactions this way, but in my experience mocking out components is annoying and a fuckton of maintenance. I usually stick with testing the logic or clumps of un-mocked components. There's also support for end-to-end tests using Protractor, but I'm not super familiar with it.
> I'm happy to sacrifice one or more of the other requirements in favour of tools that are likely to be maintained 10 years from now.
Angular will probably be around 10 years from now, but I doubt keeping the version / other dependency versions up-to-date will be painless. Some things are just kinda deprecated / replaced for lame reasons (but you'll have notice of these changes waaay in advance).
You don't have to make any more choices after picking angular - you are all set and everything not only works together perfectly complete with extensive documentation for the whole thing, but you also get a professionally maintained UI framework designed to work with it.
Compare with react which is just the first of many subsequent and continual choices you will need to keep on making as sub-frameworks come and go and need to be replaced as you maintain your app e.g. major security issue in foo 1.1 but you can't upgrade as it has a dependency on boo 1.2 that has not been updated so you need to switch to quux 0.9a but that changes how forms are handled so you need to refactor your apps routing, and that breaks your test framework etc, then someone deletes the leftpad repo and none of your dependencies work anymore anyway etc (oh and by the way your NPM install is out of date too so upgrade that first). Then factor in fighting with NPM & node, dealing with separate documentation for different sub-frameworks, your effort and sanity from trying to integrate them etc. I am perplexed as to why anyone would pick react for anything apart from the most trivial of UIs - it is a nightmare.
Angular will be around for a long time - it is used extensively in enterprise environments and Google.are throwing SWEs at it even if the vocal cool kids are using react or Vue or whatever.
Source: I maintain a complex Angular SPA since AngularJS/2.
I find it quite straight forward to use once you overcome the somewhat steep learning curve.
* Must maintain a deep understanding of RxJS, which is its own beast. Angular team sometimes uses it in "creative" ways that change between versions in creative ways.
* Must not go off reservation (or do) where the Angular code is committed but not covered by documentation (because reasons). Template variables (hack an ngIf into an ngVar) come to mind, as well as how not subclass an abstract component (e.g. abstract component can technically have its own template and interesting things happen when children also have their own templates).
* Must understand how Angular i18n works by inspecting various Angular code repositories (and sometimes having to build the Angular project yourself, inadvertently discovering the "wonders" of Bazel). For example, the list of Angular supported locales is generated from CLDR dumps. CLDR likes to release new dumps and so the list of Angular supported locales changes (sometimes). You can think of interview Angular questions from hell such as what is the default build locale and what happens if you change it to "en-US-POSIX"? Or, my current favorite, how to ask Angular put dir="rtl" into the generated index.html for locales that are RTL?
These are just off the top of my head. I didn't even go into various performance optimization techniques which may or may not be made redundant by the next version of Angular because of their own compiler optimizations. Also, having to make the decision of the E2E testing solution (or sticking with Protractor).
I too would like to hear about what complexities you are encountering and if they are incidental or necessary complexities.
This reads like too much cool aid.
Angular is an entirely application stack, “choices made for you”. uses dependency injection out of the box, has a complex module system (eg. How you used to have import Material components one by one). It’s observables all the way down.
How can you argue that’s not complex? It’s super complex.
I mean, let’s just take an example, say, making a library… https://angular.io/guide/creating-libraries
Now let’s look at https://kit.svelte.dev/docs/packaging
Quite the difference.
I’m a modest fan of angular because it produces good stuff… but not because it’s simple or easy to learn.
You get good solid engineering outcomes with it.
Huh?
Lots been done in this space — what are you still missing?
There's a lot of criteria in the original question, which will inexorably lead you to React.
But for learning fast from scratch and doing lots of iteration and rewrites on a very complex UI, Svelte is going to provide a leg up.
The biggest issue is finding a UI library you are happy with, and dealing with inevitable Sveltekit changes. I used tailwind and it integrates ok with Svelte. And I've just resigned myself to dealing with Sveltekit updates.
- Typescript
- React
- styled-components (I've heard good things about tailwindcss too)
- Jest and react-testing-library for testing
- prettier and eslint for linting
Just throwing it out there in case you'd like to share your code between web, desktop and mobile:
- Electron (desktop)
- React-Native (mobile)
- React-native-web (to bridge it all together)
- C# can be used for all code, frontend and backend.
- Several GUI frameworks/toolkits to choose from (mudblazor, radzen etc)
- Cross-platform
- High quality development tools from several providers
- Code can later be reused in native applications for most platforms
- Lots of documentation and tutorials available.
The main factor that might make or break it for your usecase is whether it supports the kind of advanced text layout you might need.