How to manage HTML DOM with vanilla JavaScript only?
htmldom.dev
htmldom.dev
You know where vanilla JS still has a legitimate usecase in the era of SPAs? Landing pages.
- Mostly static HTML, time to first render is critical, all you want is a little bit of (progressively added) flair
- Can be inlined for instant loading/execution, no bundle download (or SSR) necessary
- Code has low volume and scope so structure / spaghetti isn't a concern
- You can separate it out from the rest of your SPA bundle(s), so shipping changes is completely decoupled from your SPA CI/CD process and can be done as frequently as you like and very quickly
- You can separate it out from the rest of your SPA bundle(s), so shipping changes is completely decoupled from your SPA CI/CD process and can be done as frequently as you like and very quickly
I mean sure I guess I could do a lot of extra work to separate it out, it's true. But the real benefit of a vanillajs landing page is stuff is simple, and getting all the benefits by pre-rendering and hydrating using a system like react-snap sounds difficult.
If we follow the old saying Simple things (to say) should be simple (to do) it implies to me that Difficult things to say will be (relatively) difficult to do.
In creation, React breaks up large parts into smaller components. In distribution, it renders them at runtime, not build time (with a standard create-react-app app). However, there is no reason to have both at once. Components make the page easy to reason about, and they can be used to compile a site at build time, as Svelte does. React also has its own libraries for this, like Gatsby and Next JS. You do say that the landing pages have low volume but they can certainly grow to encompass a larger amount of things, such as multiple feature pages or a blog, so I'd rather not rewrite everything later on.
You could also use Web Components but they don't have as much support and are generally not as good as React (one can disagree of course), so I like to use React + Gatsby to build the pages at compile time and use them without any Javascript whatsoever [0] but still have the developer experience of creating a page via components.
[0] https://www.gatsbyjs.org/packages/gatsby-plugin-no-javascrip...
If you don't mind, as someone who is not familiar with react can you elaborate on the difference? What do you mean by life cycle of a site? In the template I use, I can organize all parts of a site as functions and compose/reuse them freely.
Do you think duplicate code bad, no matter the case? I'd like to hear your thoughts.
Personally, I don't mind a bit of duplication and difficult coding if I can avoid a juggernaut like React, but I also don't mind simpler visual UIs. I actually prefer them over the complicated SPA that tries to look and feel like a native application, because it never works. There's this "uncanny valley" between native application UIs and SPA web apps which try.
You get a way to organize your server side code, CSS, JavaScript and flavour of Web API of the month (SOAP, REST, gRPC, WebSocket, ...).
Naturally reusing components across frameworks isn't that easy, but the same problem also happens across React, Angular and what have you, unless you make use of WebComponents, but that only works if targeting the most recent browsers.
As a side not React also bucked what was the sage wisdom of the time which was, don't mix templates with code via the introduction of JSX. This came from the very real and sage pattern of separation of concerns but somewhere along the way we confused separations of technologies with separations of concerns. If a piece of CSS, a piece of HTML and a piece of JS are all dealing with the same black box concern and are not reusable outside of that black box, separation of technologies (i.e separate files for each) only serves to add complexity to the solution as it abstracts them away from each other, forces the need to resolve their interdependence and obfuscates the ability to quickly get an entire overview of the black box.
Well, for me my framework is vanilaJS, anything else only when there is customer demand.
Then they get surprised how fast everything runs.
I've heard doing document.getElement... and then modifying the DOM is costly.
Then only use JavaScript where it makes sense.
For example, using Angular, React, Vue to display text or encapsulate three.js is probably not the best use case of customers CPU and bandwidth.
Pretty much if you make changes to a DOM element and then read a computed value from it before a new frame renders (like dimensions etc), the browser has to recalculate the page layout before it can return an answer.
Fast: Read -> Modify -> Paint
Slow: Modify -> Read (reflow!) -> Paint
This generally isn’t an issue but if you’re seeing hiccups it’s either GC run wild, synchronous code chewing up the frame budget or frequent reflows.
So, manipulating the DOM uses more memory than, say, manipulating strings.
But assuming you're going to change something on the DOM anyway, the framework has the exact same API's to manipulate the DOM that you do. And they have their own overhead to figure out what operations they want to run.
Almost by definition, vanilla will always be faster.
That doesn't mean it's always better. If you need the DOM to reflect changing states in complex ways (think Trello or Notion) I'll be the first to admit it's simpler to let someone else's algorithm morph the DOM. And that's okay.
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.
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.
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 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.
https://developer.mozilla.org/en-US/docs/Web/API/NodeList/en...
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.
Do you mean this literally?
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]-->
Easier said than done when best practices shift every 6 months.
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).
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).
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.
I've basically have an implementation of Observer Pattern, PubSub and I have written something similar to hyperscript.
https://github.com/hyperhype/hyperscript
https://webdevstudios.com/2019/02/19/observable-pattern-in-j...
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.
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).
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?
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.
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.
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.
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.
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.
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 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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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-...
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.
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.
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).
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.
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)
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
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.
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.
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.
WebComponents do not have DOM diff APIs whatsoever.
Diffing will always be expensive memory wise.
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.
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.
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.
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.
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).
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.
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...
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.
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.
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.
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.
The problem usually isn't react, but that most projects using it directly use it wrong.
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.
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.
I have vanilla-js code from 1998 that still works unchanged in 2020.
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.
Please use well documented frameworks, otherwise we're trading away the entire teams productivity in favour of the rockstar to have his say.
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.
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?
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.
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.
const doThing = event => {
input.value = event.value;
input.focus();
sound.play();
}
button.onclick = doThing const doThing = event => {
const input = event.target
input.value = value
input.focus()
sound.play()
}
...
<button onClick={doThing} />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)
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.
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.
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.
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.
<input id=input />
<button
onclick='
input.value = "value";
input.focus();
sound.play();
'
>
Button
</button>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
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.
To ask the same question differently, what about functions that do not need 'this'?
It's easier to use arrow functions for everything except for the tiny minority of cases where you want prototype this.
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 happen1. 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
With three, I disagree. It is kind of like saying let us just use var everywhere to be consistent.
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.
That doesn’t sound true. Do you have any evidence? (Under an uncommon JavaScript engine?)
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."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/#/
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?
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.
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 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...
>> 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 functionsI think frameworks are great, but you have to develop a self restraint from using every bell and whistle that's in it.
You don't need frameworks for any of that.
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 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.
Also, what are important and incidental nodes?
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"]
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.
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.
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 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.
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...
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...
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.
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-headersSo yes, I do find this more readable. It makes it clear that only one branch will get executed.
function test() {
switch (true) {
case console.log('asdf') === undefined: return 1;
case console.log('qwer') === undefined: return 2;
}
}
test(); 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; return (cellA === cellB) ? 0 : (cellA > cellB ? 1 : -1); return (cellA > cellB) * 1 + (cellA < cellB) * -1;
More: return Math.sign(cellA - cellB); return (cellA > cellB) - (cellA < cellB); '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).Or indeed drop the <, > based approach and use: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Or: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
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 badI find a better indendation style for this is more like
condition
? truthy
: falsyyeah, 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.
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.
if (cellA > cellB) return 1;
if (cellA < cellB) return -1;
if (cellA === cellB) return 0;
throw new Error();The correct is return a<b?-1: (a>b? 1 :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.
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.
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).
function $(query) {
const result = document.querySelectorAll(query)
if ( result ) {
if ( result.length > 1 ) {
return result
} else {
return result[0]
}
}
}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.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.
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.
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.
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 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 newer UI frameworks are round-about and confusing. They make it easy to get 80% of what you want, but that last 20% is bear, requiring long trial-and-error periods, unless you are heavily versed in them. Abstraction is only nice when it does what you want, not when it becomes "abstract art".
The price for "responsive" (client-side auto-placement) has been huge. In applications that are primarily for office desktops, their advantage is lost. Mouse and PC's is still where most real work is done. Instead we are using things like Bootstrap, designed for social networks, not real work. Glamour won over logic.
It's great job security for UI experts, but expensive for organizations because they need stack specialists whereby before a one-man-band (or 2) could make useful apps for less than half the cost and time without having to spend years with UI-Yoda to master some screwy layout engine.
Something is wrong.
The web’s layout engine is just a PITA. I also feel much more in control inside a canvas. I can do anything I want inside it.
However, DOM manipulation is not a solution to layout issues, so I am not sure the OP’s gripe is that relevant to this tutorial.
Now I have a big high-res monitor but can't read bad written applications like Steam because they don't honor my DPI settings.
No, we need flexible layouts. We always did.
The browser today lets you opt out automatic layout and instead specify fixed x/y/width/height coords with `position: fixed`.
It seems to me that your problem isn't the technology itself but perhaps the culture around it?
The built in tooling got more flexible in .Net (eg. You could effectively "bind edges"), but I actually found setting all that up more time consuming in practice that just arranging everything myself in straightforward code (which also gave me more control over exceptions and edge cases).
To do this correctly you need to do two passes for layout and at that point you've basically implemented a rudimentary layout engine.
I think we overestimate the complexity of apps we built back then and don't have an appreciation of how complex our apps are today.
Not to mention the amount of finicky bugs you will encounter.
Making the same in a declarative way requires tons of options and it is a mess. See CSS flex, CSS grid, CSS @media queries, CSS box-model...
If frontend was bicycle science then I must have missed that in my 10+yrs writing frontends with JS+CSS...
> They make it easy to get 80% of what you want, but that last 20% is bear
JQuery was the standard before JS frameworks took off and it was a nightmare for anything besides smallish websites. It was good for 25-50% of what you wanted at most - everything else was completely different every project you looked at. Trying to manage a large application that any serious modern web-based SaaS company uses was incredibly difficult.
I started using Backbone.js before Ember/Angular was even a thing yet and it was the first serious attempt at building large JS-driven apps for browser and mobile. That was simpler because it mimicked Railsy REST/MVC set ups, plenty of analogies for backend people to learn from, but that turned out to be a poor way to create UIs and React/Vue/etc + Redux offered a thinner view layer with a very clean way to manage state and bind data to the UI.
JS frameworks stopped pretending they were traditional web server app/database in the browser. But rather one that reflected the reactive interactions which we are trying to model in real-life spread across various individual components... more like desktop interfaces, not recreating web apps backends in the frontend.
Vanilla javascript has improved quite a bit to lessen the need for JQuery, but even then managing state and mutations reliably, modelling data, coordinating async operations, only loading the JS you need on a particular page, code organization/modules, etc have all been made way easier with the new Webpack-driven frameworks.
But you can still use simple vanilla/JQuery if you only have a small project. There's still plenty of Jquery libraries being developed and simpler UI libraries like Bootstrap...
Unless you mean pure-HTML forms, which are extremely limited in terms of interactivity. But again they haven't gone away either if it fits your needs.
One of the biggest motivations of these JS frameworks early on was due to the adoption of smartphones becoming the primary computer interactions. The other was the SaaS model, creating far greater demands on what needs to be done in a web form.
I've developed VB and cross-platform stuff like Qt and wxWidgets, and that stuff is no easier than the stuff I'm building with JS every day. HTML templates + automatic reactive bindings via Vue and a Redux/Vuex 'backend' are very simple.
What's more complicated and still shitty with JS frontends is the wider frameworks with Webpack, that come with a hundred packages that break often. That is the most painful thing I have to deal with day-to-day. The learning curve once you add in Babel, PostCSS, the various code optimizers and linters, TypeScript, etc can be quite intimidating.
But that has more to do with the tooling than the general approach being taken in modern frontend development.
And they keep failing because they throw layers at the problem: chicken-wire is used to fix problems caused by the duct-tape on the prior layer, etc.
It's becoming pretty obvious that Yet-More-Layers only exacerbates the problem. It may get "solved" by having fewer browser choices, but then the evil of oligopolies will kick in and we'll be back to the IE-esque problems, one of the most hated browsers.
Re: I've developed VB and cross-platform stuff like Qt and wxWidgets, and that stuff is no easier than the stuff I'm building with JS every day. HTML templates + automatic reactive bindings via Vue and a Redux/Vuex 'backend' are very simple.
My experience is different, and I observe similar bottlenecks at various orgs. Those JS-centric frameworks are harder to trouble-shoot when things go wrong, and different browser brands/versions render them different and/or wrong. With the VB/Delphi-esque tools, things show up exactly on the screen where I tell them to go: there is no if, ands, and buts. They follow my exact commands like dutiful robots. The technology is MY slave instead of the other way around: Thou Shalt Go At X=37 and Y=200. My Will Be Done! (Cue thunder clap.) React/Vue et. al. often go, "Sorry Dave, I cannot do that, but I'll do it my way anyhow." (I recommend GUI's use vectors instead of pixels these days, by the way. They are potentially equivalent when needed.)
Further, the quirks in pre-web GUI tools were getting ironed out over time: they got better with age. The web seems to get messier with age because of the layer-to-fix-layer problem above.
Is this just a matter of there being less ways to interact with the apps back then? Everyone had the same platform, same hardware, same screen resolution... etc. Plus, accessibility was an afterthought. Now, users have bigger and more varied expectations.
What you've said directly proves OPs point - you've missed the central message: UIs used to be bicycle science before everyone started using JS to make them.
They mentioned VB as in visual basic. GUIs with VB/Delphi are a case of dragging controls to where you want, pixel perfect every time on every desktop.
Web technologies are not designed for desktops but for building on top of HTML, so everything is an abstraction to get back to something that used to be possible with zero experience and sometimes even zero programming. For example, a simple notepad clone can be made in Delphi without a single line of code.
Now you need to 'full stack' to even know what's going on under all the layers just to place a control at an x,y and even then it can't be guaranteed because of all the different browsers, css edge cases, and other caveats.
Sure then I agree, making simple toy apps with VBasic and similar tools was easier. It was also easier to make websites in Dreamweaver back in the day than really learning HTML+CSS.
That doesn't really solve any serious problems, nor the reasons why we've adopted such extensive frameworks.
What I disagree with is that it's getting harder or messier or worse to build frontends. I've seen significant improvements in the last few years and I've told many people that I'm actually liking making JS-driven apps for the first time in my career (Typescript has played a big role in this as well, not just React/Vue). I'm no longer scared of deploying large-scale browser apps since it became clean component/redux driven stuff instead of a tangle of JQuery + other crap shoot combinations.
I'm sure the pace of change to outsiders can make it seem like a long series of failures and flailing about, but to those who have been following it there has been a relatively consistent evolution of ideas. One that more recently has gotten us the closest to desktop quality software than ever before - even though 'desktop widgets' was a dirty word in the frontend world for a long time - IMO largely because early attempts were too bold and complicated for the capability of the browsers at the time.
Yes it does. It meant that less-experienced developers could make nice programs that near-zero-experience users could immediately take advantage of, with the same look and feel as every other program they already used.
It went far past "simple toy apps"; maybe not suitable for making a distributed network app, but for making something useful for an accountant or an administrative professional, it was perfect.
> I'm sure the pace of change to outsiders can make it seem like a long series of failures and flailing about, but to those who have been following it there has been a relatively consistent evolution of ideas.
I've been following this since the 90s and it went from "a nice way to publish documents to everyone" to "a bastard environment with a shitty language that is inconsistently implemented" to "overburdened with frameworks to paper over the fact that this system was never designed for this at all".
Great, 20 years later we have some huge massive framework that takes ages to learn even for someone who used to know JS competently, just to draw some basic widgets and data tables that we used to be able to drag-and-drop into place in the 90s.
> What I disagree with is that it's getting harder or messier or worse to build frontends.
Maybe it's slowly improving in the browser now, but until we have things on the level of Flash as far as interactive design for non-developers goes, it's still massive steps backwards for no real gain besides the self-gratification of JS devs.
Let me clarify. I am or used to be what's now called a "full stack developer". I am not really an intense "coding wizard", but can do ALL parts of the development cycle reasonably well, including talking to the customer to understand what they need and why they need it. Those good with code details tend not to be so good at the analyst and communication side of things. There are exceptions, but I'd say this is about 85% true. These tools made full-stack-developers possible and relatively cheap.
This also means each department (group within an org) can have its own programmer/analyst who can focus on and learn the domain, now it has to be more centralized in order to have specialists.
Tools like VB-classic, Delphi, PowerBuilder etc. meant I didn't have to micromanage a lot of UI details that either take a lot of time or require hiring UI coding specialists now. I could do both the analyst/people side and the technical side at a good clip.
Current web stacks mostly killed all that, requiring either layer specialists or spending a lot of trial-and-error time fiddling with browser UI's trying to get the friggen UI to match the sketch. Before if the customer asked, "can you move that button to the right just half an inch", it was 5 minute job. Now such can take 2 days if it goes against the grain of the UI framework. It's ridiculous. Sure, an expert at the UI framework may instantly know the magic CSS trick, but it's only obvious to a UI framework expert, NOT to generalists like me.
It now often requires rocket science or a manual genetic algorithm (mass trial & error) to move that damned button half an inch on the customer's screen.
I used this tool at the State of [redacted] Dept of Taxation to develop the whole system. The database was Oracle (I think) and we would write the backend code as such:
1. Copy the 2019 code function "VERIFY_TAX_RULE_147B_2019()" to "VERIFY_TAX_RULE_147B_2020()"
2. Follow this list of rule changes for this rule to change the function
3. If there are any 2019 functions in this function, make a ticket to copy+paste those in a similar fashion for some other developer
4. Close ticket
5. Get another ticket
The front end for the forward-facing revenue agents would also get updated in a similar fashion, one Power Builder form for each year and window they needed, so if you opened 2020 taxes you would get "WIN_FORM_PAGE_A317_2020" and if you opened 2019 or 2018... you get the idea.
It was a horror from the usual "software engineering practices" standpoint on stuff like code re-use, but it was super easy to do and based on the risk analysis it was the best/easiest/cheapest solution to be able to test, review, and ensure the accuracy of EVERY tax rule we implemented with iron-clad certainty.
Someone in QA would just go to each function, make sure it calculated things correctly based on the requirements, and do a few other checks. We had a big QA department that would do test driven development on each pull request (if it failed, you went back to fix it again, so since we used Visual Source Safe we ENSURED it worked the first time; you know what I mean if you used VSS) and sit down with the developer for each function and go through it in a heavy review. I can't imagine trying something like that in React or whatever, you could never ensure the software would always behave the same way each time with the network latency and huge underlying security concerns for the framework and a bunch of other issues we would have had to overcome to prove it worked correctly every time. Backend frameworks would be even WORSE for our risk profile.
Most importantly: no one cared what the damn UI looked like as long as all the buttons and text boxes were there in the designated configuration. They were all Windows 95-style UI boxes and I doubt that the front desk agents would have been happier to use some Reactified "pretty" stuff.
The story is just to say that I agree with you wholeheartedly that the UI/UX space has exploded with useless garbage you don't need in a simple, boring business tool and 95% of software is just that, simple and boring.
As far as most business software being "simple and boring", I wouldn't necessarily call it "simple", for the domain rules can get intricate. But it doesn't need buzzwords like blockchain web-scale AI or what not.
Desktop GUI's reached a pinnical around the late 90's and web UI's still cannot compete on simplicity and functionality. DOM-based emulators tend to break on browser version updates. We need a dynamic GUI-over-HTTP standard to allow us real GUI's on a browser or browser-like interface. Something like YAML, but more interactive. #MakeGuisGreatAgain!
However this improvement is in spite of using a tool designed for a different medium, rather than because of it, and the years and abstractions its taken to get here express this.
Having said that, cross platform is better going from web to desktop than the other way round.
I suspect we'll need a new web standard that's GUI-friendly. For one, have the option of sending raw coordinates to the browser and have the (optional) layout/flow engine be on the server. That way you only have ONE layout engine instead of a different one for each browser version/brand, which is what we are really dealing with.
A. app -> server layout engine -> coordinates -> client -> screen
B. app -> markup/JS -> client -> DOM -> coordinates -> Screen
The problem with "B" is that each DOM is slightly different: different browser brands and versions. You have to test with about 50 variations to be sufficiently thorough. And as time goes on, they break more code. A more accurate diagram would fan out after "client" and have DOM1, DOM2, DOM3, DOM4, etc. Since the browser is dealing with raw coordinates in A, there fewer things to go wrong. Thin client = thin errors.Another advantage of A is that you can choose different layout engines not bound to DOM standards and quirks. Or even have none and go WYSIWYG. (Web browsers don't really do WYSIWYG well in practice, partly because font-to-widget-size-ratios are not standardized.)
"A" is more stable. It's better factoring, period.
jQuery was never a standard any more than it is now. It was popular even driving a bizarre fundamentalist cult of personality worship, but that by no means makes it a standard. In technology a standard requires wholesale adoption opposed to mere frequent consumption, even if not enshrined by a document (de jure). For example there was never a time that jQuery was required in any commercial capacity either to seek employment, perform work, or deliver a finished product. Claiming that I hated jQuery during its prime didn't stop me from closing a job interview, but it did turn a few heads.
* https://en.wikipedia.org/wiki/Technical_standard
Because I'm in healthcare, the web sites have gone crazy in the last four months, and there are updates upon additions upon updates of the additional content over and over and over. Think 14-hour days.
The sites that have been migrated out of the framework jungle can be updated in minutes to hours. The sites that are still stuck in framework hell can take hours to days.
When things happen (for example, when another state locks down), the framework sites get slow. The non-framework sites keep zipping along, which was my main reason for moving them in the first place.
The next time you're looking at a government or healthcare web site that doesn't have the latest COVID-19 information on it, look at the source code and try to figure out what it's been generated with.
I don't know what the requirements of these sites are, but throwing out all the things you get with a framework such as a battle-hardened authentication system for "plain old PHP" hardly seems like a pragmatic decision. Was a full rewrite in a base language only really an easier/superior decision then finding more simply caching solutions (which many frameworks support out of the box)?
Rolling your own auth system is very likely not going to produce an auth system as battle hardened/tested as <popular framework>.
Rewriting an entire site from scratch is rarely the correct choice and is one of the most common engineering fallacy. https://en.wikipedia.org/wiki/Second-system_effect
Caching is a problem you need to solve regardless of whether you're using a framework or not.
These problems don't magically go away when you decide to rewrite these components yourself. You probably aren't going to write code as well as a community of coders that have contributed to a years-old codebase. Especially not on your first pass.
These are all pretty legitimate "what-if" questions to ask.
Still though, auth is just one arbitrary requirement I plucked from many that popular frameworks solve such as request handling, response rendering, database operations, routing, etc.
Yes, you can use a hodgepodge of libraries to solve these requirements but your argument that your codebase will be leaner than a "heavy framework" using codebase gets a bit flimsier in my experience.
Look, I'm not saying you shouldn't use a framework, every project has different needs. I'm saying that frameworks have made people lazy and they try to fit their project into the framework they know when when it's wrong.
What do you think the components in a framework are? They're just libraries, and often can be/are used standalone. I've seen no evidence that there are less bugs in a library not used for frameworks than one used for it.
> If I use the big framework, I'm stuck with it if I ever have to change my data storage method and it's outside of the frameworks normal scope.
There's no reason you can't use a different library within the framework. It's the exact same as writing from scratch, you're just doing it within the patterns of the framework instead of the patterns you've created on your own.
> Look, I'm not saying you shouldn't use a framework, every project has different needs. I'm saying that frameworks have made people lazy and they try to fit their project into the framework they know when when it's wrong.
I'm not advocating for blanket usage of frameworks either but I've yet to see a compelling reason to in this discussion thread not to.
With a framework you not only have to learn how build things in the framework (which takes a lot of time to become truly proficient) I also have to build what I am already supposed to be building.
I find personally that frameworks
* Simple things hard. Hard things simple.
* Anything outside of the happy flow they present to you in the docs is a major PITA.
* I frequently find myself scrabbling around for information when I need to override how the framework works in a particular scenario.
* They nullfy much of your pre-existing knowledge e.g. I am described at a lot of places as a JavaScript guy in the team, because I get JavaScript. When I use Angular or React, most that is irrelevant. It doesn't really help me.
If I am just using well established patterns + my existing knowledge of the programming language and environment. I can normally put something together myself that does just what I need it to do and I use a library for things like date time calculations or Ajax requests or something else that is mundane.
The only thing I'd counter to this with is when I see this approach taken, an informal "framework" of sorts tends to evolve naturally. First you write something that handles the routing, then soon you want to organize the code the route endpoints call, then you layer on the authentication at the top level request handling area, so on and so forth. Over time, as new requirements come in and new people work on the project, more and more patterns, conventions, and library are added to the codebase - pretty soon all that "glue" code meant for interfacing with libraries is reaching or exceeding the complexity of a framework based codebase (except your codebase probably has less documentation for things like conventions and patterns than a framework would).
That said, I don't think it's the wrong approach especially when the scope of the project is limited and/or there are ways to manage feature creep (e.g., frontend only, limited lifespan, internal facing apps, etc)
Yes. That's part of my job.
I don't know what the requirements of these sites are
Then anything else is just blather. I know more about my systems than you do.
Was a full rewrite in a base language only really an easier/superior decision then finding more simply caching solutions (which many frameworks support out of the box)?
Yes. For my purposes. Perhaps not for the sites you work with.
My company has a very, very small number of UI experts who are tasked with making sure non-UI folks can build front-ends. It's been a rousing success. We own some documentation and a few tools to make starting projects easy. We teach an hour long workshop that covers everything (React, the npm ecosystem, TypeScript, best practices, etc) and then we let them have at it. It's been a rousing success and nobody has seriously suggested moving back to jQuery or any of the WISYWIG tools.
Sure there is a cost -- you need to hire at least one person with enough knowledge to cut through the bullshit and build the right tech stack. But once you've paid that cost once the payoff is massive.
This looks an excellent approach.
>> you need to hire at least one person with enough knowledge to cut through the bullshit and build the right tech stack.
How do you ensure that this person will "build the right tech stack"? There are myriad of possibilities to go astray.
You can get pretty good mileage following industry best practice -- pick React, pick TypeScript, and pick the most popular tools for each.
After doing it several times, they will start building their own framework. At that point they should consider using an existing framework. :)
But UIs are better than ever. How many Google Docs, Webflows, SquareSpaces, existed in VB-classic?
Let's give the space some credit. All this complexity wasn't for nothing.
https://stackoverflow.com/questions/60997602/event-handler-g...
I was reading through the code, and was astonished at how this doesn't look like code anymore but a mashup of different languages and patterns in one single block of code.
The only framework I'm willing to tolerate at this point is Vue.js, which, with the help of http-vue-loader, is capable of nicely using components in a compiler-free workflow.
React may be excellent for teams, where there's a clear distinction between font- and backend development, but sometimes you just need to hack together a server with a minimalistic frontend which should just be editable via sftp, when you're building tools for internal use only. Vue.js is great for that, but I'm worrying that it will turn into the same thing Angular has turned into.
You can't honestly compare VB UI's to modern day web UI with a straight face. Following your analogy, making decent UIs is closer to rocket science because web apps are closer to rockets than bicycles these days.
I would love to see a drag-n-drop approach to web UI building that is responsive and fast. But I highly suspect the reason this doesn't exist isn't "great job security".
There's really nothing complex or difficult enough in React, Vue, or any other UI framework that can't be picked up by a competent dev quickly.
>Something is wrong
Yeah, the hivemind that loves to hate anything JS/front-end related and things "purity" is the only bar by which to measure things.
The problem with many layers of abstraction is that it borders the imposible if the layer abstacted to poorly suports something.
Take physical screen size and simple scaling to fit? Is it a tiny 1024px laptop or a giant tv? there is no solution I can think of
I also don’t get the JS hate here. :) you certainly should not use react for your static resume site or blog. But react is a brilliant and necessary tool for web applications. If you don’t use it, you’ll end up making your own, probably worse abstraction for managing state and reactive updates.
Honestly. Where I work we have a few undergrad co-op students who have just finished their first year of school. No previous React experience. They jumped right in and were useful on our React projects after about week. They just read some docs, asked a couple questions and played with our existing code. They're smart people but they're not x10 programmers.
We have other large projects that are a more "traditional" mix of DOM manipulation use jQuery, global CSS, etc. and introducing new hires to that is never as smooth. There are no docs as thorough as React's that explain the patterns established in those codebases (if there are any consistent patterns at all).
One thing to note, we make what I would consider to be web applications (for data management & analysis), not web pages.
Even worse. We're stuck with html/js also for "desktop" apps, via the electon and similar. Basically, UI development is dead (Windows WPF is in maintenance mode) and if you want, as example, build some graphs you need to manipulate js in a webpage. A
Users want to run your software on their system. You don't want to write software for their system, you want to write it for all systems. The output impedance of the developer and input impedance of the users is a function of how easy it is to write the app for all users and use it by any individual user. Optimal power delivery is achieved when I/O impedances are matches low. Efficiency is achieved at lower impedances.
JS/HTML/CSS is currently the optimal solution in that context.
UI isn't dead, it's more alive than ever. But since what works is what can get my product to the most people the fastest is on a web stack, that's the thing that's going to be used. And since the web stack is high impedance to begin with, anything I can do to lower that in terms of framework is going to be in demand, hence all the diversity we see.
Unfortunately the real world and the perfect world the CSS designers envisioned were two totally different things and as a result people have been fighting with CSS layout for years.
On the other hand I know what you mean because I cut my teeth on coding VB6 and Delphi (Borland anyone?) applications in middle school (where are my Yahoo!, ICQ, AIM app masters at?). It was fun, and easier than todays craziness. And people wrote more client software instead of making everything a web service. We also had zone alarm and people got hacked left and right and windows BSOD and all the fun of the 90's and repeated unknown socket errors on winsocks. I also felt like the programming world had more curiosity and self-sufficient people, as opposed to being so heavily money, convert, social, latest tech driven. It feels like everything now is a rinse, repeat, sell to FAANG cycle.
Whether you like inaccessible websites when you disable JavaScript is one thing, but don't dismiss useful tools that don't suit to your tastes. If you don't need to build a web app nobody's forcing you to.
As for frameworks: the market has indeed spoken, but not in the way you think. Consumers of websites rarely pay for the majority of websites they use. Employers, however, pay developers and the buzzword-chasing in resume building/interviewing cycles is real.
Whenever I read the word 'modern' in this context now, I know the writer means javascript, and in particular one of the 'modern' javascript frameworks. I'm not sure quite how or when it acquired that meaning, but it seems to be used that way on HN frequently. I wonder how this word came to mean built with Javascript to some people? Do you genuinely see modern as synonymous with built in React, Vue, etc. or would you allow other approaches into the modern canon?
The similarities with the burn the old world then rebuild it anew attitude of early 20c Modernism are striking, so I suppose it fits, but it should not be used in the place of built with javascript, as the implication is nothing else is truly Modern.
Also what does high fidelity mean in the context of websites? Is this like high fidelity vinyl records with a warm sound? Do your frameworks have gold cables?
I think you'll find people here casting doubt on the requirement for web frameworks because there are many other ways of building websites (server side for example, the way this website you're using right now is built), there is no one 'modern' way. People build contemporary websites with a variety of tools, Javascript is not objectively better than other solutions IMO (in many ways it is obviously worse), and client side is not obviously better than server side, it's a pattern which has seen its popularity wax and wane and will do so again.
It is easier to make UIs with Winforms, Qt, WPF, heck even with Actionscript it was more managable than with DOM.
The problem is that there is no unifying standard, no single vision. There are competing frameworks but they leak abstractions all over.
For example I am making UIs with ipywidgets which is basically JS on the front end and it at least a couple of abstractions too deep to fully understand it.
To emphasize how stupid making UIs using web is, let's take something simple like dropdown.
There is no such thing in the web standards, we use ul, ol etc and then we fake it/add another abstraction with a library or framework
In an ideal world dropdown would be a web component that could be imported, then be styled and events would be bound.
Except when you do want that behavior. E.g., you only want to set one listener and have a stream of data coming in that can trigger various attachments/detachments to the same element(s) over and over.
With the ancient "on" methods you get a single method that you can replace at will. Unbinding happens automatically. For example, you can keep assigning to an anonymous function till your heart's content and there will only ever be one callback in that slot attached as the author states.
With the new, "recommended" methods you must manually track the state and unbind old callbacks. For example, you would have leaky behavior if you kept assigning anonymous functions with addEventListener. And you can't easily hack your way out of the state problem because the DOM doesn't give you a way to fetch the current number of listeners, reset them to default or really know anything about them.
So the recommended behavior does not include in its design the ability to achieve the useful old behavior.
But at least DOM does have a convenience method to toggle class that will save a good 10 seconds per year of dev time.
I was wondering something similar while looking at https://htmldom.dev/toggle-password-visibility
This could be done inline with <input type="password" id="password" /> <button onclick="password.type = password.type == 'text' ? 'password' : 'text'">Toggle</button>
...instead of 10 lines of code. Is it ever ok to use the fact that window.elementID works? even for exposition? (it works in all browsers, not sure if its standardized...) Why use setAttribute? Again, setting via element.type = ... works in all browsers.
The idea behind addEventListener is that multiple handlers can be attached to the same event of the same node, whereas before handlers were property assignments that would clobber each other.
The disadvantage of addEventListener is that event handlers are associated with event listeners instead of with DOM nodes, which makes them more challenging to garbage collect and thus increases the memory space of your application. The way to keep the code clean is to use removeEventListener when the handler is no longer needed. Event handlers are rarely removed from the code though, because of a lack of discipline and because many times its hard to tell when they are no longer needed.
The biggest advantage of assignment by property approach is that it imposes simplicity. Simplify means to make fewer and complicate means to make many. When there is only one handler it is inherently the most simple approach, which greatly increases code cleanliness and forces a greater concern of code organization.
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.
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.
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.
We were using Adobe's Test and Target (Omniture) application for launching and measuring our tests. It works via code injection.
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.
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.
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 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.
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. python -m SimpleHTTPServer
or python3 : python -m http.serverHowever 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/
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.
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.
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)
Just like using webpack has nothing to do with how you interact with the DOM.
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 :)
I thought vanilla means not using front end view framework/library such as Vue, React, jQuery...
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!
i'd say your js qualifies as "vanilla"
in the first paragraph, can't edit anymore"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.
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.
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
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.
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.
https://chrome.google.com/webstore/detail/web-server-for-chr...
And it works
This swap function is just `a.replaceWith(c, d, e, …)` in DOM4
https://htmldom.dev/swap-two-nodes
If you haven't seen this before, I highly suggest looking into it.
https://github.com/WebReflection/dom4 (I can't find any articles about DOM 4, so this polyfill’s readme will have to do)
https://htmldom.dev/copy-text-to-the-clipboard
I get "trying to stay vanilla", but any reasonably-common snippet should either be installed from npm or published there.
For this specific issue there's a module named almost exactly the same and it restores the previous selection and focus as well: https://github.com/sindresorhus/copy-text-to-clipboard/blob/...
This is the point of published modules: your code isn't stuck into the version someone wrote in 10 minutes 5 years ago.
Or, you just want to write code in notepad.exe. There is benefit to simplicity in many cases.
And that's how you end up with the joke that was left-pad and the broken internet that resulted when the author yanked it.
Dependencies represent a real risk to your product. If it is actually a simple snippet, you shouldn't take that as an NPM dependency - the risk/reward ratio is just way out of whack with that.
Except it literally happened again 2 years after the left-pad incident:
https://status.npmjs.org/incidents/41zfb8qpvrdj https://github.com/facebook/create-react-app/issues/3701 https://github.com/angular/angular-cli/issues/9113
But anyway whether or not the module is un-published doesn't really matter. The module could also just become malicious. Ownership changes, quality of code changes, etc... If you're pinning with lockfiles you're basically back to copy/pasting or checking in a clone of an upstream repo - the maintenance burden shifts back to you at that point. You still then have to manually go update, and remember to do that, or you become just as easily obsolete as the copy/pasted snippet.
Instead of adding a file to your “libs” folder you add a line to package.json
Any code that isn’t in my repo is code I don’t have to maintain.
Left pad can’t happen anymore (for 4 years now) and if you don’t know that you’re either lying or outdated (like those files in your libs folder)
The overhead of setting up NPM, some repo when I can achieve the same thing with that snippet, seems just to over the top.
What overhead? You don’t run any optimization step on your code? I haven’t seen a single front end project without package.json in years in all the companies I consulted for, and I don’t even deal with fancy frameworks.
The web projects that I work on are rendered at the server and then that is displayed to the client.
* 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.Tangentially, my most recent frustration: I wanted to try a couple frameworks together (they had no overlap in functionality - not like trying to use React and Vue together), and they both came with CLI tools to initialize an empty project and complained when it wasn't empty. They both had different opinions about how to structure project directories, and neither explained in an obvious place how else one might get started.
I think most people learn these frameworks by being put to work on a mature code base with established patterns, that already uses a set of frameworks. At first, you kind of don't understand the control flow, but you get better week over week from there. Over time, you are bootstraping your own opinions by asking questions and learning hands-on.
Eventually, you can start a project from scratch including the minimal dependencies yourself, as you learn what's actually useful, vs what's "the same interface, but dressed for business".
That being said, I'd recommend getting started with `create-react-app`, and following some of the tutorials. I'd then recommend jumping into hooks (https://reactjs.org/docs/hooks-intro.html) as soon as possible, unless you have to maintain an older codebase that uses classes, because in "modern" react code, you're almost never using classes any more, and that reality bomb is not typically dropped on you in most react tutorials.
If you start writing a site in vanilla JS you'll eventually end up writing your own UI library basically reinventing the wheel which is fine as a learning experience and personal projects but maybe not the best choice if you're working on a large scale project with many developers since UI libraries and frameworks provide a common set of patterns as convention to follow that makes it easier for everybody to be on the same page.
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.
site:htmldom.dev search terms here
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.
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.
I'm not dissing Frameworks. They are a tool that help you with certain kinds of problems. Any crafts(wo)man, should know their tools well.
There is a lot of potential for the imperative APIs for this though. I even made a proposal:
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.
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.
What is this supposed to mean?
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 am a huge fan of React for the maintainability of the resulting code, and this was my attempt to regain some of that without the dependency.
This one is mine:
https://github.com/donohoe/content/blob/master/posts/javascr...
(I follow basic ES6 syntax but easy to switch as needed)
Edit: To clarify, a drop in replacement is what I was looking for.
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. fetch(url, {
method: “POST”,
body: “a body”
})https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequ...
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.
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.
That seems really useful, and I had no idea it existed.
It's a pretty poor reference for most people. For example, you have no reason to be defaulting to XMLHttpRequest for http requests.
Ouch!
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.
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.
So basically the frontend JS is so the backend can produce HTML.
Rather weird way of looking at it.
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.
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.