Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
TodoMVC App Written in Vanilla JavaScript (github.com/1marc)
152 points by thm on May 7, 2022 | hide | past | favorite | 109 comments


How many people who are critical of the current state of JS actually use it on a daily basis? Modern frameworks like React and Vue don't exist to fill in the gap left by native JS, they exist so that you write your application in a declarative way where the view is rendered as a function of state. This relieves the developer of keeping track of DOM state, as you only declare the render function once, and after that you only need to manage state.

If anything, modern frameworks tend to build as much upon the native functionality that is available. This reduces bundle sizes and increases performance. It's an abstraction on top of the browser capabilities, not a clone.

Now, onto the code itself. The author claims it is "pretty simple" to build "fairly complex things". He backs up the claim by stating it took only 60 minutes to write this app.

First, I would be careful to claim things are easy or difficult. This is very subjective, and phrased in the wrong way it can also come across as arrogant.

Second, the app is not simple. Looking at the code the author created his own DOM abstraction. The current abstraction is only proven to work for a simple to do app.

Third, a to do app is not a "complex thing". Not even remotely.

It's a nice exercise, but the conclusion drawn by the author aren't valid.


> React and Vue [...] exist so that you write your application in a declarative way where the view is rendered as a function of state

Exactly. To elaborate, here's the big, big caveat in a miniature form:

https://github.com/1Marc/todomvc-vanillajs-2022/blob/854dd40...

Note that this clears and recreates the DOM on every action (eg mark complete), and DOM ops are the most expensive ones. This is a sound strategy for vanilla JS, because the alternative is mutating the DOM and keeping it in sync which is error prone to put it mildly.

I use frameworks very sparingly, and am always cautious with deps. But a reactive UI/diff engine is non-negotiable for me.


This relieves the developer of keeping track of DOM state, as you only declare the render function once

A good part.

and after that you only need to manage state

A part where to change a[n].b.c:

React: you either split into unhealthy number of “components”, which are never reused and require tons of pass-through, or only manage state as a sequence of unnatural to js “reduce” operations.

Vue: give away your data to Vue, because once it hits `.data` it gets charged with properties incompatible with the entirety of js language.

Vue is essentially a separate programming language, which somehow managed to sell the manual transpilation to its users. React did the same being Haskell-like variant. The “upon native functionality” of this is equivalent to python3.dll being upon a native functionality of C++.

Most of your points still valid, I only wanted to unfold that “only manage state” bit. It’s sad that libraries like Mithril aren’t the default, and instead monstrosities like React are.


You have to manage state within the rules of the framework, that's true. But the hard part of programming usually isn't syntax. Who cares if it's a different language/paradigm? It's a simple language and I only have to say a few words. It's still orders of magnitude less complex (this is not an exaggeration) than rolling your own framework with vanilla JS.

I would encourage you to find out why React is popular and why Mithril isn't on the assumption that the world isn't crazy.


Are you familiar with both? Finding out why React is popular is a hard task because every article starts with comparing it to jQuery and usually ends there. I’d like to learn from the relevant side, not from the one centered around some obvious strawman. A link or just few words, I would really appreciate it.


Yep, you nailed it. I've been looking at low-JS and vanilla JS again recently given the amount of hype around these kinds of frameworks (and the perceived maturity of the browser).

It still has the same problems you describe. You worded it way more eloquently than I can.


Yeah, that's exactly what I would imagine vanilla js code look like, and I'm glad we moved on to frameworks. Just this small app seems not so fun to maintain


Yep, it’s a really nice demo for how to use JavaScript. But it’s not a valid criticism of Vue, React, Svelte because it’s solving a very simple problem. The reason for those frameworks becomes clear when you have multiple people maintaining it and adding features.


I’m sorry but this is not a fairly complex app. When things do get more complex (and not even that much) is when you start hitting problems. How would you reuse a “component”? Among many other things.

I honestly don’t know if that’s the point of the author but I would agree that many framework are too heavy, but honestly there so many good compromises today that don’t make you re-invent the wheel and fix bugs that have been have been fixed millions of times before.

Going against good abstractions as developers seems to go against the most powerful tool we’ve got.


It's a good way for people to revisit the current status quo and avoiding cargo cult. Frameworks are useful, but there's definitely an element of cargo cutting going on in the JS ecosystem whereby no matter what the requirements, you just reach for React/Vue. We're getting to a point where almost nothing that uses JS gets built without a frontend framework (and all its weight) anymore.

One thing that's easy to notice from reading the code is that so much of the code takes inspiration from the frameworks themselves. How the code is organised - the state store, the render function, the computed getters, the mutation methods, it's all there. It's clean.

Perhaps the main benefit of frameworks is that they've taught a whole generation of JS developers how to organise their code in a way that can scale to bigger, more complex apps (vs. how easy to make a mess of things in the jQuery days).

-

Having said that, I do agree with your point about things getting more complex: This is a properly specced, easy to grasp project. Throw in stakeholders and PMs needing to add functionality and requirements changing, and this system might start to struggle. Not to mention the cost of onboarding new developers. I feel like that's the best thing about frameworks in any language; when you jump into a new project you know more or less how everything is organised and where things are supposed to be, and you can get going fairly quickly.


Building on your comment, frameworks have described themselves as “polyfills”. Polyfills used to be libraries that added modern browser features to old browsers. Then, Angular and React began using polyfills to add future features to modern browsers. The intent was always communicated as “some day we won’t need this because it’s built in to HTML5 and when that happens your initial payload will be smaller”. Typescript has had similar effect on JavaScript language features and syntax.

This rewrite of the Vanilla JS TodoMVC is a great illustration of how far things have come.


> How would you reuse a "component"?

Save the element template as a string and set innerhtml of a div as that?

> compromises today that don’t make you re-invent the wheel

Yeah but there's also no need to include jQuery and bog down your site with piles of code you won't ever call just because you don't know how to use the native api like a normal person. React/Angular/whatever are just the latest fad of that mindset, big team corporate ease of use aside.


What happens when you need to update some deeply nested child element without re-rendering the whole tree? Suddenly you need some system of labeling the children, how to find them in the dom, how to update them, how to keep them in sync with the state... a vanilla JS solution becomes extremely unwieldy as soon as you step out of the "global pointers to elements" phase (what the project in the OP is). Lit-html is an example of a tool that solves this problem in tiny package- less than 1KB- and you can continue using string templates with that.


I mean speaking for myself, I mostly make robotics web apps which isn't the most typical of web applications but the times this sort of thing is needed are few and far between.

So yes, this pattern is helpful for solving that sort of thing when it occurs (and if the use case is even substantial enough to warrant it) and Lit looks like it would fit that role reasonably well, but basing the entire site on this principle as a full on framework seems a bit ludicrous.

What html actually lacks is the option to include external html part files, but there are lots of ways to do that serverside that don't involve the stupid idea of putting html into strings in js files for literally everything.


Oh, hey! This is from the founder of Frontend Masters – easily the best FE resource I've ever found: https://frontendmasters.com/. Their content creation process is pretty nifty: they run live workshops regularly that subscribers can join, and the footage from the workshops ultimately gets cut and turned into the tutorials.

Had no idea who was behind it, but I love that they're still contributing back like this.


Ah, thanks for the plug!! I did this as a fun little weekend project, glad people are finding it useful as a reference of how simple vanilla JS can be these days. :-)


My app CardBoard (https://www.cardboard.team/) is no-framework vanilla js. This is a large-ish codebase with a lot of functionality, and the same code is wrapped with apache cordova for both iOS and Android apps. In 2022, browser-native WebComponents (addresses encapsulation, code organization, and re-use) with no frameworks is a hill I'd die on.


I wrote a TodoMVC App with React, Redux and SSR that works without JS enabled in the browser a while back, for those interested in that sort of thing :)

Demo: https://todo-react-redux-noscript.herokuapp.com/

Repo: https://github.com/wishy-gift/todo-react-redux-noscript/

Talk (updated framework): https://m.youtube.com/watch?v=3yY-Z-X3xE4

Helpers to do your own stuff: https://www.npmjs.com/package/@wishy-gift/noscript


Thanks for sharing this. I have to admit, this is an absurd amount of code for a todo app. Is there a specific goal you had in mind when creating this? Are you trying to show the capabilities of SSR (or maybe Redux)?


A good exercise, well executed.

While I would rather nail my bollocks to the ceiling than build a vanilla application (in any stack), there’s no denying the benefit revisiting the basics.


The thing I enjoy about frameworks like React is the declarative nature of the UIs.

I'd love to not be able to use them and to create complex UIs in pure JavaScript but it always ends up being painful where you spend more time optimising the rendering than doing any work.

In simple apps I will write UI in a functional matter in pure JavaScript, regardless of the performance implications. But bigger DOM means worse performance with this method.

When will we get to the point where we can tell the browser what we want the DOM to look like and then the browser does the diffing like a framework would?


There’s absolutely no way you’ll have worse performance with this vs React. The app is modifying the target elements directly, not recreating the whole page with innerHTML. React will do the same amount of work at a minimum, and that’s after rebuilding the whole tree and diffing it.

The main bottleneck here are the synchronous localStorage calls happening in the render path, they could be moved to a separate timer.


It seems like you didnt actually look at the code because thats exactly what its doing: https://github.com/1Marc/todomvc-vanillajs-2022/blob/main/js... it clears innerHTML there and then rerenders the children


Right but proper manual dom is generally faster than optimized react code. That does not means that in general manual dom code is proper.


I did this style to mimick modern framework code — taking the state (todos) and render the state of the world every time. If the browser had a DOM diffing api this would be more efficient and we would be there. So for a larger project I might using something like Lit’s html stand-alone package or fastdom to get the DOM digging functionality without much dependency code.


You’re right, I did a quick reading and thought it was updating elements one by one.

I still suspect this might be faster than React anyway. Would be interesting to try.


> There’s absolutely no way you’ll have worse performance with this vs React.

It's normal to get much worse performance than React if you layout thrash and it's very easy to layout thrash without batched updates. There's overhead in the vdom but getting all the updates batched tends to be a performance win in any decent sized app. This was an active area of library exploration/development in the 2008-2012 timeframe but the only framework actively promoting it was Sencha IIRC.


I never suggested you'd have worse performance. But it's not declarative, it's tedious.

Read my comment again.


One way React can be faster than hand-written code is by batching all dom manipulation into animation frames.


The rendering code here is already batched since everything happens within a single render() call. And unless you’re using react fiber, its rendering is also synchronous.


Handwritten JS could also batch DOM manipulation (without the need for virtual dom comparison).



Ooo fastdom looks great! Thanks for the link.



Echoes of Alan Kay's recent comment on how software devs are way too concerned with the how the computer works to the detriment of what the software is supposed to do.


Yup. The reality is that programmer time is far far more expensive than compute time. And as long as that's the case, increasing levels of abstraction are our only hope at building complex software.


Programmer time is more important than their computer time, sure. Not sure that programmer time is always more expensive than the compute time of all the users of the software added up.


Yep because software devs is in the business of making money, while Alan Kay is in the business of smugly commenting from the side lines. He has very little understanding on what matters in the commercial world of software.


The battle is fought over performance and size, I think that's exactly what the user wants.


I don’t think the typical user cares about size.


I agree. In over 20 years I've never had a single user ask or complain about the size of the app. They have let me know when there was something not working right though.


People definitely notice speed and performance. They won’t complain about it generally, sure… but there’s plenty of data and case studies on the fact that users care https://nitropack.io/blog/post/web-performance-matters-case-...


>People definitely notice speed and performance.

There's sort of a "Maslow's Hierarchy of User Needs" that exists in software though. So long as the user can do something, and their immediate needs are met, performance concerns are just a small annoyance. And generally they will continue to ask for more features rather than performance improvements as long as the app remains usable.


