12 ms·
TodoMVC App Written in Vanilla JavaScript
- norswap 4y agoFWIW TodoMVC does list a vanilla JS implem: https://todomvc.com/examples/vanillajs/ https://todomvc.com/examples/vanillajs/ It's older though (seems to have been first written 6 years ago) and has significantly more code.
- simooooo 4y agoVery interesting but quite verbose for the render
- brrrrrm 4y agoI wrote a video editor in vanilla JS https://github.com/bwasti/mebm https://github.com/bwasti/mebm
- gherkinnn 4y agoA 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.
- Trufa 4y agoI’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.
- moreira 4y agoIt'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.
- mch82 4y agoBuilding 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.
- moffkalast 4y ago> 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.
- wildrhythms 4y agoWhat 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.
- moffkalast 4y agoI 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.
- krembanan 4y agoYeah, 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
- blowski 4y agoYep, 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.
- deleted 4y ago[deleted]
- listless 4y agoThe 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”.
- mch82 4y agoMy 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.
- Philip-J-Fry 4y agoThe 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?
- kgbcia 4y agoi 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.
- creakingstairs 4y ago> 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.
- alserio 4y agoThe primitives of fine grained reactive programming seem to me more amenable to be implemented by the browser than react-style whole world diffing
- nkrisc 4y ago> 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.
- wackget 4y agoWhy is there HTML inside the JavaScript? Doesn't that defy the entire point of the MVC pattern?
- pjmlp 4y agoReact people think it doesn't, and apparently that is what everyone should be using...
- dymk 4y agoThat’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.
- mrspeaker 4y agoI like the "const TodoStore = class extends EventTarget" idea to trigger rendering... neat trick!
- telagraphic 4y agoI noticed that, where does one even find EventTarget in the docs/references? I feel a bit behind on built in apis…
- ravenstine 4y agoLooks 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.
- cehrlich 4y agoI once wrote a Twitter clone in Vanilla JS, just for the sake of it. I'm glad we have frameworks.
- arriu 4y agoFor 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.
- notduncansmith 4y ago> 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).
- ericsilly 4y agoMy app CardBoard (https://www.cardboard.team/ 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.
- goldenkey 4y agoHow 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 :-)
- danielskogly 4y agoI 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/ https://todo-react-redux-noscript.herokuapp.com/ Repo: https://github.com/wishy-gift/todo-react-redux-noscript/ https://github.com/wishy-gift/todo-react-redux-noscript/ Talk (updated framework): https://m.youtube.com/watch?v=3yY-Z-X3xE4 https://m.youtube.com/watch?v=3yY-Z-X3xE4 Helpers to do your own stuff: https://www.npmjs.com/package/@wishy-gift/noscript https://www.npmjs.com/package/@wishy-gift/noscript
- dimgl 4y agoThanks 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)?
- ghubcoder 4y agoI 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...?
- ricardobeat 4y agoThe 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.
- lelandfe 4y agoOh, hey! This is from the founder of Frontend Masters – easily the best FE resource I've ever found: https://frontendmasters.com/ 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.
- grabanski 4y agoAh, 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. :-)
- oblak 4y ago
- deleted 4y ago[deleted]
- rickstanley 4y agoNice! 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_Types_API https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Typ... 1: https://github.com/1Marc/todomvc-vanillajs-2022/blob/1c31309be3cf64936418d60539b8cbf4eab78dc3/js/helpers.js#L4-L10 https://github.com/1Marc/todomvc-vanillajs-2022/blob/1c31309... 2: https://developer.mozilla.org/en-US/docs/Web/API/TrustedHTML#browser_compatibility https://developer.mozilla.org/en-US/docs/Web/API/TrustedHTML...
- grabanski 4y agoCool! I'll look into the API and consider adding it to this implementation. Or happily would take a look at a PR for it.
- randomfool 4y agoSeriously- just do the innerHTML assignment on li.innerHTML omitting the title, followed up by a simple li.querySelector().textContent = todo.title.
- grabanski 4y agoHow does this look? https://github.com/1Marc/todomvc-vanillajs-2022/commit/d38e58e9be4a7dacc74aeff889869fc0bea27a1d https://github.com/1Marc/todomvc-vanillajs-2022/commit/d38e5...
- msoad 4y agoThis 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.
- steve_adams_86 4y agoA 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.
- syspec 4y agoWouldn'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
- realPubkey 4y agoAlso it does not work properly when it is used in more then one browser tab.
- grabanski 4y agoHere's what it would look like to support that usecase: https://github.com/1Marc/todomvc-vanillajs-2022/commit/0997999497617e358e0132058ceeb23d9ae34a73 https://github.com/1Marc/todomvc-vanillajs-2022/commit/09979...
- gherkinnn 4y agoThe 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/Memory_Management#garbage_collection 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 https://javascript.info/event-delegation 1 - https://reactjs.org/blog/2020/08/10/react-v17-rc.html#changes-to-event-delegation https://reactjs.org/blog/2020/08/10/react-v17-rc.html#change...
- syspec 4y agoI 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
- timcavel 4y ago
- xdennis 4y agoVanilla 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'));
- randomfool 4y agoPlease do not re-implement HTML sanitization. Just replace that escapeForHTML and innerHTML assignment with a later textContent assignment. Please. Pretty please.
- xupybd 4y agoI'm impressed this took an hour and a half. Is this the kind of timeframe someone should be able to throw something together in?
- mmcnl 4y agoHow 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.
- klabb3 4y ago> 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/854dd40bdf0facfdcdbd116b6c37dee906168254/js/app.js#L82 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.
- dimgl 4y agoYep, 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.
- skybrian 4y agoIt 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?
- 1marc 4y agoAgreed, 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.
- yuzuquat 4y agoHey! 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
- 1marc 4y agoThank you! Agreed!
- qudat 4y agoNow 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 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.
- BiteCode_dev 4y agoAlso: - 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.
- 1marc 4y agoWith 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: