548 comments

[ 2.9 ms ] story [ 400 ms ] thread
That's great ! Very useful.
Interesting how the list doesn't begin with use of querySelector or getElementById.

I know these sites are made by experts who aren't necessarily thinking about beginners, but a foundation, even a small one, is super valuable.

> but a foundation, even a small one, is super valuable

Well, I mean, first example is "ele.classList.add('class-name');", beginner or not, you gotta understand where `el` is coming from. Seems like a big oversight to have incomplete samples, even from the first example.

This site is a real gem. Clean, simple, and minus the excessive complexity and obfuscation caused by frameworks. Doing & Learning things in plain JS we can learn fundamentals.
(comment deleted)
I agree!

The MDN docs are from my experience the best browser frontend reference available.

This site however covers a different need: guide/howto oriented documentation, which is often what you want.

> Doing & Learning things in plain JS we can learn fundamentals.

To this I have to add that I often do write plain JS supported by only a few, small libraries such as is.js, axios, json-schema and so on. This is regarding small to medium sized projects and/or features.

This can easily save time, setup and mental energy, as long as one follows a consistent, simple structure. And on top of that, the fewer dependencies you have, the less friction.

But it also means that one has to have a bit of a deeper knowledge of the available frameworks and tools, which can manage complexity with growing features, because you add them incrementally and only when needed and so on.

Honestly, while axios is nice to have on the server side, the websocket API in the browser is very simple to use. Which IMO is a consistent theme with modern browser APIs.
Agreed: on our current front end project at work I’m having a lot of fun teaching the team the amazing browser APIs that subsume the need for a lot of the third party dependencies we used to reach for
How do you deal with IE 11?
Many of us do not need to deal with IE. I haven't even needed to deal with mobile in years. Depends on requirements and use case.
Agreed. But the reason I asked because I am assuming they are making changes to a long-standing project that previously relied on third-party libraries (for browser compat?). I'm interested in that specific situation, not all projects in general.
In this project, simple: we don't have to. Despite being a decade old application, it was entirely AJAX-driven and front-end focused even back in 2010, and IE support was dropped entirely a few years ago by the business. Works in Edge just fine, as to be expected
Makes sense. I think the two options are just dropping IE support entirely or using (usually third-party) polyfills.
MDN is great as if you're reading the manual with all the details and etc.

But like a lot of raw manuals sometimes you read it and wonder "Wait.. why would I want to do this again? Does this even do the thing I started looking for?"

Some of their examples have actually evolved to be a bit more akin to more usage based rather than raw specs.

I do appreciate the other sites that are more "You want to..." as a complement to MDN and such.

I don't like it because it's basically wrong, or if I'm being more charitable it's only telling you half the stuff you need to know. Take this page as an example - https://htmldom.dev/select-an-element-or-list-of-elements

Firstly, it doesn't tell the reader that every method of selecting elements listed is available on both a Document and an Element. document.getElementsByClassName selects everything in the page with that class name. Element.getElementsByClassName selects every child of an element with that class name. If you're wrangling a huge page using one is better than the other. Chaining calls is really useful eg document.getElementById('users').getElementsByClassName('admin').[1]

"Select an element by given ID" using getElementById() does select a single element on the page with that ID, which is right, but browsers don't enforce ID uniqueness so you're only getting the first element with that ID. That's a very common gotcha for devs who are new to this. (React would tell you if you've not got a unique key.)

.querySelectorAll() does not return a list of elements. It returns a NodeList, which is different to the HTMLCollection that the other methods return. For a start, NodeLists aren't iterable in the same way as HTMLCollections. You can use forEach but you can't use map. That's going to throw a lot of devs a curve ball.

Worst of all though, it doesn't mention .querySelector() for picking individual elements. Why would you miss that out?

[1] The page that does talk about selecting children (https://htmldom.dev/select-the-children-of-an-element) of an element suggests using an element's childNode array. That's horrible. There could be all manner of strange things in there. Just use an element.querySelector() call.

>.querySelectorAll() does not return a list of elements. It returns a NodeList, which is different to the HTMLCollection that the other methods return. For a start, NodeLists aren't iterable in the same way as HTMLCollections. You can use forEach but you can't use map. That's going to throw a lot of devs a curve ball.

querySelectorAll does return a list of elements. While technically a NodeList, you can't select non-element nodes with selectors which is why querySelectorAll never returns such.

Further, neither NodeList nor HTMLCollection implement methods like map, but both are quite iterable and in a similar fashion (by converting them to Arrays or using Array methods with them, like with other Array-like objects which JavaScript is full of). But if anything, NodeList is a "more" iterable type than HTMLCollection, as it does implement forEach itself, too.

I would certainly not recommend using querySelector for accessing an elements first child node or child element.

> Firstly, it doesn't tell the reader that every method of selecting elements listed is available on both a Document and an Element.

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

Just about everything on the Element node type is available directly on the Document. The document is actually a node type in the DOM. In JavaScript the DOM methods are populated on the global objects Element and Document and that is visible in the browser console with:

    Document.prototype
You can see that the prototypes are almost but not exactly identical and both inherit from the global Node object. The page could have dived into that level of detail, but I think that largely misses the point. Most JavaScript developers are irrationally scared to death of the DOM and that page is trying to be a friendly low friction reference. If somebody were really looking for that level of granularity they could go to MDN or the DOM spec.

> but browsers don't enforce ID uniqueness

Actually, the browsers do. This isn't a browser shortcoming. It is an HTML shortcoming. If the code were parsed as XML the browser would point to the location of this violation.

> .querySelectorAll() does not return a list of elements. It returns a NodeList

Same thing. Node lists are iterable lists but are not a form of Array where the only practical difference is that a node list does not have the Array.prototype methods.

> The page that does talk about selecting children (https://htmldom.dev/select-the-children-of-an-element) of an element suggests using an element's childNode array. That's horrible. There could be all manner of strange things in there. Just use an element.querySelector() call.

Suggesting reliance on the convenience of the querySelector method is bad advise, especially from a learning and reference perspective. The querySelector method executes thousands of times slower than the other more specific methods because it requires a parse step. Also I see no danger of using the childNodes property. Simply don't make the blanket assumption that everything in the DOM is limited to element and text node types.

> The querySelector method executes thousands of times slower than the other more specific methods

Do you mean this literally?

Yes. Test it yourself on JSBench https://jsbench.github.io/
Why link to a blank page?

It was an honest question, no need to be snarky. I'll just take that as "I've no real facts about the numbers am throwing about" answer. Thanks

It’s a benchmark tool that runs in your browser. You have to supply code samples to compare to see the numbers.
A benchmark tool. Wow! Thanks for that snarkboy, I never would have known!

Again, I wasn't asking for proof or tests, or links to blank benchmark tools where I could write the tests myself. I simply asked if you meant 1000 times faster literally or figuratively as that is a HUGE and significant difference. A more civil response:

"Yes, I mean literally. See https://jsperf.com/queryselectorall-vs-getelementsbytagname/...

Too bad this site doesn't remember your scroll position when you go to a page and hit the back button. For a site promoting vanilla Javascript, it didn't really need to be built with React.
I was also annoyed by it not remembering the scroll position. The site doesn't live up to its name.
I love the idea, but the very first example on there ("How to add a class to an element") comes with the disclaimer "isn't supported in IE 11". Everyone likes to support only modern browsers, but completely dropping support for IE is unlikely to be acceptable for most users.

For my own sites I conditionally include a shim for IE users so I can use vanilla JS and only IE is bothered by the longer load time, using <!--[if lte IE 10]> ... <![endif]-->

I'm a vanilla-js guy.

That cookbook is pretty good.

If anybody has a good way of doing a password dialog in vanilla-js, please post a link.

It's the one thing I've encountered where I wish I had used a framework.

Sorry, what's a password dialog?
A dialog box that prompts for your password. Never seen one?
Like <input type="password">? Or something more complex?
That’s a password field. Now just put it in a <dialog>.
What's the problem exactly? I assume you looked into putting that input element inside a dialog element and it didn't work, is that the issue?
dialog is not supported on Firefox and Safari without a polyfill.
Turns out those stupid things come in handy sometimes!
I have never used the dialog HTML element before, but I was playing around with adding an input type="password" this morning inside a HTML dialog and didn't see any problems.
Send a 401 (let's call this "vanilla-http").
Ironically, the site itself uses ~100ko of gzip’d JS.
And is built in react. It's about choosing the right tool for the job.
> And is built in react. It's about choosing the right tool for the job.

React is useless here. Try browsing the website without JS and notice how litterally nothing changes.

The only things that need JS are the light filter at the top and the fast navigation using body/head swapping + pushState, none of which require React.

On the frontend, yes. But it seems that it does server side compiling.

So basically the frontend JS is so the backend can produce HTML.

Rather weird way of looking at it.

If anything this reminds me why I'm using React. Having to manually add and remove children, classes or anything dynamic is just a pain.
I'd be interested to see if other people have similar go-to vanilla JS? If so, can you share a link here?

This one is mine:

https://github.com/donohoe/content/blob/master/posts/javascr...

(I follow basic ES6 syntax but easy to switch as needed)

A vanilla JS replacement for jQuery's ajax functionality, that worked on older browsers, would be welcome.

Edit: To clarify, a drop in replacement is what I was looking for.

For me the Fetch API is basically that:

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

    fetch("http://www.example.com").then(res => res.json()).then(json => {})
Only big downside is no IE11 support but thankfully I don't have to worry about that so much these days.
It still doesn't go POST in a nice way like the jQuery API does BUT it is not worth bringing jQuery to the page just for making requests with slightly nicer syntax.
What’s not nice about POST?

    fetch(url, {
      method: “POST”,
      body: “a body”
    })
It has some limitations as well around timeouts, cross site cookies, and progress tracking (uploads, for example).
Sure, but those aren’t common uses for $.ajax. Fetch can get you 95% of the way there.
So why not just use jQuery?
I like their ajax implementation, but don't need the rest of the library.
Added!

I don't know how far back it will help with old browsers. I'd need to test that and it will take awhile.

JSON.parse will throw a few older browsers by itself.

Nice work. I was looking for something just like this!
This is useful for some devs in some situations, but let's not go overboard. Teaching newbies to venerate vanilla is almost educational malpractice.
Teaching newbies that they can gloss over fundamental details with some extra NPM commands is certainly educational malpractice IMO.
(comment deleted)
It really isn't. Teaching newbies to venerate JSX and React is far more harmful in my opinion: it does a really good job of hiding what's actually going on.

These days vanilla JS DOM APIs are pretty straightforward. It's well worth learning them and using them on small projects where a library like React is absurd overkill.

Understanding fundamental browser behavior serves the purpose of optimizing CPU and bandwidth. Think of it as the bare metal of the browser
What is tantamount to educational malpractice is the pathological revulsion javascript developers have for their own language, such that merely teaching newbies how to actually write it without six proxies, three other languages and a framework to protected them is considered harmful.
Sure, either Javascript is an intrinsically good language, and you should therefore be able to use it as is, or it is not good, in which case the sane response would be to use it as little as possible. Every language has warts, but most can at least go out in public without layers of makeup.
>either Javascript is an intrinsically good language, and you should therefore be able to use it as is, or it is not good, in which case the sane response would be to use it as little as possible.

That's a false dichotomy. There is no such thing as an intrinsically good or bad language, and if the use of frameworks demonstrated the intrinsic flaws of a language, then all web-facing languages would be equally flawed, because no one avoids using frameworks in any of them.

Learning how to write "vanilla" JS (that term really bugs me) and how the DOM actually works is valuable regardless of whether the scale of most modern applications makes it efficient or cost effective to do so.

It’s not veneration it’s the idea that devs should understand the way things work underneath the over engineered abstractions FAANGs developed so they could onboard new grads to web development faster.
Pretty good! My only wish is that the site would be like http://youmightnotneedjquery.com/, so that the content would be viewable just by clicking the heading and having new space for it, perhaps in a fixed window, instead of separate pages.
Nice collection of recipes! Just a few quibbles about the website design:

    * The back and forward buttons lose scroll position.
    * Visited links look the same as non-visited.
    * In each recipe, top 70% of the screen is headers and whitespace, bottom 30% is content (on my laptop).

     * The text on this kind of code block is annoying to read even on a 15" laptop with only a slightly enlarged font.
This is a really great set of demos! The resizable table columns really irks me because I spent so long trying to make something similar and it ended up being hundreds of lines longer.
This is such a wonderful resource, I wish we had it when first building our app, which uses no frameworks or libs. We do use TypeScript to generate it, hard to pass up the benefits and syntax it provides.
I recently built a small side project in vanilla js for fun. I just didn't want to break out webpack and waste an hour getting it set up.

I got pretty far, did all the design. I wanted to run a client side simulation in javascript though, and found I needed to host a local server as chrome refused to read modules from a file due to CORS permissions (running chrome with the usual arguments didn't fix it).

At this point, since I needed an outside piece of software to run things anyway, I figured I might as well switch to webpack dev-server and get the whole modern frontend ecosystem. I then quickly started replacing my home grown dom syncing with vuejs, and snowballed from there.

I definitely learned a couple things, so time well spent, but I'm also going straight to webpack next time. I know it'll only take a few hours before I start hitting the limits of what vanilla js can do, and while reinventing the wheel was fun and educational, it didn't result in a better wheel.

Alternatively, you can use a simple web-server without needing all of webpack:

using npx (included with npm):

    npx serve .
using the php CLI:

    php -S localhost:5000 -t .
You weren't hitting the limits of vanilla JS, you were hitting the limit of reading files directly from disk instead of through a web server.
This is a good point, the fact that browsers won’t load JS modules over the file:// protocol is not the fault of JavaScript.
or in python 2 (should be on installed by default on most distro):

   python -m SimpleHTTPServer
or python3 :

    python -m http.server
Seriously, the poster is going to have to host their files somewhere eventually if they intend anyone else to ever see it. I can't believe they rewrote all their JS because they were forced to access over http:// instead of file://. This seems nonsensical.
Hey, never used python's http server, that's just as nice and easy as the two solutions I proposed, thanks for the tip!
A simple web-server only does that: serving a website. With a proper webpack setup, you get imports/exports, (node) module bundling, live reloading which all massively improve your development speed.

However I wouldn't recommend anyone to build their own webpack config if you don't know exactly what you're doing. Just use parcel: https://parceljs.org/

There's also Parcel: https://parceljs.org/

It does many things an advanced Webpack project does, but without any config. I use Parcel as long as possible and then switch to lower-level Webpack when I need more control. Easier way to start a new project.

If you want to spin up a project without doing config first then https://parceljs.org/ is a really good place to start. It does 95% of what most people use Webpack for, but with no config.

It's also worth noting that if you just want a bundler (with no server or hot module reload stuff) then Webpack with no config usually works for most projects that aren't doing anything advanced.

Why is using webpack not considered “vanilla”?
Because the code you write is not what is loaded into the browser, it’s bundled and loaded in chunks.
I still don’t see how that’s not vanilla.js
Because webpack is not part of the language specification.
So I guess using VSCode isn’t vanilla either cause it’s not part of the language spec?
Epic point being made here. TypeScript is Vanilla JS as well because it outputs JS.
So now VSCode only writes TypeScript just like Webpack only bundles React?
(comment deleted)
how are an editor and a code preprocessor comparable here? they serve entirely different purposes, unless you stretch "producing code" reaally far
They're both tools. As in webpack is a tool that allows you to use a preprocessor like babel but you don't have to if you don't want to.
yeah, so is git. would it make sense to say "So I guess using Git isn’t vanilla either cause it’s not part of the language spec?"?

my point is, i can't understand why you would bring VSCode up at all in a discussion about webpack's relationship to "vanilla js" (whatever that is).

(btw i was using the term "preprocessor" loosely - i meant source-transforming tools in general)

That is exactly the point, using a tool like git has absolutely nothing to do with how you interact with the DOM.

Just like using webpack has nothing to do with how you interact with the DOM.

true, it doesn't. but imo when people say "vanilla js" they mean both no framework to abstract DOM manipulation and no build steps, whether they be transpiling from ES7 or bundling stuff. perhaps webpack can be used to just minify+concatenate a few files together, but that's not how it's usually used, and i guess not what most people mean when they talk about webpack.

i am a bit biased, based on my recent experience of trying to load a webpacked library's `dist/foobar.js` into a WordPress thing via a normal <script src="..."> and having it barf all over the console, yelling about `window.module` missing and loaders and stuff. i never managed to get the bundled version to load, which reinforces my opinion - it's not "vanilla" if it needs some custom infrastructure and can't just be dropped into an existing plain js environment.

i did however manage to load the unbundled source with a native ES6 <script type="module">, and it worked great! vanilla js can be pretty pleasant these days :)

So vanilla js must be ES5 if you want to support legacy browsers? Because babel and other build tools aren't considered to be "vanilla"?

I thought vanilla means not using front end view framework/library such as Vue, React, jQuery...

i'm sure it means many things to many people :) obv i only speak myself here

ignoring framework stuff (bc everyone seems to agree there) i'd say if your js qualifies as "vanilla" if it can run in a relatively recent browser without a build step or other transformations. you might further ES5-ify, uglify and minify it for practical reasons, but that must be an optional thing

---

since we're splitting hairs, we could also distinguish "theoretically vanilla js" - js that's standard ECMAScript so it'll run fine when browser catch up, but it's not supported just yet and thus needs transforming. this would exclude non-standard extensions like JSX

and note that i don't mean "vanilla" as any sort of value judgement! it's a practical description of how it works, not some kind of platonic ideal to aspire to – frameworks, webpack, Babel etc provide useful solutions for the shortcomings of the browser platform and ecosystem. the thing i was talking about is a single-file internal tool, and compat isn't a problem; if it was user-facing, i'd probably use some ES5-ifying tool myself. and i'd probably use JSX if i was doing a React thing, because it's great - inline HTML is an underappreciated convenience in PHP!

whoops, meant to write:

  i'd say your js qualifies as "vanilla"
in the first paragraph, can't edit anymore
The programming environment usually is not deployed to the runtime environment, so it's not a part of the built program. Libraries are.

"Vanilla" language or tool has a precise meaning of using the official tool without external customizations. If you are importing a library that is not part of the language standard specification, that's by definition not vanilla.

Using a development environment is not a "customization" of the language, because javascript has no official development environment that you could customize by using a different one, so the environment is not a part of the language.

For languages like Smalltalk implementations that have an IDE+runtime that is THE official development environment and specification, switching the code to a different IDE+runtime would indeed be using a non-vanilla version.

https://en.wikipedia.org/wiki/Vanilla_software

Technically the runtime is the browser.

index.js var foo = document.body.getElementById("bar");

That is dom manipulation using vanilla javascript in all modern browsers. I can use webpack, rollup, parcel, or load it in a script tag, it doesn't matter it's still just plain old javascript.

Because you end up with Webpack runtime code in your bundles. No different than if you included a library’s source code in your code— it would not be vanilla JS.
Is JSONP vanilla.js?
No you don't, that's not how webpack works. You can use webpack's live reloading during development, but that's it. It's just a module bundler
> It's just a module bundler.

It is how Webpack works, actually. Webpack does not support bundling to native ES6 modules [0], it has to bundle into a format which requires runtime code being injected to execute properly, handling imports, and whatnot instead of relying purely on native ES6 modules.

Have you ever looked at the contents of a bundle? [1]

Long story short, Webpack circumvents native ES6 modules in favor of other module formats. It provides a great amount of utility, but it is not Vanilla JS.

[0] https://github.com/webpack/webpack/issues/2933 [1] https://pastebin.com/C2qPunwV

Internet Explorer isn't Vanilla.js either.
Agreed. Internet Explorer was almost certainly not written in JavaScript at all— most likely C++.
I want to give you the benefit of the doubt that you're being sardonic but just in case I meant IE doesn't support ES6 modules so thereby following your narrowly pedantic definition it isn't very vanilla.js
My point was not that you must use ES6 modules— my point was that webpack does NOT use ES6 modules so it must include a framework for importing, exporting, and otherwise consuming the bundles.

Serious questions, please don’t dance around them:

How is what I described above still Vanilla JS?

Would you consider using TypeScript to be Vanilla JS? Why or why not?

Would you consider using lo dash to be Vanilla JS? Why or why not?

Also, Vanilla JS is pedantic. The point is that you don’t need any of these tools to make a website or web app.

I personally like the tools I use, I don’t care about vanilla js. But you can’t just try to argue it’s not obviously meant to not include a bundling or transpiration step.

Furthermore, making a site/app with everything being vanilla js EXCEPT for also using Webpack is certainly as admirable— but it makes it not vanilla js.

I started trying to answer your first question, when I realized it’s a reasonably good question. Webpack doesn’t automatically change your JavaScript, so it is possible to use vanilla js and also Webpack. Colloquially though, “vanilla” is also referring to not using a pre-processing step of any kind, and not having project dependencies, basically directly writing the files that are loaded by browser.
And yet people wonder why HN has a reputation as a community of pedantic dorks.
... why would people wonder that? You expect a community of hackers to not nitpick? A group largely populated by programming people who are entirely accustomed to a single character changing the entire function of a statement and who frequently expect natural language to work the same way?
Hey dammit, we’re autistic programmers, not pedantic dorks! ;) But seriously, I’m not sure that’s entirely fair. I do think Webpack feels not-vanilla, even if it doesn’t change how you manipulate the DOM.
Fine I'll use rollup instead.
(comment deleted)
At least React doesn't require you to use packaging.

Just require it via script tag and create your app.

If you don't like the size, Preact is a good tiny alternative.

If you want JSX like syntax, try htm or t7.

Coincidentally, I just commented yesterday about an interview experience I had about the DOM. I did not expect it to be so highly upvoted. https://news.ycombinator.com/item?id=22740897
I don’t know if I would pass your test, but the outcome is more or less exactly what I would have expected. The vast majority of employed web devs do not use pure JS to manipulate the DOM because it’s incredibly tedious. That was true 5-10 years ago when the most popular option was JQuery, and now we have massive swaths of React where people don’t manipulate the DOM directly at all. And they get by just fine. Major commercial sites are built with little to no direct DOM manipulation.

Saying that you’re going to let people have time, use the web to lookup the answer, that there’s no penalty, etc., that seems blind to the fact that you’re signaling what it takes to pass the test as well as what people will be doing once they start working for you. I’m certain you lost the opportunity to interview some good candidates simply because they are choosing to not work somewhere that thinks pure JS is the only performant solution, and might not know that there are both good and bad ways to use JQuery, and/or functional reactive solutions that avoid keeping messy/buggy state around when you could instead re-render. I’m sure you also lost interviews because some candidates were basically told by you that already knowing how to manipulate the DOM via pure JS was what was required to ace the interview. They assumed, and reasonably so, that spending the hour showing you they didn’t already know how would result in not getting a job, so why bother with the interview right now? You might have sent several smart people off to study and do homework about it, but you don’t know that because they walked out the door.

So, while I do think it’s very useful to know how to use pure JS on the DOM, and I think your interview experience is interesting, the incredulity about it makes it seem to me like you’re not entirely taking responsibility for the implicit message that you sent to your candidates for the interview, nor that the outcome is fairly predictable.

The job position was for people to write A/B tests. A/B tests are a form of white hat hacking where code is injected into a page to manipulate or deface the page to test a business idea as an experiment.

It would not make sense to inject something like Angular or React as part of test code and would be detrimentally regressive to inject Angular or React targeted logic over an existing framework application without a more thorough consideration for second and third order consequences. An experiment is meant to be something that is created with the least possible labor since its not production code and short lived.

That said the most desirable approach was to manipulate the DOM directly since this achieved the fastest execution, provided the smallest risk/footprint, and was fastest to QA for regression.

---

In hindsight we learned a couple of things from A/B testing.

* In a page with a lot of asynchronously loading content everything can be precisely altered before the user can notice it. The more precise form of delay were recursive setTimeouts where the interval delay could be manually adjusted to the millisecond and there was never interval overlap. This took practice to know when and where to increase the interval rate without impacting the performance of other logic already in the page.

* The tests did not often reflect the actual business results compared to the production code written later. We found the test logic, even though it was just hacky throwaway code, was generally less defective and faster executing than the more thoroughly tested production code and so performed better than the actual results from the formally released code.

> A/B tests are a form of white hat hacking where code is injected into a page

No. The idea of A/B testing does not require DOM manipulation or code "injection" after the fact on an already rendered page. I don't know about your A/B tests, but A/B tests in general are site experiments you run on your users/customers -- the idea does not in general involve code injection, or say anything about the implementation. I have built A/B tests in React myself, and there is simply zero technical or performance issues with doing so. You render one thing for some people, and a different thing for other people, and measure their reactions.

It might not make sense to use React or Angular for you, for your particular site design, but there is nothing wrong with implementing A/B testing using React in general.

There's nothing wrong with using JQuery either, if you want direct DOM manipulation. It would be worth studying why your previous A/B tests were slow, because it can uncover some knowledge about JQuery. There are bad practices in JQuery, there are ways to do things really slowly. There are also ways to fix it when it goes slow, and learning those things might be overall a lot more efficient than resorting to pure JS DOM manipulation.

> No. The idea of A/B testing does not require DOM manipulation or code "injection".

We were using Adobe's Test and Target (Omniture) application for launching and measuring our tests. It works via code injection.

Yeah, that makes sense. The specifics of what you're doing certainly will drive what the implementation looks like. It makes sense that using Omniture for tests means that pure JS DOM manipulation is the best way forward. This detail is actually incredibly important to your story, and so I think it's easier than not to draw the wrong conclusion from the story because that important detail was left out. Omniture testing might be something a lot of candidates aren't exactly clamboring to spend their time doing. Certainly, with an A/B testing job I would be hoping and aspiring to learn more about things like site UX, maybe some data science, do HTML & JS that is relevant to the business team, and be involved in the production site's implementation and design, etc. I would personally be less excited about using an older legacy testing framework that requires low level DOM hacking, especially if it seemed separated from the core dev team. How do you implement the design that wins? Does the A/B test writer's version get put into production, or does someone else take the code injection and translate it into HTML?
> Major commercial sites are built with little to no direct DOM manipulation.

Little implies some, and I think the average bundle is already large enough without saying, "Oh, just throw jQuery in there whenever you do need to do DOM manipulations.", which will happen. I built a React app a couple weeks ago where I had to use portals to integrate it with a legacy form solution because we didn't have time to rewrite the entire form backend to justify a custom frontend. It involved a fair amount of manual DOM manipulation, but it worked out fine. All said and done, it was probably ~75 lines in a file with a few more comments than usual. It doesn't make sense to add 30kb or even 10kb to the bundle for that, so yes, I would expect the average developer to know the base DOM api at least somewhat well.

edit: I completely forgot about TDD. Depending on your testing environment, you may need to understand the DOM api for mocking or base utilities built into the test suite.

> Little implies some

I did not suggest using React and Jquery at the same time, and I don't really encourage that. I do not agree that it's a slippery slope and people will just start using JQuery with React. It's possible that something is already starting to go wrong if you're trying to manipulate the DOM using both React and DOM manipulation. The very point of React is to avoid direct DOM manipulation.

I've been in about half a dozen interviews in the last 6 months and I've never had to do this problem, but honestly my first reaction would be "this is a trick problem" out of paranoia that it's too easy. I wonder if more anxious people fall into that trap and overthink it to the point of overwhelming themselves; kind of like freezing up during an exam that you studied extensively for.

My biggest issue in interviews is remembering the recursion formula with some of the sorting algorithms. I eventually get it, but I end up burning a good chunk of time figuring it out, so it looks bad. In my entire career (almost 15 years now?), I've never had to use recursion or sorting algorithms believe it or not. That's what I get for working strictly on enterprise business applications.

I think everyone should know how the DOM works under the hood but the HN hate for frameworks and love for vanilla JavaScript is just unbelievable. As soon as you venture past small JavaScript sprinkle you will regret using vanilla. It feels like a made-up opinion by people who are actually not developing front-end JavaScript seriously. The DOM API is simply unfit for real web apps without a proper framework on top.
Its hard to see why the JS frameworks came to be, and easy to see the up front complexity of most of them. People who started before good frameworks were around take it for granted that people know what happens when you build complex sites with vanilla JS: You get a mess, or you get your own framework.
Not everybody wants to render everything on the client. JS frameworks (vue included, despite trying) do just not support rendering as a simple page.

Some people do have light needs that won't ever require a full framework.

Other people have very heavy needs that will require their own frameworks. The JS ones (react included) are not absolutely flexible.

And, if you fit none of those categories (honestly, most people are on the first), just replace the title with "how does a JS framework operate on the DOM", and take it as a learning resource.

> Not everybody wants to render everything on the client.

No, and then you should just render it on the server. Most "apps" should not be JavaScript apps at all. However, once you do need to enter that territory you should definitely use a front-end framework.

> JS frameworks do just not support rendering as a simple page.

What is this supposed to mean?

Agreed. The only way vanilla JS scales to a large codebase is through serious discipline and internal tools, essentially creating an ad hoc, poorly specified, home grown framework. Even the web components standard is insufficient without abstraction layers on top.
Not all codebases are large, and not every site is, or needs to be, enterprise scale. I think HN sometimes forgets that there's an entire web outside of FAANG+ and startup culture that doesn't care about any of that.
I don't think you need to be enterprise scale to justify using a front-end framework. Anything above trivial complexity is enough and it will give you headroom to scale as a bonus. I think a more common mistake is to use a framework when you could just as well render it on the server with the same result and being simpler at the same time.

But when you do need to create a dynamic web app, you should definitely use a framework. Using vanilla will just result in you creating your own half-baked framework anyway.

I do all my personal mvps now in vanilla JS, I can get ideas fleshed out faster without fumbling over frameworks.
Out of random interest, not even jQuery? I find it immensely tedious to write out vanilla js compared to all the shortcuts that $ provides...
QuerySelectorAll is widely supported and you can make your own shorthand for it.

  function $(query) {
    const result = document.querySelectorAll(query)
    if ( result ) {
      if ( result.length > 1 ) {
        return result
      } else {
        return result[0]
      }
    }
  }
I hope you don't use that since it randomly returns either an element or a list of elements, so you'd have to also add an if/else every time you use it.

This is my go-to:

    const $ = document.querySelector.bind(document);
    const $$ = document.querySelectorAll.bind(document);
Tip: browser consoles already have these shortcuts, except $$ returns an actual array there instead of a NodeList.
Knowing that jQuery ends up calling those very same functions, only often after jumping through a bunch of hoops, doesnt make me consider it a shortcut. Between auto-complete and copy and paste, I prefer slightly more "work" up front, and then zero needless work at runtime, than a bit of "magic" that ends up doing needless work every single time it is run.

But I have to admit, I don't care about compatibility beyond Firefox on the desktop, if I wrote stuff for a company on a deadline, or if I worked with other people on something, I would mind jQuery very little or not at all. But for my own stuff I make to spark joy, where I get to decide all of it, I want it as vanilla as I can get it.

> copy and paste

Bravo for admitting it. I have to say I've usually run into trouble working with copy and paste coders though.

How do you make sure what you're doing this with is something you understand? I never understood this one.

I just meant copying and pasting long function and variable names out of my own code elsewhere, should autocomplete somehow not apply.
Not even jQuery. The dom selector API is cohesive enough these days for my use.
If they do this regularly, they surely have a personal toolbox of js code they can draw from that handle most everything jQuery would provide.
Yep, especially for handling events (which I try to use sparingly :)). That was one thing jQuery had a great out of the box API for.
This line of reasoning only made sense in the old days.

For example, $.ajax() is strictly worse than the native window.fetch() -> Promise we have today.

I could see using jQuery in 2020 if your poor soul still has to support ancient browsers, but beyond that I suspect people only latch on to jQuery out of habit.

> I could see using jQuery in 2020 if your poor soul still has to support ancient browsers

IE 11 at work for some customer projects. It's dreadful. No support for anything decent, but at least the debugger is better than the "nothing" you had with IE6...

The main advantage of jQuery these days is all the plugins it provides, most (if not all) things you need on a website exist in jQuery. And I also found it really has messed up search results, search for anything javascript related, and almost all answers you find on StackOverflow are people suggesting to use jQuery. (Even when the author didn't ask for it)

The other day I was looking for a simple markdown editor, and it took me a while to find a decent vanilla one. (Ended up using https://simplemde.com)

The problem with vanilla JS is not APIs, API is the easy thing. The problem is building proper architecture, so code won't quickly turn into spaghetti. With frameworks like Angular or React, it's much easier, as the general structure is dictated by framework and developer just have to follow good practice. With vanilla JS it's the wild west.
> just have to follow good practice

Easier said than done when best practices shift every 6 months.

The problem is that the Wild West and unnecessary complexity has just been shifted up a level or two as devs are now facing the Wild West of frameworks, de ops has turned into a monster with an unnecessary large toolbox.
Agreed. This is my main issue with the "you don't need frameworks" rhetoric.

If you're a small team or a solo dev working on a simple app, and you know the source code very well, frameworks might not be the best choice.

However, if you've ever worked on a team of revolving contributors, constantly shifting requirements, or have any reason to reuse code across apps/repos, frameworks help immensely.

The biggest benefit to using something like React imo, is that when we hire somebody familiar with React, they can hit the ground running and start contributing immediately. Unless your app is dead simple, you won't be able to have the same velocity in a homespun framework (and given enough time, most "vanilla" apps turn into homespun frameworks).

Isn't this also simply true in the corporate world in general? Frameworks and best practices of doing something means that things are standardized. Standardization means that a vocabulary is shared and people understand each other.

You want to make people as swappable as possible. At least that's how I look at it from a management perspective (not a manager, but one can dream).

Not necessarily. Using popular frameworks will always widen the pool of contributors you have access to, no matter what "sector" your project falls under.
We've adopted a framework as a small team and it has nothing to do with onboarding new people. We adopted it became clear that if we stuck with vanilla JS, we'd end up re-building something like jQuery to keep our code and abstractions manageable. And then we'd build something like React, while doing a much poorer job of it. Once your app has some "click X and A, B and C should update" logic you quickly descend into a tangle of tracking dependencies by hand.
> Once your app has some "click X and A, B and C should update" logic you quickly descend into a tangle of tracking dependencies by hand.

I managed to deal with moderately difficult scenarios with about 7 files in typescript. I ended up using webpack but that is a dev-dependency which doesn't really count.

I built this for me, but if you employ some basic patterns and use something that is a little more powerful than JavaScript it isn't that hard. I also very rarely ever use a DOM selectors in my JavasScript.

I don't particularly like frameworks these days because you end up spending more time dealing with the framework than actually getting things done.

Could you share this? I'm a backend developer and I just want to make light frontends with flexbox, grid and javascript. But it'd be nice to scale to more complex UIs also with a few functions.
Just use vanilla JS to begin with. If your app has a lot of interaction, you can use React with create-react-app makes things easier.

You can still use vanilla JS, HTML and CSS. And it's not morally wrong.

Assess the requirements. Lots of moving parts and not a whole lot of time? React or Vue lets you draw the big lines quite simply. Need something simple or with fancy animations? Vanilla may be your best bet.

Personally I use vanilla for simpler stuff and React for more complex apps.

Don't worry, just make cool stuff. Nobody ever cares how you built it, just that it works.

Trello still uses CoffeeScript. It really does not matter as long as it works.

PS: You can combine if and when needed.

Most of the complexity comes from state management and tracking data dependencies, not dom manipulation.

If you like keeping things light this library gives you a lot of bang for the buck:

https://github.com/MaiaVictor/PureState

It's similar to how pub/sub works but it does the topological sort that prevents data with diamond shaped dependencies from being triggered twice, in less than 500bytes minified (before zipping).

You could learn to pick better frameworks. I can’t remember the last time I dealt with a framework bug in react and I’m working on multiple teams on about two dozen web apps. And that’s without including other jobs.

It sounds like you’re not really working on apps frameworks like react are supposed to deal with, (7 files of typescript) so why do you care?

> You could learn to pick better frameworks. I can’t remember the last time I dealt with a framework bug in react and I’m working on multiple teams on about two dozen web apps. And that’s without including other jobs.

I have used quite a few frameworks over the years and there is always some PITA issue you have to deal with.

> It sounds like you’re not really working on apps frameworks like react are supposed to deal with, (7 files of typescript) so why do you care?

You don't need large frameworks to scale something. You can just do it with applying the right patterns (that these large frameworks use) and get 80% of the benefit. However that requires (shock and horror), thinking for yourself and learning how things work properly.

"descend into a tangle of tracking dependencies by hand." What is your definition of "by hand"? What constitutes by hand and what does not constitute by hand?
My definition is declaring each dependency explicity. "A, B and C depend on D or E." Add a watcher on D and E to go update A, B and C. Repeat for every combination of dependencies. When app is complex enough I threw that away for a framework that tracked dependencies for me.
Sorry, I don't understand. How would the framework know what the dependencies are if you don't declare them, even indirectly in some fashion? In what sense are they dependent?
> when we hire somebody familiar with React, they can hit the ground running and start contributing immediately

This is one of the selling points, but never really realizable in a large scale project. I've seen people become productive with an in-house template system, vanilla javascript + custom libraries even faster than on a "standard" React project.

As they emphasize in their own docs, React is not a framework. The amount of moving pieces you need around it for a working project ends up being more complex than your cut-to-size custom framework. There are many other positives to adopting standard tools, but this one is a red herring.

Here's an example of a vanilla JS app with good architecture: https://github.com/Rajeev-K/eureka
Looks like you structured your own MVC framework?
Yes, and the MVC framework is all of 500 lines of code and can be used with React too: https://github.com/Rajeev-K/mvc-router
No disrespect, but I think you proved @vbezhenar's point. The right way to structure the code is with a framework of some kind, even if it's homegrown.
If there is anything I am trying to prove it is that you don't need complicated frameworks like Angular or React. Those frameworks have gotten too complex for what they do.
React doesn't even have a router, so your framework is already more complex.
I don’t think there is anything wrong with building your own ‘framework’. I feel like there is a lot of good experience gained, and learning to be had from taking this approach. Especially for less experienced devs.

It forces you to brush up on fundamentals, fill knowledge gaps, and practice/ learn design patterns. Also the end result is there is no ‘magic’, you know everything that is happening because you implemented it yourself.

Frameworks are great, but I don’t like reaching for them when I start new toy projects, I want to use it as an opportunity to improve my core JS skills.

I agree. I'm stubborn to take on frameworks as I have a vision and want to code it now; rather than learn and understand the framework to do what I want to create which by then my idea has deflated.

The company I am currently contracting for use Ansible. I've never used it prior and I get where the hype is but to me the whole system is just a mess. Asking the younger developers on "why isn't this working" feels quite embarrassing.

Five different folders, within more folders and then more folders on that; then you've got YAML which if you have one wrong space spews errors. I'm not dissing any of it as when it works when it works they do have their reasons for existence but it just feels so convoluted to do something you could write simply in bash.

Maybe I'm just a cynical SysAdmin throwing "get off my lawn" while wanting to see the world burn. But the era where I am from, where the internet was truly developmental; where if you wanted a CMS you built it from scratch. If you wanted a forum, you built it from scratch is kind of almost deleted from internet history.

Wordpress came a long and it ended all that, though I suppose it had to happen if you wanted more features from the users on the internet. It was a niche in the early 00's to have your own website but now my 70 year-old mother administrates her own website.

Agree, in the end you just end up creating your own custom framework.
The problem is every dev thinking that every single project has to be resume buzzword compatible and super complex to hide the complexity they're sure is coming. But these requirements really only occur if you're forced into them by working on something in order to make money. The web is more than just the commercial web.
I'm using far more ridiculous, buzzwordy and complex tools in my non-commercial projects though. (In fact, that's usually the point of those projects.)
>In fact, that's usually the point of those projects.

And are you doing it because you truly enjoy the needless complexity or because the buzzwords would look good on your resume? If the later, again, that's profit motive and commercial web. Like how the only point of using kubernetes for personal stuff is to learn kubernetes for non-personal stuff.

> With vanilla JS it's the wild west.

In my experience in the corporate world it's just as much the wild west even with using popular frameworks. Frameworks aren't a substitute for discipline or organization.

I wonder if those chaotic corporate experiences would've been far worse if not for the frameworks. They're just so useful for significantly constraining the solution space that you can't get too far into the weeds even when lacking discipline/organization.
This, is my experience, tends to just chase the mess deeper into the architecture, which may not be a good tradeoff.
My experience is that velocity slows because devs get so lost in all the accidental complexity of these frameworks and their hidden lifecycles (that they only barely grasp from their 1 tutorials worth of experience) that their velocity of delivering real business value plummets. We are much less productive than a decade ago.
In my experience, a framework atleast provides some ropes to hold onto while traversing the mess. Currently I'm stuck with a codebase with almost no documentation of a mess of legacy and new code with layers and layers of developers' opinions on top. The only way I'm able to figure anything is out is by tracing remnants of a light framework that's in place. I'm able to read the framework documentation and slowly unravel it, without it it'd be an even more monumental task!

I googled/linkedin developers that have worked on this codebase for the past decade and most of them appear to have this "rockstar developer" thing going on. They are opinionated, had heated debates (from what I'm told), and often rolled their own solutions whenever possible. Now we see the result of these geniuses doing their thing.

Just use a framework please, your homegrown solution is sucks. I guarantee it.

React was somebody's homegrown solution. Same for Vue, Angular, Svelte and every other framework.
Yeah. But they got selected by the ecosystem because they were GREAT homegrown solutions. While Angular was an accidental success, it seems that Facebook really grasped early on what was happening with React, (we all benefited from the Angular experience, warts and all) and really put in the resources necessary to make React successful, for the benefit of all.
> they got selected by the ecosystem because they were GREAT homegrown solutions

While React has lots of great ideas, good marketing and the facebook brand is really what boosted its popularity. Popular does not necessarily mean great. There must be some other great homegrown frameworks out there, but we have never heard of them, since they did not start out as a facebook or google homegrown framework.

> it seems that Facebook really grasped early on what was happening with React,

This just is not accurate. React has also evolved a lot since its inception, they've just been careful about maintaining backwards compatibility compared to angular.

One does not preclude the other.
The only way I benefited from Angular was when all the companies who let the front-end dev come lately's talk them into using it; realized they had been sold a bill off goods and needed someone to get them out of their Angular mess. I made a good living off of getting people out of Angular 1's mess. The reality is Angular 1 was poor, it was so poor that the developers decided that they has missed the mark so much that they needed a complete rewrite to make a good product. Why people stuck with them after that is beyond me. I can still vividly remember taking over my first angular project and realizing that the devs that built it where so green that they had misused common concepts and terminology like what scope means and what state means and had conflated the two into a mess.

Angular was bad and it's ashamed that it's hype pretty much relegated better toolkits like Dojo and MooTools to the dustbin of history.

> Currently I'm stuck with a codebase with almost no documentation of a mess of legacy and new code with layers and layers of developers' opinions on top.

If it was originally built using a framework, what framework do you think that would be? And would it still be in active development and evolving today? How do you integrate new code in a legacy or evolving framework? My experience of this says it is not really a framework vs no-framework problem, but a problem of how to keep an applications code base healthy in a world of ever changing and evolving features, developers, frameworks and technologies. I think thats the real problem you are dealing with here, and not "hot-shot developer from 10 years back didn't use the coolest stack of that time".

And it is the problem you were hired to solve. If everything was working perfectly with no new features required to be added to the legacy code base, they simply wouldn't need you.

Ja 100% ! Ppl will argue with you and they will argue the exception not the average experience. Sure there are code messes with frameworks. I feel that ppl argue Jquery with multiple ppl and a good size project is better, just havent had enough pain. You can x my argument by 2 if its a project you join and didnt start.
Did you ever work on a JQuery codebase? (JQuery was an almost 1:1 mapping to browser APIs, do it's more or less equivalent to vanillaJS). Codebases based on modern frameworks, especially React, are much less complex than codebases based on the old approach. Back then you'd get lost in the weeds of DOM manipulation, and it'd be hard to see the big picture at all.

In my experience most of the incidental complexity in modern apps comes from inexperienced devs doing things that simply didn't need to be done in the first place. Very little of it comes from the frameworks.

I also feel modern web apps are just much more complex than those from the jQuery era. So codebases have to do a lot more. It's hard to find a 1:1 mapping, as we just didn't expect as much out of the web in those days.
Complete BS. Not true at all. the jquery era had ajax with dynamic dom updates, dynamic svg, css, and many things we have today except for websockets, web usb, mic, camera, and other devices. the difficulty was more around each browser implementing things differently. and css was a nightmare. just to center something horizontally or vertically (or both) took patience.
It’s not “Complete BS.” — just because we had those features does not mean most businesses used them to the same extent we do today. I was deep in the front-end weeds in 2007 and onwards, and while I may have been doing some neat stuff then, the complexity pales in comparison to the sheer amount of business logic that now lives client-side.
That's because you have 13 more years of experience now. Or you like to revise history.
jQuery is constantly tested with all of its supported browsers via unit tests. However, a web page using jQuery may not work in the same set of browsers if its own code takes advantage of (or falls prey to) browser-specific behaviors.

https://jquery.com/browser-support/

That quote says that if you attempt to solve for a cross browser conflict using a standards based approach it will likely conflict with jQuery code in the page. Either your approach will fail due to changes imposed by jQuery or your approach will break something supplied by jQuery. That is bad mojo.

Another problem I have with jQuery is that it encourages extremely inefficient practices in exchange for convenience. For example consider jQuery's closest method, which looks great if you don't consider the steps that execute under the hood to make that happen. In contrast using a non-jQuery approach generally meant event handlers that more directly target specific nodes in the page without all the necessary DOM walking.

I also remember jQuery frequently breaking IE back in the day. IE uses instruction count to determine if there is too much code in the page, whereas other browsers use a 20 second clock to warn on long executing code. Since jQuery does a bunch of unnecessary things and encourages method chaining those instructions counts would quickly add up and IE would stop executing code.

I have also found for many developers that jQuery is/was more of a live or die crutch they cannot live without opposed to a time saving convenience which was very off putting because developers were unreliable when things broke or when things needed to execute faster.

It's 10x the code now. 10x = 10x more space for bugs and bad design.

Use to be I might setup a handler on an input element to update a value. Now I have to write an action factory to generate an action to get reduced into a function that updates the value. From simple data.prop = elem.value to 4+ functions and a bunch deep deep overhead.

Now I'm not saying all that structure doesn't have benefits but it's also a large amount of rope in which to hang yourself.

I honestly think it's about a quarter of the code. Yes, there's a bit of ceremony around state management (but you are also free not to use Redux). But it's mostly boilerplate with a prescribed structure, so IMO it's pretty difficult to get it wrong.

On the other hand, most of the code has always been DOM manipulation, and having that declarative rather than imperative is a huge win. The alternative used to be using a template engine like handlebars, but that did a complete re-render every time any state changed, so for anything moderately complex that was too slow and you had to fallback to manual DOM manipulation, and manually keeping the DOM in sync with your state. And that was a large amount of rope in which to hang yourself

Yet we all managed to write complex web applications without much trouble that performed better than React ever can. DOM manipulation was needed rarely actually - usually you replace subtrees anyways (switch tabs, etc).
If DOM manipulation is rarely needed then your web app isn't complex, it's at most a collection of CRUD pages. UI Frameworks like React are for building UI's that accomplish a lot more than that through frequent DOM manipulation. If all you need is CRUD then templating frameworks still exist, are well maintained, and widely in use.
Even in complex apps, most of the DOM remains the same and you are changing several properties (some text, changing some classes).
That's not true as soon as your UI contains conditional logic or a list of elements, at least one of which will be present in almost every web application.
> ... and having that declarative rather than imperative is a huge win. The alternative used to be using a template engine like handlebars

While React markets itself as a declarative DOM manipulation library, any kind of HTML templating system is declarative out of necessity. Why? Because they all produce HTML in the end, which is itself a declarative markup language.

This completely matches my experience. I've worked on a 200k+ line javascript codebase that originally used just vanilla HTML DOM management and jQuery for everything, and I've helped introduce React into it over the years.

Every time the old code needed to place a view inside of another view, it was a fresh adventure in the exact way that sort of extremely common routine operation shouldn't be. Understanding a module always meant understanding its approach to managing its DOM elements before you even got to its business logic. Modules often chose between having simple-but-janky code that re-created DOM elements from scratch every time anything in the view changed, or having more-efficient-but-complex-and-buggy code that intelligently updated only the changed elements but often had inconsistencies with the first-render code causing some values to not work if they got set while the view was already mounted. People tried to establish some conventions across a few modules, but the chosen conventions often had significant drawbacks or only worked in specific cases because the people making the conventions didn't have the experience of library/framework authors.

I remember working with a coworker sketching out an idea of a convention we could develop and use for updating text and substituting in translations and live values. One of my main goals was to allow our modules to have the same code for the first-render and subsequent renders without having to replace all the module's elements with new ones. It was originally intended for just updating text, but I started to realize it would have to handle arbitrary HTML and embedding views from other modules to really be useful. The idea felt like it would need special cases to handle that, and I couldn't get the idea further. Then I later found React, and I realized it was a generalized approach to accomplish exactly what we were trying to design. I got the green light to use it in a few new modules, and even coworkers who weren't yet familiar with React could see how the modules were much more focused on the actual business logic rather than being absolutely filled with so much unique DOM-manipulation code. Everyone was sold on it within a few months, and people that needed to make changes to old modules would often choose to move the code over to React first to make it simpler to work on.

I make my money by wrangling old jQuery and Knockout projects into 2020: I can wholeheartedly agree with you
> (that they only barely grasp from their 1 tutorials worth of experience)

If you're going to staff your entire corporate dev team with a bunch of green developers, yeah, things will be nasty. That's not the frameworks' fault though, that's just a straw man.

Agreed. Framework or no framework, general software development principles should still apply. Need experienced leads and architects
I don't think frameworks make any difference in this regard. The most important thing to remember is that developers are people. Most everyone benefits from direction and guidance without regard for their seniority. Some of that guidance can be automated by applying appropriate limits or certain safeguards to the process, but is generally not something that can be outsourced directly to a tool. I think of that as something akin to letting a television parent your child.
They do though, frameworks are just an amalgamations of patterns and practices codified. If you go Vanilla JS you are going to build abstractions on top of it to make your patterns and practices reusable and structured. Given enough time you are going to build a framework that enforces your patterns and practices. So why not just adopt proven ones out of the gate. But verify that they are indeed proven ones before just jumping on a bandwagon.

An example I would highlight is, Redux it's great and it has helped a lot of developers that don't know state patterns learn to deal with state, but it only taught them half of what they need to know. The other part of state is not allowing applications to fall into an inconstant state that it should not be in. Redux intentionally ducked this one because state management is a complex task and building a state machine makes the cognitive overhead much more complex but that is what developers following correct patterns should be doing, they should be using a state machine and it is the reason I use XState in my projects over using Redux as it is a full state management solution, that gives me a guarantee that my state is both preserved and consistent.

https://timdeschryver.dev/blog/my-love-letter-to-xstate-and-...

> Given enough time you are going to build a framework

I have heard this argument countless times over the last decade and its not based on anything. I suppose if you have never written code without a framework and for the first time attempt to write some new application it would make sense that your application ends up looking that thing you are familiar with. Beyond that this entire position is absolutely meritless.

What I find most frustrating about this sentiment is the lack of originality it codifies. Many JavaScript developers I speak with online are absolutely certain the language is limited to building static pages and SPAs. That's it. And, it absolutely blows my mind that their imagination is so immediately limited. Logically, though, since there is nothing else to build but SPAs and frameworks are great at building SPAs it must not make sense to even not use a framework. That line of thinking leaves me speechless, literally. I just spot responding and walk away.

I started with Motorola 68000 assembly in the late 70's early 80's (hobbyist not old enough at that time to work) while their where frameworks of sorts back then there really was not what we have to day. I can assure you though when you built stuff of enough abstraction you ended up with your own frameworks that helped you build new applications. Patterns of the way you do things and tried and true methods. Packaged up into reusable libraries.

You see it in every discipline, game programmers use game engines which are frameworks almost nobody is writing their engine from scratch because they don't need frameworks.

Enterprise programmers have saleforce, SAP etc. Hardly anyone is writing an ERP from scratch.

It's not that a lot of people that use frameworks don't know how to go it alone, I certainly do and most of the caliber of developers I work with certainly do. It's just that we realize we will, in the end, end up with something that looks like a framework. Because there was a day and time when that's exactly what we did and it was common practice. But that practice came with the additional overhead of training people on an internal framework, as well as maintaining documentation and the codebase of said custom framework.

It was more common and more acceptable before the internet and opensource that a developer or team would roll their own framework, create their own patterns and procedures and it was a very common practice to roll your own framework. But their where commercially available frameworks at the time for things like computer graphics, UI etc. Frameworks are a natural evolution of code reuse. The difference is today people tend to agree on third party frameworks as a standard way to develop as opposed to internally develop them. IN a effort to externalize, training, support and documentation of the framework.

I understand your frustration with developers conflating a simple page with SPA's. I only build large SPA applications I am not a web page developer, but if all I needed to do was provide a landing page, I would not use a framework because 90% of the deliverable is HTML and CSS. It's a lot of overhead to bring in something like React and the NPM build ecosystem because you have one tiny component of an otherwise static page.

> you can't get too far into the weeds

Oh, but you can. It can go anywhere from realizing that your extensive enzyme-based test suite turned out to be garbage because nobody really grasped the value proposition of snapshots at the beginning of the project, to the entire application aging extremely poorly because it's written in Angular 1 that is a mix of needless directives and jQuery call hacks (both true stories).

Github seems to be doing fine with vanilla JS.
You’re write. I’m a tech lead in an ‘enterprise’ team, and the fight against spaghetti is so real.

I feel a lot of enterprise devs are older, and more set in their ways. It’a not just teaching them new technology any more - I have to fundamentally shift their approach.

All the while being 20 years younger and less ‘experienced’ than them.

It’s slow progress. Every time I relax control within a few hours I have to bring it back. One guy today tried to set up a deployment of a prepackaged service that involved building the service (in debug configuration), then running that. I had to explain that deployments out of /bin/Debug is a bit of a red flag. I’m not sure how you can miss that myself, but here we are.

*right (unless wordplay was intentional)
I have to explain to "senior" developers why a deployment process involving keeping the source code on the prod server and building it with Visual Studio on the prod server is not a great idea.
That has nothing to do with being older. That guy was similarly reckless when they were 20 years younger.
You mean as opposed to Release? Or something else?
The problem in corporate is too many developers trying to do things all at once 10 different ways, without anyone pushing to maintain consistency
Maybe this is just a problem where I work (large enterprise SV company) but a big issue is that a lot of engineers know better but they do a shit job because they are looking to deliver ASAP so they get brownie points for finishing a task quickly. These people are just looking to get promoted fast and they will have jumped ship long before they are held responsible for the maintenance burden of their spaghetti code. At the same time, people who actually take the time to write maintainable code get the shaft because they appear to be unproductive and are "blocking" progress. Of course, a good manager can see through this but good managers are rare where I work.
This could be read the other way too. In my experience there is a spectrum from reckless to needlessly perfectionist, neither of which approaches are very helpful. Being focused on delivery is not necessarily a bad thing. But then I've mostly worked in small startups, so perhaps it's different elsewhere.
In my experience any team anywhere can turn any codebase into soup!

Strong tech leadership that provides good examples, institutes code reviews, establishes & follows standards etc is where nice code bases come from (even in tiny teams)

Ofcourse they are, I know a good bit of React and I can get a good understanding of any reasonably sized React project within a short amount of time _because_ it's a React project. People may still be people and do weird stuff, but that's a given in anything you do.
A framework enforces some organization by its very nature, even the barebone ones. Otherwise they usually break. Plus, the popular ones will have a community that sets some standards, example, off the top of my head: python significant white space

Frameworks are not a substitute for engineering standards but anyone whose really interested in that, pay the bills interested, first thing they do is look for frameworks

In my experience this is not the case if you have experienced leads and architects. Just using a framework for the sake of using a framework can be just as bad or worse.
I came here for this comment, thank you sir.
The difference now is it's only a "wild west" as far as app structure goes. Developers still need to put a lot of thought into component composition and app state to maintain a quality code base. Previously you had to do all of that AND put a lot of thought into how to update the UI correctly and efficiently. New approaches and frameworks removed the complexity of that last step.
I completely agree. What's everyone's favorite extremely lightweight view frameworks? And for those of us writing SPAs, favorite controller and routing frameworks?
Can confirm. Before I started using Preact, my client-side code was a large vanilla script. I would rather go work on a farm in Mongolia than go back to that.
The vanilla API is still a problem. It feels pretty verbose and limited when you're used to jQuery.

You really don't need any more than jQuery if you're just doing a few small things per page as opposed to a single page app or something.

Are transpilers included in Vanilla JS? If not, then IE 11 and Edge prior to 15 don't support async/await, which would mandate two codebases for lots of use-cases. Similarly, lots of other stuff has uneven support, hence polyfill, which also isn't "Vanilla JS" sensu stricto.
> The problem with vanilla JS is not APIs, API is the easy thing.

Then the problem is really the API, if one needs to write tons of helpers just to make that thing bearable. Never had to write a framework on top of QT or WPF just to develop apps on these platforms. Web Components tries to make things a bit easier by allowing people to write their own widgets that know how to clean up themselves when removed, but it's not there yet apparently.

IMHO what the DOM needs is a good DOM diff API directly included in the browser. Right now it's either modifying DOM nodes themselves manually or just innerHTML string trickery, when wanting to update an entire tree of DOM nodes.

events are already a solved problem thanks to event delegation. It's DOM modification that is still painful.

This list of recipes doesn't solve the large front-end app at scale problem.

So personally right now, all I need IS a DOM-diff library. Using external widgets is a bit trickier, but with event handlers I can do required instantiation and clean-up provided the third party widget has the necessary event hooks.

> Then the problem is really the API

I think the problem of JS is not the APIs, it's the language itself.

> IMHO what the DOM needs is a good DOM diff API directly included in the browser.

Here you go, part of WebComponents:

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

> Web Components tries to make things a bit easier by allowing people to write their own widgets that know how to clean up themselves when removed, but it's not there yet apparently.

WCs aims to replace a lot of what is now React. As is "just the view and some encapsulation. With a the litElements lib (or some other) you also get some life cycle callbacks.

> This list of recipes doesn't solve the large front-end app at scale problem.

It did not claim to either.

My 2 cents: that problem is prolly going to be fixed by writing code that compiles to JS (or WASM). JS was the problem all along for big codebases; too quirky, too little safety, very easy to make mistakes.

> part of WebComponents

WebComponents do not have DOM diff APIs whatsoever.

Diffing isn't really needed - usually you either replace a subtree completely or change a few attributes, which isn't hard to write code for.

Diffing will always be expensive memory wise.

> Diffing isn't really needed - usually you either replace a subtree completely or change a few attributes, which isn't hard to write code for.

Replacing the entire page on model change doesn't work for interactive forms and I don't want to micro-manage every attribute. My model drives the view automatically so diffing is necessary. The memory cost isn't that big if the diff algorithm is implemented efficiently.

In theory yes, but in practice even with frameworks codebases can turn into messes, and/or tends to become solid but completely frozen on a particular feature set. Small changes suddenly becomes daunting because the initial architecture needs to be changed to accommodate and surprise all is tightly coupled under the cover. With vanilla JS and spaghetti it's painful and boring but at least if I need to change a behavior on a page usually I'm done with a few lines of code. Edit: it's a tradeoff, but in early stages I found being able to make one the fly changes in a few minutes/hours to accommodate a customer instead of weeks (or never if it's too painful to evolve the perfect architecture) very valuable.

It really depends on the use case, and sure frameworks are awesome in the right context, but I think the current "best practice" of defaulting to one in any project no matter the business trajectory, product market fit maturity and team size is misguided.

At my position, there are at least 5 different interpretations of how to do React. Each project has an overseer who enforces a particular philosophy/design. JS frameworks are frameworks. They don't make the problem easier, they just change the terminology and add new abstractions which inevitably turn into angel hair pasta.
React is not a silver bullet. It solves one problem and it solves it very well: dealing with dynamical updating DOM views. There are still many different ways to architect your application but it stops the bikeshedding and reduces the opportunity for bugs at the view layer.
The problem with frameworks like React is that the version you’re using and its API will become outdated in no time. We started using React in 2014 and their approach to state management changed at least three times since then. Not to mention build systems, tooling and libraries. In my experience that leads to a large fraction of developer time (10-30 percent I’d say) just going into often pointless refactoring that is necessary to keep up with the framework ecosystem, because you don’t want to run “legacy code”. Most large organizations seem to accept that but for smaller ones it can be quite a burden.

The beauty of the native JS APIs is that they are relatively stable: things that worked 10 years ago still work today, and can be done in the same way. Also, standard adherence in browsers has become much better so if you do not need to support legacy browsers like IE you can get away with writing pure JS without any polyfills or frameworks.

Why refactor if you don't see any value in it? There is no reason you have to refactor.
If you don't refactor and update your dependencies regularly you can easily end-up in a corner.

You can be hit by a bug in your dependencies, be it a functional one or a security one, but if your dependencies are completely out of date and there is tons of API incompatibilities between the version you are using, and the version implementing the bug fix, it will be really painful and take a long time to update, with stakeholders breathing down your neck expecting a fix asap.

Also, maintaining old tool chains can be a real drag (maintaining older building hosts, developer machines or VMs).

Updating frequently to be near enough the latest version is generally preferable.

This. Framework maintenance is something that takes a lot of time from our development team. Compared to other ecosystems (Python, Java), the frontend teams spend much more time dealing with updates to their stack (webpack, react).
Once a year I update my webpack, React, and TypeScript versions. And this is for a completely custom webpack toolchain. I don't think that's unusual compared to other technologies.
When has React's approach to state management changed?

The only change I know of is the introduction of the useState hook, but you don't have to use it.

The React team has done stellar job of maintaining a stable API with very minimal breaking changes. The only major breaking changes I can think of is the move of React.createClass to react-create-class and replacing the lifecycle methods through a slow and steady push over multiple major versions. I'm sure there were some smaller ones, but nothing that required any significant amount of time to fix.

As far as build systems and tooling, that's only as complex as you want it to be and doesn't have to change with the seasons. I've been using the same Webpack/Babel/React setup on one of my projects for about 7 years now with minimal work on my end (the only major upgrade was Babel 6 > 7, and Webpack 2 to 3, which took about maybe half a day to complete both).

Talking about global state management (not local state/props), when we started working with React their recommended method of state management was via Mixins. Those became deprecated in 2017 (I think). They then recommended to use only higher-order components (HOCs) for state management. Last year they deprecated this in favor of hooks. The context API has changed several times as well, though since that was never meant to be an end-user API I think it's less problematic. They also deprecated a bunch of life cycle methods (e.g. componentWillMount), though that is probably also a minor nuisance.

As you said you can still use the old ways of managing state (except mixins I think which were really removed for good), the thing is just that most of the ecosystem of third-party libraries (routing, state management etc.) quickly moves to the latest paradigm, so if you do not want to run outdated code with potential security vulnerabilities you will need to constantly refactor your code as well just to keep up with the ecosystem.

You're conflating several different things: patterns specifically recommended by the React team, patterns in vogue in the community, specific libraries from the community, and actual API changes in React itself.

The React team did definitely tell folks to stop using mixins and try using HOCs instead [0]. HOCs have some limitations as well, and hooks are designed to help address those [1], but it doesn't mean HOCs are suddenly broken and you can't use them.

React's actual APIs are quite stable. As the React team has pointed out, Facebook has something like 100K components in their codebase, and many of those are still using older APIs. For example, even `React.createClass` still works. Granted, it was moved to an external package `create-react-class` package a while back because it's discouraged, but the API still works (and that's what had mixin support).

The community jumped on render props, and the React team never specifically recommended them as a generally-encouraged pattern that I know of. The only example of render props in React's actual APIs is the `<Context.Consumer>` component.

The context API never "changed", per se. There's the original `this.context` API, which is now definitely considered legacy and deprecated, _but_ it still works fine as of React 16.x. The new `createContext()` API, added in React 16.3, is a new API that solves the same use case.

The deprecation of lifecycle methods is real, but the React team has been warning about that for a while. Note that even in future code, renaming them to `UNSAFE_componentWillReceiveProps` will still work, and the React team has provided codemods to make that fix if you want to keep using that code as-is.

The churn in the resulting ecosystem is a more valid point of concern. React-Router is a frequent target of complaints. That's _partially_ justified, as their API has changed a couple times.

As a Redux maintainer, I'm very happy that we've managed to keep the React-Redux API stable across multiple major versions and internal rewrites [2]. If you were using React-Redux v4.x, you _should_ be able to jump to the current v7.x just by bumping the package version.

[0] https://reactjs.org/blog/2016/07/13/mixins-considered-harmfu...

[1] https://reactjs.org/docs/hooks-intro.html

[2] https://blog.isquaredsoftware.com/2018/11/react-redux-histor...

You're conflating several different things: patterns specifically recommended by the React team, patterns in vogue in the community, specific libraries from the community, and actual API changes in React itself.

This is fair, but I'm not sure how much it matters.

In reality, we build software as part of an ecosystem. Even if the foundation of an ecosystem remains stable, much of the value often derives from what is built on that foundation. It's the other tools. It's also the blog posts and forum comments and training courses and YouTube videos. It's also the collective experience of the community in using those tools, which is reflected in all of those sources of information, as well as simply passed on from one developer to another in person.

I'm not sure React can truly claim to be stable any more, though it's certainly done better at that than many projects in front-end web development. But even if that's true, the community has moved on from the older APIs to the newer ones. The new resources are built using the new APIs and written about the new APIs. If you're still using the older version of things, even things that React itself still intends to fully support, the reality is that you're going to be excluded from many opportunities elsewhere in the ecosystem.

Why would you want to use the old APIs for new code? Surely the benefit of API stability is that your old code that you don't want to change still works? It's not like they're introducing new things every week. It's more like once a year there are major new features, and the old ones still work.
Why would you want to use the old APIs for new code?

Consistency. A code base that has been maintained for several years but now does similar things in four different ways because of which APIs were fashionable at the time each of them was implemented isn't going to be great to work with.

Or maybe you just liked the old APIs better, perhaps because they were more helpful for your particular application than the new ones, or because some other tool or library you find useful works better with the old API.

Well, I'm glad you're happy with your work, just describing my epxerience working with React over the years and the frustration of having to keep up with an ever changing flow of changing paradigms and programming styles. People value different things in frameworks, for some frontend developers it's probably exciting that the community comes up with so many new things all the time and that they can learn a new state management paradigm every year and spend time refactoring their codebase, for me it's more a nuisance.

The problem of React is not that the core API is not stable, but that it's not a full framework for developing frontend apps as it misses e.g. routing and app-level state management, it only becomes useful in combination with libraries that provide this functionality (unless you want to write your own, which is also an option). It's the rapid pace of churn in the community eco-system that's a problem for me. Probably I'm just getting old.

I agree with you about the React team being very careful about maintaining backwards compatibility as much as possible. The API is however still a moving target, and some patterns or ways of doing things are actively pushed more than others. For example you can still use mixins and createReactClass now without any problems, but the docs and tooling all have one recommended way, which slowly shifts over time.

The problem just isn't with React though, I think the problem is with the culture that expects an opensource project to always be constantly evolving and putting out new things. I'm guilty of it myself... when checking out a library in github and I notice it hasn't been updated in awhile I get suspicious of it.

Been using react transparently through clojurescript's reagent for years and was never hit by any of react's API changes.

The problem usually isn't react, but that most projects using it directly use it wrong.

Browser APIs have changed quite a bit in the last 10 years. Yes, the same approaches are still supported, but there have been many additions and modifications to core APIs. Ten years ago you would have never dreamed of trying to build complex front end behavior without something like JQuery, but now it’s totally unnecessary as all browsers mostly adhere to the standards. I guess my point is I don’t think React has changed any more or less than browser APIs - both have just steadily updated best practices just like any other piece of software since ever.
> Browser APIs have changed quite a bit in the last 10 years.

They really haven't.

> Yes, the same approaches are still supported, but there have been many additions and modifications to core APIs.

Once again, there really haven't been.

Yes, there are many more APIs in general (audio, touch etc.), but on the whole it's the same old cumbersome poorly designed 90s-Java-style DOM API.

In 2010, browsers supporting rounded corners were considered exotic. It’s totally, totally different now.
yeah seriously... in 2010 i am pretty sure we were still rounding corners via background images in css
It's not a change. It's an addition of APIs (css in this case)
(comment deleted)
Just because the APIs remain largely backwards compatible does not mean that they didn't change. Just the fact that querySelector and querySelectorAll was introduced and started actually being usable across all the major browsers is a huge change IMHO.
I... I wrote that as my last paragraph:

there are many more APIs in general (audio, touch etc.), but on the whole it's the same old cumbersome poorly designed 90s-Java-style DOM API.

> things that worked 10 years ago still work today

I have vanilla-js code from 1998 that still works unchanged in 2020.

I think the main pain point is towards front end appearance/interactions. Js as a language has gotten more ergonomic, but it's been Turing complete forever. As a practical matter, the pain comes when you say "I want to align x" and come to learn that every browser has different flags to accomplish the task. I'm sure you've seen the fat stacks of moz/ie/opera checks and flags before. I know that example is bad, but I can't think of a good one at the moment, I rarely touch front end.
That is not the case anymore. Vendor prefixes are discouraged and seldom needed.
Doing interviews I've heard a lot of this - react is more efficient than using the DOM directly, etc but no one can tell me why - they are just parroting what they hear or get taught at coding camps and make a fool of themselves.
>The problem is building proper architecture, so code won't quickly turn into spaghetti [...] With vanilla JS it's the wild west.

This is a "problem" that I solved for myself years ago. It's not even that hard. I've started by noting that most of the issues with JS come from a few sources.

- Managing code dependencies.

- Navigating DOM. (Manipulating DOM is trivial.)

- Managing events.

- Synchronizing JS state with DOM state consistently.

If you pause to think about those, each of them has a straightforward solution that does not require a framework.

- Do not make libraries that directly depend on external code. Use DOM and HTML events for configuration and communication.

- Use CSS queries.

- Use timers or document-level events. They will continue to operate regardless of how elements change.

- Use DOM as your state storage. (Custom attributes + occasionally symbols.) This way your code itself is completely stateless.

There is more to it, but this is the foundation.

One of my favorite libraries is one that checks for specific attribute that contains a CSS query, then runs it, then outputs the result as a parameter on the original element. Couple dozen lines of code, countless applications. Best of all, you don't have to write any page-specific glue code. You load the library and it just works.

I disagree with storing your state on the DOM. Querying the DOM can be pretty slow, but also now you're state is going to be stringy-typed which will involve parsers and a whole mess of reasons you don't want that. If you want to keep the logic simple, a view should be a function from a state/model to some 'visual' representation (be it DOM, canvas, Qt, ASCII, a quilt pattern, etc).
A DOM node's attributes are strongly typed, but it is an object and you can still set Node.foo = barObject if you're so inclined. Not saying it's not without it's tradeoffs, but if you want state housed in the DOM rather than another state manager it's not hard to conceptualize.
I hope then someone in your team is responsible for continuously documenting these patterns, however trivial they may seem to the author. I use frameworks for their documentation more than anything else. Maybe it's the UK developer culture but I haven't come across any codebase that has even remotely useful documentation in the past five years in three jobs. These "intuitive patterns" only exist in the senior dev's head. New comers have to either constantly ask or figure it out slowly by going through source files. Homegrown "simple and intuitive" solutions only benefit the rockstar who wrote them, not the other members of the team who are there now and who will come after the rockstar is gone.

Please use well documented frameworks, otherwise we're trading away the entire teams productivity in favour of the rockstar to have his say.

This is a real problem, but I'm not sure the root cause is that senior developer.

We've been building software far more complex than any web front-end for many, many years. Much of it was built without the help of all-encompassing frameworks. Much of it has stood the test of time longer than any web app, too.

Doing this requires a basic understanding of general programming principles from all developers. It requires a solid understanding of software design and architectural concepts from at least the more senior developers.

These things aren't rocket science. Millions of developers around the world have these skills. Many books and conference talks and training courses have been created to pass on the knowledge and the important ideas behind it.

Unfortunately, lots of people get into web development without ever learning even the basic skills of their trade. They learn by copying and pasting snippets from Stack Overflow or some YouTube video they found, jumping from one trendy framework or tool stack to the next every five minutes, with no awareness that those snippets were often also written by people who never learned the basics. Rookie mistakes are everywhere, and the culture often favours shiny new things over solid, well built solutions to real problems.

You can't really fix this just by getting developers to use a well-documented framework. For one thing, a lot of those frameworks aren't great themselves, either in their design or (not coincidentally) in their longevity, because they too were written by people with limited experience and understanding. But even if you do find a good framework, if your developers don't understand how to use it and the trade-offs it makes, they will still make dumb mistakes. When you have requirements that can't be implemented by just joining one framework dot to another until you're done, you definitely want someone who knows what they're doing writing that code.

As is often the case, the key to improving this is probably better training, particularly in the early stages of a career. But that doesn't always work in business, where resume driven development means developers will stick around long enough to add a few buzzwords and then jump ship to a better paid job somewhere else, taking the value of any accumulated experience with them. Until businesses start looking for real skill instead of buzzwords when they're hiring and start rewarding real and growing skill with their compensation packages, unfortunately the cycle will continue.

What is the library you use for running functions based on CSS query?

I am working on a project where I initialize some DOM elements with data- attributes and control their visibility in response to a form input change event. It would be nice to somehow run the visibility check in more of a declarative/reactive manner without having to commit to writing my templates with a front end framework and build tooling.

Are there any reactive JavaScript frameworks that treat DOM and data- attributes as first-class citizens?

>I am working on a project where I initialize some DOM elements with data- attributes and control their visibility in response to a form input change event. It would be nice to somehow run the visibility check in more of a declarative/reactive manner without having to commit to writing my templates with a front end framework and build tooling.

Here is an approach you can use:

    const name = 'check-if';
    const aState = name + '-state';

    run();

    function run() {
        document.querySelectorAll('[' + name + ']')
            .forEach(update);
        setTimeout(run, 50);
    }

    function update(target) {
        let selector = target.getAttribute(name);
        let matchedSomething = document.querySelector(selector) !== null;

        if (target.getAttribute(aState) !== matchedSomething.toString()) { //only update when change is necessary
            target.setAttribute(aState, matchedSomething);
        }
    }
Usage:

  <style>
  [check-if-state="false"].conditionally-visible{ display: none; }
  </style>
  <div check-if="#input:valid" class="conditionally-visible"></div>
This exact code can be used for any styling based on any CSS query. It only allows one rule per tag, but in practice it's usually sufficient. In case you need multiple rules, you can wrap the original tag in another one. You can use data- attributes instead of customs, which will simplify the library somewhat at the expense of HTML readability.

You can use the same approach for enabling/disabling inputs.

If you need more fine-grained information to act upon, you simply write another library that adds it to DOM.

From what I have seen React is not better. It may not be spaghetti but then it is an exercise in architecture astronautics with way too many layers of indirection that is might as well be that spaghetti bowl.
Sometimes I question if people claiming vanilla is spaghetti have actually used vanilla in any meaningful way or if they are just parroting what others have said. I find that a lot of times, it's the latter...

For example, something that I've come to find cumbersome about frameworks is that expressing things in terms of states makes it more convoluted to express mutations. For example: in vanilla, one sensible unit of organization would be something like this:

   const doThing => {
     input.value = value;
     input.focus();
     sound.play();
   }
   button.onclick = doThing
Expressing `input.value = value` is what frameworks generally shine at, but expressing the method calls is usually clunky, since they represent effects and those can't really be expressed in terms of state snapshots. So, expressing them in a "frameworky" way usually just looks like some variation of this, but on top of some abstraction (think, e.g. React's useEffect nested anonymous functions + refs + probably context and a provider because you're not going to just initialize your sound manager in your component, right?).

I think frameworks are about colocating things in some specific way, and whether the colocation structure is "good" is largely a matter of herd acceptance. W/ older frameworks like Backbone and Angular, the focus was on colocating things to fit a MVC paradigm. And people were totally on board with that. With Redux, one colocates actions for a particular piece of state. And people sing their praises about this structure too.

With reaonably written vanilla JS, it's not that there's no colocation. One colocates mutations related to a single action. It may not be a "cool kid" organization structure, but it _is_ structure.

Of course, one can write bad vanilla JS, but that's also true about any framework.

Did you mean something like this?

   const doThing = event => {
     input.value = event.value;
     input.focus();
     sound.play();
   }
   button.onclick = doThing
(comment deleted)
I would do this identically in React.

   const doThing = event => {
      const input = event.target
      input.value = value
      input.focus()
      sound.play()
   }
   ...
   <button onClick={doThing} />
a) that doesn't do the same thing (button != input)

b) in React, it's extremely bad practice to mutate raw DOM elements programmatically (the idiomatic version is to use some state management mechanism and bind the value via `<input value={value} />`, which incidentally would be broken by this code)

c) setState may be asynchronous, so you can run into nasty surprises (e.g. you can't focus a hidden element). Whereas in vanilla code, unhiding logic could be added in a predictable procedural and explicit manner, in React a naive call to .focus() in the event handler may noop because of React-rendering-pipeline-specific reasons and then we need to get into its more obscure APIs to fix it)

Ah, your code sample was incomplete so I was extrapolating. I'm assuming the complete code would be:

  const input = React.useRef(null);
  return (
    <>
      <input ref={input} />
      <button
        onClick={event => {
          input.current.value = "value";
          input.current.focus();
          sound.play();
        }}
      >
        Button
      </button>
    </>
  );
Which is almost identical to how you would do it in vanilla JavaScript except you would grab input by a query selector and be less resilient against DOM mutation and your references becoming stale.

To point b there's nothing wrong with having an uncontrolled input. React allows you to use the raw DOM API if you'd like. You only need to use controlled inputs if they buy you something, and then the rewrite is a small diff:

  const input = React.useRef(null);
  const [inputValue, setInputValue] = React.useState("")
  return (
    <>
      <input ref={input} value={inputValue} />
      <button
        onClick={event => {
          setInputValue("value");
          input.current.focus();
          sound.play();
        }}
      >
        Button
      </button>
    </>
  );
This is adding a line of code (useState) but in this case it's buying you something -- you have full control of the value and are insulated against DOM updates.

For point c I'm not sure what you're referring to. I can't think of a situation where React would drop your call to `input.focus()` on the floor. I just tried breaking it by spamming state updates and was unable to. The whole point of React is that it handles DOM updates seamlessly and I would be surprised if it didn't in this case.

Sure, if you're using a ref and being careful not to bind `value` in JSX, you're fine. That's not what you were doing though. Here's a simplified demo showing a variation of the issue: https://codesandbox.io/s/react-example-bytg0

As for controlled/uncontrolled inputs and refs/hooks: that's kinda my point. In order to declaratively wire things up in an idiomatic way in React, we've had to introduce a bunch of React APIs to the snippet just to express the equivalent of a "when you click me, focus that guy" action -> effect relationship, because otherwise that relationship is hard to express in terms of declarative state snapshots.

You've misspelled the handler, onClick is the correct casing. Fix that and it works.

Also you don't need to use a ref -- if I were inclined I could have grabbed the element by a query selector. I'm not sure why I would though, as I mentioned using ref is better protection against DOM updates.

> In order to declaratively wire things up in an idiomatic way in React, we've had to introduce a bunch of React APIs

Yes, because declarative programming is the benefit not the cost. As I said, you don't have to do it declaratively -- you can always use built-in DOM APIs -- but most people in the front-end community have agreed that doing things declaratively and architecting a UI as a state machine instead of a giant tree of independently mutating bits is preferable.

One of the biggest sources of bugs in jQuery projects is developers forgetting to keep the DOM in sync with the data. The benefit of doing things declaratively is you don't have to worry about it. Cutting that problem off at the source is an invaluable benefit.

He knows. He's the author of https://mithril.js.org/.

It's a person well-steeped in the theory and benefits of declarative and functional programming taking a step back and looking at the supposed enemy with fresh eyes and a deeper perspective.

Simple and clean, almost like DOM Level 0

    <input id=input />
    <button
      onclick='
        input.value = "value";
        input.focus();
        sound.play();
      '
    >
      Button
    </button>
Where does `input` even come from in your code? That's invalid syntax. Was it supposed to be `const foo = input =>{...}`?

b) It's kind of a bad practice to mutate raw DOM elements programatically without react, if it leads to horrible spaghetti code further down the road

const doThing = event => {}

function doThing( event ){}

Why does everyone seem to be using the first format? Isn't the second version a lot more readable/pretty? Even worse is when doThing is immediately exported and not refferenced anywhere else, but still there is this need to assign it to a const.

Arrow functions help save you from `this` insanity.
I agree, but do all functions use 'this'?
No, and part of the reasoning is to explicitly avoid the chance you might accidentally refer to the wrong `this`. There's an ESLint rule to enforce this: it will complain if you use a `function` without referring to the prototype this. Makes it handy because if I do use `function` I know it's because there's a reason -- e.g. some libraries still make heavy use of the local this.

https://eslint.org/docs/rules/prefer-arrow-callback

The rule you link to is specific to "function expressions", which may or may not use 'this'.

To ask the same question differently, what about functions that do not need 'this'?

I'm not sure what your proposal is -- use functions that use prototype this or no this, and arrow functions for ones that use contextual this?

It's easier to use arrow functions for everything except for the tiny minority of cases where you want prototype this.

Many reasons.

1) Hoisting + mutability

  a = 'lol';
  function a() {}
  a() // error
2) one-liners

  const findByName = (list, name) => list.find(item => item.name === name);
  //vs
  function findByName(list, name) {
    return list.find(item => item.name === name);
  }
3) signaling that `this` keyword usage should not happen
And when you don't need any of that, how do you signal that you do not need it?
3 reasons that I can think of:

1. You can implicitly return things so it provides nice syntactic sugar

2. Using an arrow function results in `this` being bound in the way you'd expect (coming from something like C++) in all cases without having to call .bind(this) anywhere. I'll never forget seeing promise chains starting with `const that = this;` in order to keep the right reference throughout the promises.

3. You use it for the previous 2 reasons and use it everywhere in order to be consistent

I agree with one and two, and really appreciate arrow functions in those two, and other appropriate use cases.

With three, I disagree. It is kind of like saying let us just use var everywhere to be consistent.

I fall into category 3 which is why I list it. It's not a technical reason so much as a code style reason so it is definitely subject to the opinions of each developer.
It is much more than a matter of code style.

For example, an arrow function accessing variables outside its scope is much slower, something you will notice when processing a lot of data in nodejs.

And if you're working in the browser and trans-pilling down to ES5, babel needs to do a lot more work.

But as long as people are aware of the trade-offs, they can use whatever works for them.

> For example, an arrow function accessing variables outside its scope is much slower

That doesn’t sound true. Do you have any evidence? (Under an uncommon JavaScript engine?)

Looking at your comment history, seems like anyone who technically differs with you gets downvotes, I'm sure that's not how it supposed to work, bring it on anyway.

> That doesn’t sound true. Do you have any evidence?

Do you have any evidence to the contrary? I have experienced it when processing heaps of textual data in nodejs (the same engine that runs chrome). My script was crashing for no apparent reason, and just changing the arrow functions solved it. Remember, an arrow function shares the same scope with it's parent function, so when I say outside it's scope, think grand-parent or higher.

> Looking at your comment history, seems like anyone who technically differs with you gets downvotes, I'm sure that's not how it supposed to work, bring it on anyway.

Probably a side-effect of what I usually choose to comment on, which are things that are objectively wrong or seriously misleading :) I think the HN voting system is poor, so I don’t use it, myself.

> Remember, an arrow function shares the same scope with [its] parent function

Exactly like a non-arrow function, then?

> Do you have any evidence to the contrary? I have experienced it when processing heaps of textual data in nodejs (the same engine that runs chrome). My script was crashing for no apparent reason, and just changing the arrow functions solved it.

Not only is that not evidence, it doesn’t support what you originally said. Slower ≠ crashing for no apparent reason.

If you mention which version of Node this was, I can go looking for evidence.

> Probably a side-effect of what I usually choose to comment on, which are things that are objectively wrong or seriously misleading :) I think the HN voting system is poor, so I don’t use it, myself.

Do you have any evidence that you do not use it?

> Remember, an arrow function shares the same scope with [its] parent function >> Exactly like a non-arrow function, then?

No, not exactly. It looks like I need to be more explicit, here goes: Remember, an arrow function's BODY shares the same scope with its parent function

> Do you have any evidence to the contrary? I have experienced it when processing heaps of textual data in nodejs (the same engine that runs chrome). My script was crashing for no apparent reason, and just changing the arrow functions solved it. >> Not only is that not evidence, it doesn’t support what you originally said.

It is called ANECDOTAL evidence, and yes, it is a thing. If you want SCIENTIFIC evidence, sorry I just do not have the time and energy. If you want to believe that arrow functions are a drop-in replacement for normal functions and that they are always better and faster in all situations, go ahead and believe that. And you'll do just fine, as long as all you are doing with JS is React and basic UI wrangling stuff.

> Slower ≠ crashing for no apparent reason.

My friend, this is a discussion, not a scientific thesis or a legal document. I do not have to explicitly explain every little detail and cover every little phrase so that someone does not misqoute me. Be generous enough to try and understand something someone is saying. So, to rephrase that too, when I say "crashing for no apparent reason" I mean "crashing for no apparent reason that I could find by looking at the code over and over again searching for bugs or typos". And yes, it was crashing due to timeout and memory issues. Please dont start arguing about how crashing and timing out are not technically the same thing.

> No, not exactly. It looks like I need to be more explicit, here goes: Remember, an arrow function's BODY shares the same scope with its parent function

Exactly like a non-arrow function, then?

I don’t mind if you don’t have the energy to support your claim, but I will recommend that you don’t make claims like “arrow functions are slower” if you can’t back them up properly or even provide any detail.

I also get the impression that you don’t know how arrow functions actually differ from non-arrow functions (see above), so your anecdote that you couldn’t figure out the bug doesn’t make a strong case.

> Do you have any evidence that you do not use it?

My browser was crashing for no apparent reason and stopping voting on HN solved it.

¯\_(ツ)_/¯ Whatever dude, I'm done here.

Have a nice day!

javascript function does too much.

It is both method and closure. Which is not universal - io has method and block, ruby has def and block

And it is constructor. So it can be called both with and without `new` with different results. Other can't:

    arrow = () => {}
    // new arrow()
    // TypeError: arrow is not a constructor

    object = {
      shorthand() {},
      ['computed']() {},
      get getter() {}
    }
    // new object.shorthand()
    // TypeError: object.shorthand is not a constructor
    // new object.computed
    // TypeError: object.computed is not a constructor

    // getter = Object.getOwnPropertyDescriptor(object, 'getter').get
    // new getter
    // TypeError: getter is not a constructor

    class Class {
      static staticMethod () {}
      method () {}
      get getter() {}
    }
    // Class()
    // TypeError: Class constructor Class cannot be invoked without 'new'
    // new Class.staticMethod
    // TypeError: Class.staticMethod is not a constructor
    // klass = new Class
    // new klass.method
    // TypeError: klass.method is not a constructor
    // getter = Object.getOwnPropertyDescriptor(Class.prototype, 'getter').get
    // new getter
    // TypeError: getter is not a constructor

    function* generator() {}
    // TypeError: generator is not a constructor
    // new generator()
I actually was surprised just how many ways TC39 introduced so we do not use function. The change you observe is not a coincidence - it is carefully crafted.
Let me get this straight: Are you saying all the changes in arrow functions, the class syntax and generator functions were all a carefully planned initiative to get rid of the "function" keyword because it does too much?
Yes, replace "function" usage with safe alternatives. And don't forget 'use strict' - it affected "function" too.

"function" is too entrenched. It's usage as a constructor appeared even before .prototype:

    function Cat() {
      this.say = function() { return 'nyan' }
    }
All the confusion about javascript object system is because of classes which have no name, we call them by their constructors. Give them real names:

    Cat = class {}.prototype // or function {}.prototype
    Cat.say = () => 'nyan'
    cat = new Cat.constructor
    cat.say()
    cat.__proto__ === Cat
A little bit inconvenient... oh! it's everywhere:

    cat instanceof Cat.constructor
    Tom = class extends Cat.constructor {}.prototype
And all the base classes are constructors

    Object = Object.prototype
with their helper methods, it should be separate like Reflect and Math:

    Reflect.create = Object.constructor.create
    object = Reflect.create(Object)

There is no simple answer, breaking change is not an option, let the planned obsolescence begin.

And it works! Slow but steady so much done since 2012 http://brendaneich.github.com/Strange-Loop-2012/#/

Ok.

I'm not convinced at all, we'll simply have to agree to disagree on that.

And I'd love to see the codebase of a JS app that completely bans the "function" keyword. Any links or examples?

Anecdotal if you're interested: I can't show it since it belongs to the company, but I just ran a grep in the app I architected and it has exactly 21 instances of the word "function"... some are comments, but most of the ones that aren't are inside a lodash debounce function. Total of 140000 non-blank/non-commented lines of code.

Btw, it's not banned, and I never really enforced it... but since I never use it myself, I guess the others devs picked it up?

It's in Vue.js, and in Vue you rarely see old-style functions anywhere, so there's that.

That's interesting. However, the Vue.js library itself uses the "function" keyword a lot, and the library is part of your applications code. Infact, it uses normal functions almost exclusively.

source: https://raw.githubusercontent.com/vuejs/vue/dev/dist/vue.com...

Furthermore, the official Vue documentation explicitly discourage the use of arrow functions in some places, so whoever set that rule just did not know what they were doing, sorry if that sounds harsh.

source:

- https://vuejs.org/v2/guide/instance.html#Instance-Lifecycle-...

- https://stackoverflow.com/questions/43929650/vuejs-why-is-th...

Saying all arrows functions are bad and evil or that all normal functions are bad and evil is nothing but dogma. Each has its own place and uses, it seems many JS devs would rather not think of this at all and just use one form everywhere.

We're not using arrow functions for everything. Why are you assuming this?

We're using shorthand syntax in methods inside Vue.js objects [1], they also don't need the "function" keyword. In fact, they are suggested in the second link you posted, please read again. Arrow functions wouldn't even work in this situation.

We're mainly using two forms: shorthand and arrow. That's how we only have 21 instances of the "function" word in our entire JS codebase, and we could remove all of them if we wanted. That's what you asked for: a "JS app that completely bans the 'function' keyword". Well, we don't ban but it's possible.

And please read my comment again: I explicitly mentioned that this is not a rule, and I never enforced it. The team (39 committers ATM) reached that result organically, mostly influenced by my own personal style.

And sorry if this sounds harsh, but it seems that you have extremely limited knowledge of Javascript and ES6, so I'd suggest learning before you make such claims before you make a fool of yourself.

Btw, you're seem to be the one holding on to dogma here, since you seem unable to accept that the keyword is not strictly necessary in a large app.

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

shorthand object method syntax === regular function

shorthand object method syntax != arrow function

> We're not using arrow functions for everything. Why are you assuming this?

Because you said "but I just ran a grep in the app I architected and it has exactly 21 instances of the word "function"... some are comments, but most of the ones that aren't are inside a lodash debounce function."

Seriously, am I in some kind of twilight zone or something? Because that statement suggests that there was a goal, and the goal was to get rid of "function" but lodash debounce ruined the anti-function-keyword cult party.

Who runs a grep on a whol;e web app to see if there are any "function" keywords, then shamelessly turns around to say "We're not using arrow functions for everything.". If you know you are not using arrow functions for everything, WHY GREP THE WHOLE CODEBASE LOOKING FOR "function"? And whats all that about "some are comments". Right? Phew! We did not really use it, they are just comments. We did not really use that old, evil 'function' keyword. It was just comments... we're too cool and hip for "function". LOL!!!

> And sorry if this sounds harsh, but it seems that you have extremely limited knowledge of Javascript and ES6

Hilarious! Bwahahahahaaaaaaaaaaaa! Thank you sir for your information, all this time I thought I knew, but you've corrected me. Now I know I don't know. Thank you genius.

First of all, are you aware of shorthand methods? Are you aware that you can have non-arrow functions without the "function" keyword :) ES6 has grown :)

And there was no goal intended with the grep. This is what you wrote:

> And I'd love to see the codebase of a JS app that completely bans the "function" keyword

I just grepped "function" to give you a personal anecdote of an app that doesn't need to use the "function" keyword much.

That was the first time I interacted with you, I was trying to be nice then, and you were completely hostile. Some of the replies were completely uncalled for.

---

EDIT: You just edited your message to add the part about shorthand methods. My point still stands. I never claimed to be only using arrow functions (in fact, you're the one who DID claim I was only using arrow functions!). I only claimed we rarely use the "function" keyword.

I do that all the time. Just after typing, I notice some typos or something that could be worded better and I quickly go and fix it. I have never edited a comment after seeing a reply someone had made to it, and I don't even think HN let you do that.

And its funny that you say you're trying to be nice while dropping comments like:

> it seems that you have extremely limited knowledge

> I'd suggest learning before you make such claims before you make a fool of yourself.

I see you flagged my comment above, maybe you should flag yours too.

(comment deleted)
Sorry, typo

>> Yes, <typo>they</typo> replace<typo>d</typo> "function" usage with safe alternatives. And don't forget 'use strict' - it affected "function" too.

> I'm not convinced at all

It could appear I've tried to convince you not to use "function". That never was the case, should have added at least one. And I do not agree with TC39 direction, just making observations. Please check my comment assuming that and typo.

My fix would be different. Prototype based inheritance is awesome http://iolanguage.com/tutorial.html and javascript could be as simple too:

    Object
    Object.__proto__ === null

    object = new Object
    object.__proto__ === Object
    object.constructor === Object.constructor
    object.toString === Object.toString

    f = new Function
    f.__proto__ === Function
    fun.constructor === Function

    object.private = function () { return 'hello' }
    Object.shared  = function () { return 'world' }
    Object.constructor.static = function () { return '!' } // we need functions
with just a simple change

    Object = Object.prototype
    Function = Function.prototype

    syntax new = function (ctx) {
      let ident = ctx.next().value
      return #`new ${ident}.constructor`
    }
It looks almost boring (just don't redefine .constructor). Now this one is much harder:

    Object.prototype
    Object.prototype.__proto__ === null

    object = new Object
    object.__proto__ === Object.prototype
    object.constructor === Object
    object.toString === Object.prototype.toString

    fun = new Function
    fun.__proto__ === Function.prototype
    fun.constructor === Function

    object.private = function () { return 'hello' }
    Object.prototype.shared  = function () { return 'world' }
    Object.static = function () { return '!' } // we need functions
I'd say the bigger problem with vanilla JS or any other imperative UI framework is exactly that, the imperative nature of these tools. React introduced the frontend world to a declarative approach for keeping the DOM in sync with your state. Until we have something similar in the native API, React and co. will continue to exist.
It really depends how much complexity you shift to js - if most of the work is done on the server, you really don't need to lean on js very much and you can have relatively simple js which just annotates certain elements and updates content in response to user actions. You don't need a framework if you're not trying to shift the entire view layer to js.
The problem with frameworks is that they tend to drive the functionality of the site itself. It's easy for developers to start thinking in terms of what fun new things the framework allows rather than what the site actually needs.

I think frameworks are great, but you have to develop a self restraint from using every bell and whistle that's in it.

You do the same with "vanilla" that you do with frameworks: organize your UI into components and everything into modules.

You don't need frameworks for any of that.

You can use Svelte and get pure DOM manipulation (fast, tiny) and a great framework to collaborate under.
On the topics of speed and lightness: does Svelte really have a proven track-record in real-world usage at this point? I understand that it has a neat compiler and some clever ideas behind it (no virtual-DOM), but still.
"and developer just have to follow good practice"

Uhm, the exact same is true with vanilla js.

If you write crappy code, your code will be crappy even if you use a framework.

I learned jQuery on a project where everyone was expected to be full stack but only 2.5 of us could do any deep work on the front end.

I have done much, much harder things than convincing my coworkers to distinguish between 'important' nodes in a composition and incidental ones. Never put the incidental ones in your selectors.

If I'm a "Select All" checkbox, I need to find all of the checkboxes in "my" block of HTML that are not me, and select or unselect them. I don't give a shit if that's two divs up, one over and three down. Or if some IE bug means now it's three divs up and two over. I care about some top level element, and any of its children at any depth.

That's it. If I write my element selectors that way, I'm done and the layout people can put in a scrollbar later, or an expando. Also if I write my CSS the same way, it's easy to make these sorts of changes and it's easy to correlate the CSS with the Javascript that affects the same elements.

So much simpler than spending all day in a debugger when you're not in bug triage.

Most of those query selectors we relied on now have feature parity in the spec. I don't see why you couldn't use the same strategies in a vanilla situation today.

Could you expand upon what you mean when you say a checkbox has "my" block of html? That a given element should not make changes in elements that are at a higher level in the tree?

Also, what are important and incidental nodes?

There are a bunch of elements we add to the page or remove to get certain visual effects to work well but they really have nothing to do with the logic of the page. Few if any interactive components ever care about them, or only for one specific interaction.

Classic example of the 'only one interaction' situation: the coworker who thinks he can use string concatenation for query parameters and you know that if you just wrap it in a form element, all of that is cheap or free and you just have to hook the form submit event to turn it into an AJAX request instead of a navigation. But that means that you've wrapped all of his DOM in a form element and now all of the CSS and half of the handlers stop working because they're looking for body>div>div>option and now it's body>div>div>form>option and now you wish you hadn't even touched this stinking pile but it's the principle and by god you're gonna finish this.

Or you had a block of elements on a page and now your boss wants it on the other side of the page, on another page, on every page, all over this page, or on a completely separate site.

What you want to solve these problems in a way that mostly stays solved is to try for a query selector with the lowest specificity (and no IDs) that still exactly identifies the DOM elements you are looking for. So there is some titular 'owner' element that all of these interactions are contained in, and they find each other by walking up until they find a particular shared parent and call parent.querySelectorAll() to find their peers, and only their peers. Not some other random element halfway down the page.

So for instance a click on .preferences .selectAll should find the first parent with class 'preferences', call querySelectorAll(".options"), and then invoke foo.selected = true on all of them. Not parent.parent.parent and then down through div>div>ul>li>input[type="checkbox"]

Frontend development is a tricky beast because its hard to separate business logic from view logic. Since all your code relates to the view, its temping to just stick all your code into the view component or controller. This makes your components huge, untestable, and brittle. An great frontend developer will keep extracting models and business logic from view code until the view code is lean and really only renders. Some things are easy to extract like http calls or parsing logic. Other things are harder to see - like logic that might drive a step wizard. Even code like this can be expressed in plain models with plain functions, but its a lot harder to see and extract. Most people don't get there, or just don't care, so many frontend codebases end up with spaghetti view modules that you edit and pray things still work.
(comment deleted)
I've been maintaining a complex web client for 14 years.

Every single time we have used a framework it has made development harder, and more fragile.

In addition within a few years either the framework is abandoned, or changed to be incompatible with what has been implemented.

Staying away from frameworks completely would have saved us more time in the long run.

Could you share some lessons learnt and architecture tips?
Only if you are building standard things IMO.
THIS a x1000 THIS !! There will never be a perfect framework, and jquery for a multi-person big project. It WILL be a mess in due time ! a Framework(even the most of the crappy ones) at least give you some opinionated standard ways of doing stuff. You can't pay me enough to work in jquery straight... Not saying it can't happen with frameworks. Just saying if you do a 100 projects with jquery or 100 projects with frameworks... There will be more chance the jquery ones will be a mess.
> With vanilla JS it's the wild west

The thing I really, really like about Vanilla JS is that it has 0 (zero) dependencies.

If something breaks in Vanilla JS, you know with 100% certainty that it's your code that's failing. With a framework, it's mostly the fault of your code - but there's always an outside chance that it's somebody else's fault, buried deep in some 3rd party dependency that may-or-may-not have been maintained.

I like React and Vue (I love Svelte!) - on a well-planned project they can perform miracles. But I see no reason to hate on Vanilla: it has its place too ... if you know what you're doing.

> If something breaks in Vanilla JS, you know with 100% certainty that it's your code that's failing.

Or the browsers' code which is a bigger problem.

I've been burned in the distant past by a blackbox framework that didn't work well with my use case (JSF) so I can sympathize with your position. These days I'd rather hit the occasional framework and polyfill bug than deal with a wide range of interopt issues.

> If something breaks in Vanilla JS, you know with 100% certainty that it's your code that's failing.

If you're lucky enough to have the same developers for the duration of the project. Otherwise it'll be your predecessor who worked at the company 4 years ago's code. I've had to do far too much "reverse engineering" of "we don't touch that" code.

On the other hand, I've literally never encountered a bug in React. I guess it must have them. But I think not all that many.

I don't disagree. I still live in hope that one day I'll work on a project where all functions and variables have relevant and informative names and the Runbook is (accurately!) updated with latest changes on a weekly basis.

The point I was trying to make wasn't about previous developers on a project. Rather, it's the way frameworks ask me to trust them about the choices made by unknown developers to include NPM packages by other unknown developers in the framework's build. That, to me, is the definition of "wild west".

React is backed by Facebook. When it comes to frameworks I'm a lot happier to trust an open-sourced codebase backed by a company with a big vested interest in making sure that all the NPM modules they include (and all their dependencies, etc) are solid, safe and up-to-date. Even so, React's package.json file lists a devDependency for core-js - whose main developer is currently serving 18 months in a Russian jail[1].

How much trust we choose to put into other, unknown developers and their code is a risk to any project, is all I'm saying.

[1] https://www.theregister.co.uk/2020/03/26/corejs_maintainer_j...

I think vanilla JS inside the components is the way to go.
It doesn't have to be wild west but I don't disagree it usually turns into that.

Before frameworks I spent a lot of cycles learning (usually the hard way) how to organize jQuery/JS code so it wasn't a total mess. I like to think I finally got it fairly maintainable for reasonable sized code bases. But by that time existing frameworks made a lot more sense so that's a bunch of thinking I'll never get back. I would guess I'm not the only one in this situation either.

Here's a really good book BTW if someone isn't aware of it.

https://addyosmani.com/resources/essentialjsdesignpatterns/b...

that sounds like a you problem, not a js problem. i always prefer vanilla libraries because i only need to know js, not js and a framework. if you need a framework to stop someone from designing something poorly, they are probably not very helpful to begin with.
A trick I use to make the JS code more maintainable is to wrap code into pure functions that returns an element. For example if you need an input that only accept numbers: var input = makeInputThatOnlyAcceptNumbers() where the function returns the element, and all nitty gritty state handling is done inside the function.
Well at least with vanilla JS you know your skills will be useful again in the future. With frameworks such as Angular or React, they can disappear and be replaced by the next flavor of the month pretty fast.
That's true of every language. It's the software developers job to build the architecture.

I am an advocate for frameworks in commercial projects, for ease of knowledge sharing, speeding up onboarding and having a strong architectural philosophy built in. But we can't forget that we are the makers, we make the frameworks. React and friends are Javascript, anything they can do we can do too.

I am happy to use them for work. But I find all frontend frameworks too tooling heavy and full of arbitrary details you have to learn once and promptly forget. In my personal projects I have a simple architecture I use to organise my code in vanilla JS, no tooling and it's simplicity lends well to small projects sprinkled with only some dynamic UI.

(comment deleted)
Interesting pattern, first time I saw this:

        switch (true) {
            case cellA > cellB: return 1;
            case cellA < cellB: return -1;
            case cellA === cellB: return 0;
        }
Source: https://htmldom.dev/sort-a-table-by-clicking-its-headers
I had to think for a sec to get this. And this already makes it worse than 3 if statements. Does anyone really find this more readable?
Coming from a lisp I often wish other languages had `cond` so I don't have to nest if statements. This looks like a poor man's cond.

So yes, I do find this more readable. It makes it clear that only one branch will get executed.

This would be equally clear if the author had just used a sequence of if statements with a 'return' in each one. (Note that Javascript's case has fallthrough, so you can't immediately conclude that only one branch of a case will be executed.)
You don't have to nest if-statements and I would say nested-if is wrong. You simply use else-if. It's a flat structure just like cond.
you mean two if statements. The last case is a default return.
Interesting at first glance, but what is the performance of this? It looks like all cases would have to be evaluated before picking one, so even slower than an if-else-if.
Isn't it going to short-circuit with the return of the first truthy statement?
The expression immediately to the right of each 'case' keyword is evaluated before the resulting values are compared to true.
(comment deleted)
If that's the case, then wouldn't both "asdf" and "qwer" be printed to the console when executing the following code?

  function test() {
      switch (true) {
          case console.log('asdf') === undefined: return 1;
          case console.log('qwer') === undefined: return 2;
      }
  }
  test();
Hmm, I wrote some similar test code before writing my comment, but only included one 'case'. Indeed, you're right, they're evaluated only as needed.
I think you can just do:

    if (cellA > cellB) return 1;
    if (cellA < cellB) return -1;
    if (cellA === cellB) return 0;
Why is the switch better? Or even (less explicit, but shorter code):

    if (cellA === cellB) return 0;
    return cellA > cellB ? 1 : -1;
A switch is literally a series of chained ifs. In most languages ir takes the form of a series of

    If(Variable == $CaseValue){
      Yield $CaseBody()
    }
But in some languages, like js, nothing is preventing you from hacking it to do something different.

EDIT: Just how petty, sheltered and dumb does a person have to be to downvote a statement of fact and then not leave a response to justify that? Grow up already.

In that case you're not really hacking it.

If you think about what a switch does and how it works, it makes perfect sense. It's just a bit unusual to do it that way.

Is it not though? By exploiting the conditions to evaluate to true == $CaseValue you're subverting the expectation that the choices all rely on a single variable, all the while breaking fallthrough and default.
(comment deleted)
'Hacking' doesn't even begin to cover it.

How about we don't `break` like we should (!) and instead have fallthrough¹ cases that execute several cases— or more —on purpose²?

Oh, switches. Always the horror. In networking they somehow replaced bridges, but it's the same thing (that was never confusing to anyone, obviously). In (my) programming, a switch so often turns out to be a nice dressing hiding some horror pattern. And that Nintendo thing... nice games but 720p 30fps? Really??

When I re-read / refactor, I've got this nagging phrase in my mind, whenever I see one: “Kill the switch! Death to switches!”

To conclude this perfectly balanced and nuanced opinion (!): some switches find their place; but most don't, and never should.

____

1: SO: Should fallthrough be “allowed”? I move that whatever congress runs your country should outlaw it! But exceptions can be made... https://stackoverflow.com/a/188506/5376417

2: Book: (NSFW // Programming horror // mutilated code in this example) https://eloquentjavascript.net/02_program_structure.html#h_j...

(upvoted you, if only to balance the weird ones)

(note: this comment is meant absurd. do not downvote yourself into a reading mistake, the tone is funny ;-) Vanilla Javascript is funny.

It makes it clear that you're going to execute only one of the possibilities. Maybe that's clearer than a page full of ifs. But yeah, not particularly fond of the idea.
Except JavaScript switch has fallthrough, so it doesn’t make that clear at all. (Sure, no fallthrough happens with return in each case, but neither would a bunch of plain if ... return.)
hah, well then you can of course continue...

    return (cellA === cellB) ? 0 : (cellA > cellB ? 1 : -1);
Keep going:

    return (cellA > cellB) * 1 + (cellA < cellB) * -1;
More:

    return Math.sign(cellA - cellB);
You don't need the * 1 multiplication:

   return (cellA > cellB) - (cellA < cellB);
does work for NaN... rookie mistake, eh
Math.sign trick doesn't work for strings.
That's true, but the default string comparison sometimes isn't that useful, right? I somehow assumed the data is numbers only, rookie mistake :)

    'ana' > 'Bob'
    '2' > '123'
You usually want to clearly define the order or pre-process the strings in some way (trim them, same casing, etc).
(comment deleted)
honestly? i like it. properly formatted it looks alright:

    return (
      (cellA === cellB) ? 0 :
      (cellA >   cellB) ? 1 :
      -1
    );
and it's an expression, so i immediately know it won't do any weird control flow. i'd prefer "if/then/else" vs "?/:" but it's not bad
This works fine if the ? operator is right-associative, but in PHP it's left-associative and you have a subtle bug.

I find a better indendation style for this is more like

    condition
        ? truthy
        : falsy
i use that style too sometimes, depends on what's clearer. IME the former usually works better if you have a multiple tests, but the latter is the only readable option if you need to break a case across lines.

yeah, ternary-if is busted in php :/ (far from the only thing that's busted there though...) i'm actually doing some PHP work right now, and never chain ifs to avoid this exact thing.

Switch statements indicate "it's one of these things", whereas in the series of ifs any of them could be true. Using a switch statement tells the reader that you expect one of these things to happen [0]. Using a series of ifs tells the reader that these things might or might not happen depending, and they're going to have to read each statement to work out which.

Your last version doesn't tell the reader what your intention is at all, and they need to work out what you're trying to do here. It's a lot less readable. Unless you're desperate for those bytes, it'd be better to use the switch statement for this case.

[0]: This gets a little weird in languages like JS where switch statements fall through to the next one if you don't break or return, but generally it still holds true.

I don't think this line of reasoning makes sense, since as you acknowledge, JS switch has fallthrough. I would not immediately assume that the coder's intent was for only one branch to execute if I came across a 'switch' in some JS code.
That's not how switches work: a switch can (and will) trigger lots of cases if you don't either `break` (highly unintuitive to new programmers, who like you believe switch is "do one of these") or `return`, either of which cuts cuts the switch short.
With if you can also indicate "it's one of these things" by throwing an error at the end:

    if (cellA > cellB) return 1;
    if (cellA < cellB) return -1;
    if (cellA === cellB) return 0;
    throw new Error();
Let me tell you about if..else!
(comment deleted)
Adding 'else's to the above code would make it superior to switch by these metrics (e.g. no fallthrough).
You should not use switch in JavaScript, because it is a language where switch requires break, which means it's 100% going to bite you in the ass unless you have a linter that checks for the break. It's not worth it for such a simple case.
both fragments are incorrect for NaN...

The correct is return a<b?-1: (a>b? 1 :0)

var a=NaN, b=1; a<b ? -1 : (a>b ? 1 : 0); // 0

var a="a", b=1; a<b ? -1 : (a>b ? 1 : 0); // 0

The switch and if statements would return undefined in these cases. Or others threw an error if none of the conditions matched, that would work too.

You're seeing it for the first time because it's a bad pattern. It's confusing to a reader who is expecting a typical switch use-case, and it has no performance benefit over a series of if statements.

I don't know about V8, but a lot of compilers would have a harder time optimizing this because of the strange structure. For mature compilers and naive (i.e. not-yet-profiled) projects, it's better to write what you mean and let the compiler optimize it.

Go does this too, and it's actually OK once you get used to it. The switch statement is still saying "it's one of these things"
That entire example in general reads more like a cautionary tale about coding yourself into overly-specific clunk in the service of staying 'vanilla'. The 'type' of things being sorted is hardcoded into the html of the table and the actual js code. The comparator function has specific logic just to handle ascending and descending sorts of that that particular table. This one 'simple' example is already more convoluted and brittle than it would be even if you 'reinvented' your own framework-like thing.
The modern code is:

  return cellA.localeCompare(cellB); 
Because cellA and cellB are always strings:

   const cellA = rowA.querySelectorAll('td')[index].innerHTML;
If using a framework, you would generally have typed JSON data, which is better. For example, makes number columns sort correctly (example code above sorts ‘10’ before ‘9’).

Dealing with cells of tables is one area where code optimisations are needed if you care about performance and have a large table. There are multiple obvious problems e.g. looping over calls to querySelectorAll.

That switch(true) statement is not what I would expect from a more experienced developer. It is show-off code that looks cute and works, but the compromises are not worth it (statement order is not obvious, if you make a mistake and two cases are true then do you know which wins, it could easily deoptimise the JIT compiler because it is doing something uncommon, I would worry how debuggers and code compressors would handle more complex cases, and understandability is poor for new devs IMHO).

Great resource. I'm wondering whether the examples are your own or copied from across the web?

I just wanted to point out that some of them are a bit outdated, and I belive it'd be nice to maintain this list as a reference with modern approaches.

For example, there's no need to use `appendChild`, because DOM today has a more versatile `append` method.

And `[].forEach.call(cols, function(col) {...}` would look much better and more declarative as `for (const col of cols) { ... }`.

These are just first 2 examples that I noticed.

Your proposed changes are not supported in IE 11. The snippets are advertised as IE 11+ compatible on the landing page.
You're correct, but let/const don't have full support in IE11 either. I understand that people are still supporting IE, but still, this website could stay relevant longer if the examples were written in ESNext.
Pretty cool!

One thing that would massively improve this is if they were written as singular standalone blocks instead of sparse collections of snippets; I'd like to be able to grab, say, "make an element draggable" and toss it on my codebase as an isolated behavior.