Well then you've never seen poor people uninstalling apps from their cheap smartphones because they need to install and use a different one ;-) that you don't see it doesn't mean it's not there


it sounds sort of wild to expect there to be diffing! why do you have to generate a whole copy of the stuff instead of just telling the browser what changes to make? bonus: the existing apis instead of one that don't exist yet.


Because it can be automated? Every app that doesn't do this is just implementing the diff by hand, e.g. on this event delete this element, update this element, add CSS class to this element, etc. When the UI gets complicated you have to maintain this all yourself and it's a pain. Multiple event listeners between components to say something has happened.

It makes sense to be able to describe what you want to achieve and to let the browser determine how to get there in the most efficient way.

If the browser could do this it would make a tonne of JS code so much simpler. There's a lot that goes into making sure that there's no unnecessary DOM updates because it's just slow.

I don't write assembly and move things between registers by hand, I write a function and the compiler decides the most efficient way of doing it. UI should be the same way, I say what I want to happen and the browser decides how to get there.


Yes, but there are ways to accomplish this automation without diffing. Svelte does this by statically wiring up the data dependencies in your app when it builds, and then at runtime making exactly the changes to the DOM that it needs to based on the information it had at build time. No need to diff.


The point is that A) that's a framework and B) that requires you to compile Svelte files.

If you want to write declarative UI in pure JS then you need the browser to do these DOM optimisations for you, and diffing the changes is the way to do that.


> When the UI gets complicated you have to maintain this all yourself and it's a pain

This is also something that can be automated by a framework. Check out https://svelte.dev/blog/virtual-dom-is-pure-overhead


Yes... but that's the exact argument I'm making here. Unless you want to go through that pain, you need a framework.

Whether that's Svelte without a VDOM or React with a VDOM. The entire point of these frameworks is that you can write complex UI in a declarative way. They both exist because writing it declaratively in pure JS leads to performance issues. But there's nothing stopping the browser implementing something that does this optimisation for you.


I find the "pain" to be drastically overstated. See this HN post.


I mean, it’s clear that with a single view, it’s possible to manage this without too much trouble. But next to no apps are single views. And any project that has multiple people working on it is going to have multiple views and features which all interact in interesting ways. It’s definitely not overstated. Try writing a moderately involved app yourself in plain JS! It does get to be a pain, I’ve done it! By the time you finish, you’ll have likely created some level of abstractions, and invented yourself a nice new JS framework for yourself ;)


Diffing seems necessary when your UI gets complicated to the level that a small change requires a full page re-render. However, I don't think this is necessary for at least 95% of the websites on the internet.


Diffing is exactly what you need to do (barring newer methods like svelte) to figure out what to tell the browser to change. The vdom tree is much faster to manipulate than DOM nodes.


But you can't see those changes until the actual DOM changes as well. It's only because of react's insistence that mutation is evil that this became a problem. You could just directly update the thing you wanted to and just skip the whole diff thing.


No, the reason React has a VDOM is because the DOM is slow to update, compared to manipulating javascript objects. It's worthwhile to calculate the list of minimum updates ahead of time rather than using the DOM as the source of truth.

Not sure where you think mutation comes into play here, that's an orthogonal concern—you can have an API that mutates some internal representation of a VDOM, and it's still faster than manipulating the DOM directly.


In order to achieve immutability, large chunks of state have to be cloned whenever a single value changes. This sometimes causes a whole new DOM node to be created during reconciliation. React encourages you not to think about it too much. But some nodes can't be replaced. Like canvas or anything contentEditable. It's not orthogonal. It's a direct consequence of the design philosophy.


Cases where "UI should be a function of state" seem like a small sliver of all use cases. Probably not worth the complexity for implementing directly in the browser. And there are plenty of conditions that just prohibit the pattern entirely as far as I can tell. Things where referential stability matters, like you have a contentEditable or allow arbitrary edits on a canvas.


> Cases where "UI should be a function of state" seem like a small sliver of all use cases.

Maybe not “should”, but it’s an incredibly helpful mental model, and I can think of very few cases it can’t model correctly. It’s so helpful a model that it’s gained traction in Rust, Swift, Kotlin, Dart, Go. It’s the ~only model in Clojure and and literally the foundation of Elm.

None of these cases, AFAIK, apply the model literally when they interface with inherently imperative APIs. They provide APIs expressing the model, and manage the imperative behavior on your behalf. This is ultimately how all functions in meaningful programming work. At the end of the day, allocating memory or displaying output is a side effect.

This is also how you can have custom renderers like those used in ink, three-solid, even React Native. The code is modeled as a declarative function of state, implemented as a set of imperative behaviors corresponding to state and dependency changes.

I’ve worked on contentEditable solutions in the past, probably more than most people who didn’t ultimately produce a library from the work (I went mad, literally angry at the complexity of making it a good UX, and gave up). I hope I never have that task again, but if I do… you can bet your ass I’d use a function of state model. It’s the only way I could reason about the problem without going mad.


Personally I would argue that UI should always be a function of state. When it isn’t, you open yourself up to all sorts of inconsistencies and difficult edge cases. Of course, it’s not always that easy; having two sources for said UI (the HTML document itself and the JavaScript within it) certainly complicates matters.


For what it’s worth, even using “vanilla” JS it’s generally much easier than it’s made out to be. It requires design discipline and knowing ahead of time what discipline to apply. But it’s pretty simple once you know it:

- the UI isn’t a source of truth, it’s a computed interface to it

- changes/interactions in the UI should update the source of truth, not other parts of the UI

- the source of truth is fully responsible for managing and notifying dependencies of relevant changes

Or much shorter: state and presentation are separate concerns. Once you have that, you can focus on the actual problems you’re trying to solve rather than the ones created by crossing underlying technology boundaries.


i agree it's up to the browsers chromium , Safari , and Firefox to do the diff. But we might need a new meta tag or change to the Fetch API to tell them this html page should only update the elements that are different.

Remember <meta http-equiv="refresh" content="5"> .

It was discouraged because the back button broke. If you're developing a single page react app, I don't think you care about the back button.


> If you're developing a single page react app, I don't think you care about the back button.

You should though. One easy way is to use react-router. e.g. going to /profile renders the Profile component. Then navigating to /dashboard renders the Dashboard component. Pressing the back button will take you to /profile.

Another pet peeve of mine is people using internal react state when they should just use path or query params to make it transparent and easily sharable.


> If you're developing a single page react app, I don't think you care about the back button.

Your users likely do, so you should too.


The primitives of fine grained reactive programming seem to me more amenable to be implemented by the browser than react-style whole world diffing


This code reminds me of Backbone. I think we all started here and then abstracted event handling and reactivity into a tiny framework like Backbone.

React and other declarative approaches are inherently different. In React I hardly think of when my component renders. In Backbone days, I remember having to debug why some part of code is not running when I'm expecting it to run. React does this really well.


A cool thing about react is that it’s easy to reason about as well. The reconciliation algorithm is fundamentally pretty simple and there isn’t any magic happening.

It can get confusing to track down unexpected renders when you think the result of the algorithm should be different, but that’s not really an issue with react so much a the nature of managing complex state, memoization algorithms which potentially use different diffing strategies, and logic which might be mutating state in ways you don’t quite expect, and so on.

People criticize these front end libraries but I’m still impressed by how well state management has been integrated into such extensible and scalable view layers.


The code here is clean, well written and honestly not that much more verbose than many of the framework ones. I also found it simple to understand.

Would you need a “framework” when an app gets beyond TODO? I think you would need to start refactoring your code to be more framwork-like. But this is something we don’t do, and I would say would even be considered “anti-pattern”.


My bet is that as soon as someone popularizes a way to manage state across a set of web components the pendulum will swing back to the “Vanilla JS” approach. It’s so nice to work on web apps without having to install NodeJS, builders, cli tools, and so on. And it encourages software engineers to learn the web platform APIs instead of learning frameworks.

HTML and CSS are actually quite nice to work with, given modern browser developer tools. Much simpler to work with when they are literal files.

It wouldn’t surprise me if people continue to compile other languages to JavaScript or WASM though. It seems reasonable a Java developer might like to work in Java or a Ruby developer in Ruby instead of writing JavaScript. But I don’t understand how people feel confident writing web applications if they don’t take the time to understand CSS, HTML, or the browser APIs.


Nice! I was going to suggest the usage of Trusted Types API [0] to escape HTML [1], but support [2] for modern browsers is not there yet, specifically for HTML.

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

1: https://github.com/1Marc/todomvc-vanillajs-2022/blob/1c31309...

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


Cool! I'll look into the API and consider adding it to this implementation. Or happily would take a look at a PR for it.


Seriously- just do the innerHTML assignment on li.innerHTML omitting the title, followed up by a simple li.querySelector().textContent = todo.title.



How do we get 31 comments but not a single one on why this solution is subpar?

The entire TODO list is rendered anytime a single item is changed/removed/added. The biggest thing frameworks give us is fast, differential DOM updates.

Once browsers add differential update APIs, then we can kiss React and all the other players goodbye :-)


I mean... You aren't wrong, but the amount of data that fits on a typical page is usually such that the speed of a full refresh probably shouldn't be that big of a deal.


Now add 500 more features and 10 engineers and see if it scales. Hint: it doesn’t. Sure you can make it work, but as someone who regularly makes FE decisions for a team, I wouldn’t want to impose vanilla on them.

What I will say is it’s tough. I don’t like the idea of react at this point. I like building products that don’t need something heavy like react/redux.

I recently launched https://lists.sh to scratch that no js itch. It was a ton of fun and I want to chase that feeling.

But building a web app is what businesses want. And while you could make vanilla js work, you’d be reinventing a lot of tooling to get you there.


Also:

- add time constraints, where you need to implement widgets that you could source from a JS framework ecosystem otherwise.

- in your 10 engineers, make it 5 juniors, 2 interns and 3 seniors comming from PHP, and make sure they write all the code in the same style, follow a congruent architecture, can find solutions to common problem, get easy onboarding, etc.

- request sub-routing, off-line mode, notifications, content udpated by multiple users and so on.

- put a big table in there with 10000 rows and ask your team it renders fast.


With some patterns they can follow, vanilla js does indeed scale so well that it becomes boring. There’s no longer any code to rewrite for the latest and greatest frameworks. No dependencies to manage. It just becomes almost too easy at some point, at least in my experience with many projects I’ve led.

I’ve made millions and millions for major brands, including my own company, and customers go “wow how is your site so fast!!” All. The. Time.

The biggest pressure I’ve found is from the engineers themselves. Not all engineers like to go counter culture and learn browser APIs and JavaScript. They would simply like to use what everyone else is using. They tend to argue against vanilla using canned arguments read off of framework websites that don’t apply much or aren’t even problems in the actual codebase.

:shrug:


I like the "const TodoStore = class extends EventTarget" idea to trigger rendering... neat trick!


I noticed that, where does one even find EventTarget in the docs/references? I feel a bit behind on built in apis…


Vanilla JavaScript feels like jQuery now. Doing this was quite awkward in ECMAScript 3 and 5.

> App.$.filters.querySelectorAll('a').forEach(el => el.classList.remove('selected'));


I wrote a video editor in vanilla JS https://github.com/bwasti/mebm


Please do not re-implement HTML sanitization. Just replace that escapeForHTML and innerHTML assignment with a later textContent assignment. Please. Pretty please.


That seems like a good improvement. Pull requests welcome!



FWIW TodoMVC does list a vanilla JS implem: https://todomvc.com/examples/vanillajs/

It's older though (seems to have been first written 6 years ago) and has significantly more code.


I get this running it in chrome

  Uncaught SyntaxError: Missing initializer in const declaration (at helpers.js:4:14)
Installed and ran with:

  npm install
  npm run start
Any idea what went wrong...?


The assignment (=) is missing from those const declarations, except for the first one; I guess they were hastily converted from function declarations to satisfy modern tastes.


Oops, yeah I just accepted a pull request from the community that broke my helpers module declarations. Just fixed it, thanks for noticing!


Thanks for sorting it.


Wouldn't this have loads of memory leaks from never removing the event listeners when the todo elements go away?

I think it hides the complexity by pretending that's not a problem


The event listeners get cleaned up by the GC. At least in modern browsers.

While events aren’t explicitly mentioned, MDN offers an insightful read:

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

Alternately, one can use event delegation [0]. As does React under the hood [1].

0 - https://javascript.info/event-delegation

1 - https://reactjs.org/blog/2020/08/10/react-v17-rc.html#change...


I think there's a reason why events are not mentioned in your linked document... The reference is maintained in memory because the browser has no idea if you will be using it again. After creating the listener, you may very well append it to another element later for all the browser knows.

Also the browser doesn't make a distinction to the type of event (such as `click` ), and say "Oh well you can't click on an element not in the DOM, I think I can clean this up"

So no it will not clean it up and it will leak memory, see for yourself


Here's what I came up with for switching to event delegation: https://github.com/1Marc/todomvc-vanillajs-2022/blob/event-d...


Also it does not work properly when it is used in more then one browser tab.


Here's what it would look like to support that usecase: https://github.com/1Marc/todomvc-vanillajs-2022/commit/09979...


It would be a different demo, but this could be made fairly modern with some lightweight tooling and dependencies:

- Use esbuild to bundle the app. - Now you can change the file extension and switch to Typescript. (Esbuild doesn't check the types, but VS Code will.) - Then change the file extension to tsx and use Preact.

I'm writing a little app this way and it seems quite nice. I don't think I'm missing anything?


Agreed, esbuild is nice. And adding TypeScript at some type of scale probably makes sense. Not sure where that line is, but in this simple example I’m trying to avoid all external tools.


Hey! This is really awesome. I'm building my own SPA in vanilla js, and I'm definitely stealing some ideas here. I think a lot of people here see the resurgence of vanilla js as a repudiation of their favorite framework. There's a definitely a time and a place for both, and it's never bad to take a break and revisit the basics


Thank you! Agreed!


For me, the biggest issue with using vanilla JS is the lack of guardrails.

Before even considering something like this I’d want to see a style guide and clear definition of where code should live. Frameworks like React do that well. I can expect a random React dev to mostly do similar things.


> I can expect a random React dev to mostly do similar things.

This has not been my experience. Even experienced software devs will differ stylistically, but intermediate devs often come up with very different ideas about how things ought to work. I suspect this is due to wide variance in awareness of different libraries/platform features/stylistic patterns/etc, a consequence of being in a relatively unregulated industry.

I have worked for companies using React since 2014 and no 2 projects have had the same layout. My current and previous employers have had the closest codebases, but only in terms of directory structure, and even now the current one is changing to become quite different (in a way I think is good, but only time will tell).


I once wrote a Twitter clone in Vanilla JS, just for the sake of it.

I'm glad we have frameworks.


I'm impressed this took an hour and a half. Is this the kind of timeframe someone should be able to throw something together in?


Why is there HTML inside the JavaScript? Doesn't that defy the entire point of the MVC pattern?


That’s a misunderstanding of MVC - it’s a design pattern that’s language agnostic, not a declaration that HTML needs to live separately from JavaScript. The view logic in JS lives separately from the model logic in JS lives separately from controller etc.


React people think it doesn't, and apparently that is what everyone should be using...


Looks well made, code is pretty good, but why the archaic form of JavaScript other than the import statements? There's a lot of well supported syntactic sugar that would make it much easier on the eye. I also wouldn't bother with the IIFE.


Very interesting but quite verbose for the render




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: