The problem with vanilla JS is not APIs, API is the easy thing. The problem is building proper architecture, so code won't quickly turn into spaghetti. With frameworks like Angular or React, it's much easier, as the general structure is dictated by framework and developer just have to follow good practice. With vanilla JS it's the wild west.
In my experience in the corporate world it's just as much the wild west even with using popular frameworks. Frameworks aren't a substitute for discipline or organization.
I wonder if those chaotic corporate experiences would've been far worse if not for the frameworks. They're just so useful for significantly constraining the solution space that you can't get too far into the weeds even when lacking discipline/organization.
My experience is that velocity slows because devs get so lost in all the accidental complexity of these frameworks and their hidden lifecycles (that they only barely grasp from their 1 tutorials worth of experience) that their velocity of delivering real business value plummets. We are much less productive than a decade ago.
Did you ever work on a JQuery codebase? (JQuery was an almost 1:1 mapping to browser APIs, do it's more or less equivalent to vanillaJS). Codebases based on modern frameworks, especially React, are much less complex than codebases based on the old approach. Back then you'd get lost in the weeds of DOM manipulation, and it'd be hard to see the big picture at all.
In my experience most of the incidental complexity in modern apps comes from inexperienced devs doing things that simply didn't need to be done in the first place. Very little of it comes from the frameworks.
This completely matches my experience. I've worked on a 200k+ line javascript codebase that originally used just vanilla HTML DOM management and jQuery for everything, and I've helped introduce React into it over the years.
Every time the old code needed to place a view inside of another view, it was a fresh adventure in the exact way that sort of extremely common routine operation shouldn't be. Understanding a module always meant understanding its approach to managing its DOM elements before you even got to its business logic. Modules often chose between having simple-but-janky code that re-created DOM elements from scratch every time anything in the view changed, or having more-efficient-but-complex-and-buggy code that intelligently updated only the changed elements but often had inconsistencies with the first-render code causing some values to not work if they got set while the view was already mounted. People tried to establish some conventions across a few modules, but the chosen conventions often had significant drawbacks or only worked in specific cases because the people making the conventions didn't have the experience of library/framework authors.
I remember working with a coworker sketching out an idea of a convention we could develop and use for updating text and substituting in translations and live values. One of my main goals was to allow our modules to have the same code for the first-render and subsequent renders without having to replace all the module's elements with new ones. It was originally intended for just updating text, but I started to realize it would have to handle arbitrary HTML and embedding views from other modules to really be useful. The idea felt like it would need special cases to handle that, and I couldn't get the idea further. Then I later found React, and I realized it was a generalized approach to accomplish exactly what we were trying to design. I got the green light to use it in a few new modules, and even coworkers who weren't yet familiar with React could see how the modules were much more focused on the actual business logic rather than being absolutely filled with so much unique DOM-manipulation code. Everyone was sold on it within a few months, and people that needed to make changes to old modules would often choose to move the code over to React first to make it simpler to work on.
I also feel modern web apps are just much more complex than those from the jQuery era. So codebases have to do a lot more. It's hard to find a 1:1 mapping, as we just didn't expect as much out of the web in those days.
Complete BS. Not true at all. the jquery era had ajax with dynamic dom updates, dynamic svg, css, and many things we have today except for websockets, web usb, mic, camera, and other devices. the difficulty was more around each browser implementing things differently. and css was a nightmare. just to center something horizontally or vertically (or both) took patience.
It’s not “Complete BS.” — just because we had those features does not mean most businesses used them to the same extent we do today. I was deep in the front-end weeds in 2007 and onwards, and while I may have been doing some neat stuff then, the complexity pales in comparison to the sheer amount of business logic that now lives client-side.
jQuery is constantly tested with all of its supported browsers via unit tests. However, a web page using jQuery may not work in the same set of browsers if its own code takes advantage of (or falls prey to) browser-specific behaviors.
That quote says that if you attempt to solve for a cross browser conflict using a standards based approach it will likely conflict with jQuery code in the page. Either your approach will fail due to changes imposed by jQuery or your approach will break something supplied by jQuery. That is bad mojo.
Another problem I have with jQuery is that it encourages extremely inefficient practices in exchange for convenience. For example consider jQuery's closest method, which looks great if you don't consider the steps that execute under the hood to make that happen. In contrast using a non-jQuery approach generally meant event handlers that more directly target specific nodes in the page without all the necessary DOM walking.
I also remember jQuery frequently breaking IE back in the day. IE uses instruction count to determine if there is too much code in the page, whereas other browsers use a 20 second clock to warn on long executing code. Since jQuery does a bunch of unnecessary things and encourages method chaining those instructions counts would quickly add up and IE would stop executing code.
I have also found for many developers that jQuery is/was more of a live or die crutch they cannot live without opposed to a time saving convenience which was very off putting because developers were unreliable when things broke or when things needed to execute faster.
It's 10x the code now. 10x = 10x more space for bugs and bad design.
Use to be I might setup a handler on an input element to update a value. Now I have to write an action factory to generate an action to get reduced into a function that updates the value. From simple data.prop = elem.value to 4+ functions and a bunch deep deep overhead.
Now I'm not saying all that structure doesn't have benefits but it's also a large amount of rope in which to hang yourself.
I honestly think it's about a quarter of the code. Yes, there's a bit of ceremony around state management (but you are also free not to use Redux). But it's mostly boilerplate with a prescribed structure, so IMO it's pretty difficult to get it wrong.
On the other hand, most of the code has always been DOM manipulation, and having that declarative rather than imperative is a huge win. The alternative used to be using a template engine like handlebars, but that did a complete re-render every time any state changed, so for anything moderately complex that was too slow and you had to fallback to manual DOM manipulation, and manually keeping the DOM in sync with your state. And that was a large amount of rope in which to hang yourself
Yet we all managed to write complex web applications without much trouble that performed better than React ever can. DOM manipulation was needed rarely actually - usually you replace subtrees anyways (switch tabs, etc).
If DOM manipulation is rarely needed then your web app isn't complex, it's at most a collection of CRUD pages. UI Frameworks like React are for building UI's that accomplish a lot more than that through frequent DOM manipulation. If all you need is CRUD then templating frameworks still exist, are well maintained, and widely in use.
That's not true as soon as your UI contains conditional logic or a list of elements, at least one of which will be present in almost every web application.
> ... and having that declarative rather than imperative is a huge win. The alternative used to be using a template engine like handlebars
While React markets itself as a declarative DOM manipulation library, any kind of HTML templating system is declarative out of necessity. Why? Because they all produce HTML in the end, which is itself a declarative markup language.
In my experience, a framework atleast provides some ropes to hold onto while traversing the mess. Currently I'm stuck with a codebase with almost no documentation of a mess of legacy and new code with layers and layers of developers' opinions on top. The only way I'm able to figure anything is out is by tracing remnants of a light framework that's in place. I'm able to read the framework documentation and slowly unravel it, without it it'd be an even more monumental task!
I googled/linkedin developers that have worked on this codebase for the past decade and most of them appear to have this "rockstar developer" thing going on. They are opinionated, had heated debates (from what I'm told), and often rolled their own solutions whenever possible. Now we see the result of these geniuses doing their thing.
Just use a framework please, your homegrown solution is sucks. I guarantee it.
> Currently I'm stuck with a codebase with almost no documentation of a mess of legacy and new code with layers and layers of developers' opinions on top.
If it was originally built using a framework, what framework do you think that would be? And would it still be in active development and evolving today? How do you integrate new code in a legacy or evolving framework? My experience of this says it is not really a framework vs no-framework problem, but a problem of how to keep an applications code base healthy in a world of ever changing and evolving features, developers, frameworks and technologies. I think thats the real problem you are dealing with here, and not "hot-shot developer from 10 years back didn't use the coolest stack of that time".
And it is the problem you were hired to solve. If everything was working perfectly with no new features required to be added to the legacy code base, they simply wouldn't need you.
Yeah. But they got selected by the ecosystem because they were GREAT homegrown solutions. While Angular was an accidental success, it seems that Facebook really grasped early on what was happening with React, (we all benefited from the Angular experience, warts and all) and really put in the resources necessary to make React successful, for the benefit of all.
The only way I benefited from Angular was when all the companies who let the front-end dev come lately's talk them into using it; realized they had been sold a bill off goods and needed someone to get them out of their Angular mess. I made a good living off of getting people out of Angular 1's mess. The reality is Angular 1 was poor, it was so poor that the developers decided that they has missed the mark so much that they needed a complete rewrite to make a good product. Why people stuck with them after that is beyond me. I can still vividly remember taking over my first angular project and realizing that the devs that built it where so green that they had misused common concepts and terminology like what scope means and what state means and had conflated the two into a mess.
Angular was bad and it's ashamed that it's hype pretty much relegated better toolkits like Dojo and MooTools to the dustbin of history.
> they got selected by the ecosystem because they were GREAT homegrown solutions
While React has lots of great ideas, good marketing and the facebook brand is really what boosted its popularity. Popular does not necessarily mean great. There must be some other great homegrown frameworks out there, but we have never heard of them, since they did not start out as a facebook or google homegrown framework.
> it seems that Facebook really grasped early on what was happening with React,
This just is not accurate. React has also evolved a lot since its inception, they've just been careful about maintaining backwards compatibility compared to angular.
Ja 100% ! Ppl will argue with you and they will argue the exception not the average experience. Sure there are code messes with frameworks. I feel that ppl argue Jquery with multiple ppl and a good size project is better, just havent had enough pain. You can x my argument by 2 if its a project you join and didnt start.
> (that they only barely grasp from their 1 tutorials worth of experience)
If you're going to staff your entire corporate dev team with a bunch of green developers, yeah, things will be nasty. That's not the frameworks' fault though, that's just a straw man.
I don't think frameworks make any difference in this regard. The most important thing to remember is that developers are people. Most everyone benefits from direction and guidance without regard for their seniority. Some of that guidance can be automated by applying appropriate limits or certain safeguards to the process, but is generally not something that can be outsourced directly to a tool. I think of that as something akin to letting a television parent your child.
They do though, frameworks are just an amalgamations of patterns and practices codified. If you go Vanilla JS you are going to build abstractions on top of it to make your patterns and practices reusable and structured. Given enough time you are going to build a framework that enforces your patterns and practices. So why not just adopt proven ones out of the gate. But verify that they are indeed proven ones before just jumping on a bandwagon.
An example I would highlight is, Redux it's great and it has helped a lot of developers that don't know state patterns learn to deal with state, but it only taught them half of what they need to know. The other part of state is not allowing applications to fall into an inconstant state that it should not be in. Redux intentionally ducked this one because state management is a complex task and building a state machine makes the cognitive overhead much more complex but that is what developers following correct patterns should be doing, they should be using a state machine and it is the reason I use XState in my projects over using Redux as it is a full state management solution, that gives me a guarantee that my state is both preserved and consistent.
> Given enough time you are going to build a framework
I have heard this argument countless times over the last decade and its not based on anything. I suppose if you have never written code without a framework and for the first time attempt to write some new application it would make sense that your application ends up looking that thing you are familiar with. Beyond that this entire position is absolutely meritless.
What I find most frustrating about this sentiment is the lack of originality it codifies. Many JavaScript developers I speak with online are absolutely certain the language is limited to building static pages and SPAs. That's it. And, it absolutely blows my mind that their imagination is so immediately limited. Logically, though, since there is nothing else to build but SPAs and frameworks are great at building SPAs it must not make sense to even not use a framework. That line of thinking leaves me speechless, literally. I just spot responding and walk away.
I started with Motorola 68000 assembly in the late 70's early 80's (hobbyist not old enough at that time to work) while their where frameworks of sorts back then there really was not what we have to day. I can assure you though when you built stuff of enough abstraction you ended up with your own frameworks that helped you build new applications. Patterns of the way you do things and tried and true methods. Packaged up into reusable libraries.
You see it in every discipline, game programmers use game engines which are frameworks almost nobody is writing their engine from scratch because they don't need frameworks.
Enterprise programmers have saleforce, SAP etc. Hardly anyone is writing an ERP from scratch.
It's not that a lot of people that use frameworks don't know how to go it alone, I certainly do and most of the caliber of developers I work with certainly do. It's just that we realize we will, in the end, end up with something that looks like a framework. Because there was a day and time when that's exactly what we did and it was common practice. But that practice came with the additional overhead of training people on an internal framework, as well as maintaining documentation and the codebase of said custom framework.
It was more common and more acceptable before the internet and opensource that a developer or team would roll their own framework, create their own patterns and procedures and it was a very common practice to roll your own framework. But their where commercially available frameworks at the time for things like computer graphics, UI etc. Frameworks are a natural evolution of code reuse. The difference is today people tend to agree on third party frameworks as a standard way to develop as opposed to internally develop them. IN a effort to externalize, training, support and documentation of the framework.
I understand your frustration with developers conflating a simple page with SPA's. I only build large SPA applications I am not a web page developer, but if all I needed to do was provide a landing page, I would not use a framework because 90% of the deliverable is HTML and CSS. It's a lot of overhead to bring in something like React and the NPM build ecosystem because you have one tiny component of an otherwise static page.
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).
You’re write. I’m a tech lead in an ‘enterprise’ team, and the fight against spaghetti is so real.
I feel a lot of enterprise devs are older, and more set in their ways. It’a not just teaching them new technology any more - I have to fundamentally shift their approach.
All the while being 20 years younger and less ‘experienced’ than them.
It’s slow progress. Every time I relax control within a few hours I have to bring it back. One guy today tried to set up a deployment of a prepackaged service that involved building the service (in debug configuration), then running that. I had to explain that deployments out of /bin/Debug is a bit of a red flag. I’m not sure how you can miss that myself, but here we are.
I have to explain to "senior" developers why a deployment process involving keeping the source code on the prod server and building it with Visual Studio on the prod server is not a great idea.
Ofcourse they are, I know a good bit of React and I can get a good understanding of any reasonably sized React project within a short amount of time _because_ it's a React project. People may still be people and do weird stuff, but that's a given in anything you do.
Maybe this is just a problem where I work (large enterprise SV company) but a big issue is that a lot of engineers know better but they do a shit job because they are looking to deliver ASAP so they get brownie points for finishing a task quickly. These people are just looking to get promoted fast and they will have jumped ship long before they are held responsible for the maintenance burden of their spaghetti code. At the same time, people who actually take the time to write maintainable code get the shaft because they appear to be unproductive and are "blocking" progress. Of course, a good manager can see through this but good managers are rare where I work.
This could be read the other way too.
In my experience there is a spectrum from reckless to needlessly perfectionist, neither of which approaches are very helpful.
Being focused on delivery is not necessarily a bad thing. But then I've mostly worked in small startups, so perhaps it's different elsewhere.
In my experience this is not the case if you have experienced leads and architects. Just using a framework for the sake of using a framework can be just as bad or worse.
In my experience any team anywhere can turn any codebase into soup!
Strong tech leadership that provides good examples, institutes code reviews, establishes & follows standards etc is where nice code bases come from (even in tiny teams)
A framework enforces some organization by its very nature, even the barebone ones. Otherwise they usually break. Plus, the popular ones will have a community that sets some standards, example, off the top of my head: python significant white space
Frameworks are not a substitute for engineering standards but anyone whose really interested in that, pay the bills interested, first thing they do is look for frameworks
The difference now is it's only a "wild west" as far as app structure goes. Developers still need to put a lot of thought into component composition and app state to maintain a quality code base. Previously you had to do all of that AND put a lot of thought into how to update the UI correctly and efficiently. New approaches and frameworks removed the complexity of that last step.
Sometimes I question if people claiming vanilla is spaghetti have actually used vanilla in any meaningful way or if they are just parroting what others have said. I find that a lot of times, it's the latter...
For example, something that I've come to find cumbersome about frameworks is that expressing things in terms of states makes it more convoluted to express mutations. For example: in vanilla, one sensible unit of organization would be something like this:
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.
a) that doesn't do the same thing (button != input)
b) in React, it's extremely bad practice to mutate raw DOM elements programmatically (the idiomatic version is to use some state management mechanism and bind the value via `<input value={value} />`, which incidentally would be broken by this code)
c) setState may be asynchronous, so you can run into nasty surprises (e.g. you can't focus a hidden element). Whereas in vanilla code, unhiding logic could be added in a predictable procedural and explicit manner, in React a naive call to .focus() in the event handler may noop because of React-rendering-pipeline-specific reasons and then we need to get into its more obscure APIs to fix it)
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:
This is adding a line of code (useState) but in this case it's buying you something -- you have full control of the value and are insulated against DOM updates.
For point c I'm not sure what you're referring to. I can't think of a situation where React would drop your call to `input.focus()` on the floor. I just tried breaking it by spamming state updates and was unable to. The whole point of React is that it handles DOM updates seamlessly and I would be surprised if it didn't in this case.
Sure, if you're using a ref and being careful not to bind `value` in JSX, you're fine. That's not what you were doing though. Here's a simplified demo showing a variation of the issue: https://codesandbox.io/s/react-example-bytg0
As for controlled/uncontrolled inputs and refs/hooks: that's kinda my point. In order to declaratively wire things up in an idiomatic way in React, we've had to introduce a bunch of React APIs to the snippet just to express the equivalent of a "when you click me, focus that guy" action -> effect relationship, because otherwise that relationship is hard to express in terms of declarative state snapshots.
You've misspelled the handler, onClick is the correct casing. Fix that and it works.
Also you don't need to use a ref -- if I were inclined I could have grabbed the element by a query selector. I'm not sure why I would though, as I mentioned using ref is better protection against DOM updates.
> In order to declaratively wire things up in an idiomatic way in React, we've had to introduce a bunch of React APIs
Yes, because declarative programming is the benefit not the cost. As I said, you don't have to do it declaratively -- you can always use built-in DOM APIs -- but most people in the front-end community have agreed that doing things declaratively and architecting a UI as a state machine instead of a giant tree of independently mutating bits is preferable.
One of the biggest sources of bugs in jQuery projects is developers forgetting to keep the DOM in sync with the data. The benefit of doing things declaratively is you don't have to worry about it. Cutting that problem off at the source is an invaluable benefit.
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.
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.
1. You can implicitly return things so it provides nice syntactic sugar
2. Using an arrow function results in `this` being bound in the way you'd expect (coming from something like C++) in all cases without having to call .bind(this) anywhere. I'll never forget seeing promise chains starting with `const that = this;` in order to keep the right reference throughout the promises.
3. You use it for the previous 2 reasons and use it everywhere in order to be consistent
I fall into category 3 which is why I list it. It's not a technical reason so much as a code style reason so it is definitely subject to the opinions of each developer.
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.
> Looking at your comment history, seems like anyone who technically differs with you gets downvotes, I'm sure that's not how it supposed to work, bring it on anyway.
Probably a side-effect of what I usually choose to comment on, which are things that are objectively wrong or seriously misleading :) I think the HN voting system is poor, so I don’t use it, myself.
> Remember, an arrow function shares the same scope with [its] parent function
Exactly like a non-arrow function, then?
> Do you have any evidence to the contrary? I have experienced it when processing heaps of textual data in nodejs (the same engine that runs chrome). My script was crashing for no apparent reason, and just changing the arrow functions solved it.
Not only is that not evidence, it doesn’t support what you originally said. Slower ≠ crashing for no apparent reason.
If you mention which version of Node this was, I can go looking for evidence.
> Probably a side-effect of what I usually choose to comment on, which are things that are objectively wrong or seriously misleading :) I think the HN voting system is poor, so I don’t use it, myself.
Do you have any evidence that you do not use it?
> Remember, an arrow function shares the same scope with [its] parent function
>> Exactly like a non-arrow function, then?
No, not exactly. It looks like I need to be more explicit, here goes: Remember, an arrow function's BODY shares the same scope with its parent function
> Do you have any evidence to the contrary? I have experienced it when processing heaps of textual data in nodejs (the same engine that runs chrome). My script was crashing for no apparent reason, and just changing the arrow functions solved it.
>> Not only is that not evidence, it doesn’t support what you originally said.
It is called ANECDOTAL evidence, and yes, it is a thing. If you want SCIENTIFIC evidence, sorry I just do not have the time and energy. If you want to believe that arrow functions are a drop-in replacement for normal functions and that they are always better and faster in all situations, go ahead and believe that. And you'll do just fine, as long as all you are doing with JS is React and basic UI wrangling stuff.
> Slower ≠ crashing for no apparent reason.
My friend, this is a discussion, not a scientific thesis or a legal document. I do not have to explicitly explain every little detail and cover every little phrase so that someone does not misqoute me. Be generous enough to try and understand something someone is saying. So, to rephrase that too, when I say "crashing for no apparent reason" I mean "crashing for no apparent reason that I could find by looking at the code over and over again searching for bugs or typos". And yes, it was crashing due to timeout and memory issues. Please dont start arguing about how crashing and timing out are not technically the same thing.
> No, not exactly. It looks like I need to be more explicit, here goes: Remember, an arrow function's BODY shares the same scope with its parent function
Exactly like a non-arrow function, then?
I don’t mind if you don’t have the energy to support your claim, but I will recommend that you don’t make claims like “arrow functions are slower” if you can’t back them up properly or even provide any detail.
I also get the impression that you don’t know how arrow functions actually differ from non-arrow functions (see above), so your anecdote that you couldn’t figure out the bug doesn’t make a strong case.
> Do you have any evidence that you do not use it?
My browser was crashing for no apparent reason and stopping voting on HN solved it.
It is both method and closure. Which is not universal - io has method and block, ruby has def and block
And it is constructor. So it can be called both with and without `new` with different results. Other can't:
arrow = () => {}
// new arrow()
// TypeError: arrow is not a constructor
object = {
shorthand() {},
['computed']() {},
get getter() {}
}
// new object.shorthand()
// TypeError: object.shorthand is not a constructor
// new object.computed
// TypeError: object.computed is not a constructor
// getter = Object.getOwnPropertyDescriptor(object, 'getter').get
// new getter
// TypeError: getter is not a constructor
class Class {
static staticMethod () {}
method () {}
get getter() {}
}
// Class()
// TypeError: Class constructor Class cannot be invoked without 'new'
// new Class.staticMethod
// TypeError: Class.staticMethod is not a constructor
// klass = new Class
// new klass.method
// TypeError: klass.method is not a constructor
// getter = Object.getOwnPropertyDescriptor(Class.prototype, 'getter').get
// new getter
// TypeError: getter is not a constructor
function* generator() {}
// TypeError: generator is not a constructor
// new generator()
I actually was surprised just how many ways TC39 introduced so we do not use function. The change you observe is not a coincidence - it is carefully crafted.
Let me get this straight: Are you saying all the changes in arrow functions, the class syntax and generator functions were all a carefully planned initiative to get rid of the "function" keyword because it does too much?
>> Yes, <typo>they</typo> replace<typo>d</typo> "function" usage with safe alternatives. And don't forget 'use strict' - it affected "function" too.
> I'm not convinced at all
It could appear I've tried to convince you not to use "function". That never was the case, should have added at least one. And I do not agree with TC39 direction, just making observations. Please check my comment assuming that and typo.
My fix would be different. Prototype based inheritance is awesome http://iolanguage.com/tutorial.html and javascript could be as simple too:
Object
Object.__proto__ === null
object = new Object
object.__proto__ === Object
object.constructor === Object.constructor
object.toString === Object.toString
f = new Function
f.__proto__ === Function
fun.constructor === Function
object.private = function () { return 'hello' }
Object.shared = function () { return 'world' }
Object.constructor.static = function () { return '!' } // we need functions
with just a simple change
Object = Object.prototype
Function = Function.prototype
syntax new = function (ctx) {
let ident = ctx.next().value
return #`new ${ident}.constructor`
}
It looks almost boring (just don't redefine .constructor). Now this one is much harder:
Object.prototype
Object.prototype.__proto__ === null
object = new Object
object.__proto__ === Object.prototype
object.constructor === Object
object.toString === Object.prototype.toString
fun = new Function
fun.__proto__ === Function.prototype
fun.constructor === Function
object.private = function () { return 'hello' }
Object.prototype.shared = function () { return 'world' }
Object.static = function () { return '!' } // we need functions
Anecdotal if you're interested: I can't show it since it belongs to the company, but I just ran a grep in the app I architected and it has exactly 21 instances of the word "function"... some are comments, but most of the ones that aren't are inside a lodash debounce function. Total of 140000 non-blank/non-commented lines of code.
Btw, it's not banned, and I never really enforced it... but since I never use it myself, I guess the others devs picked it up?
It's in Vue.js, and in Vue you rarely see old-style functions anywhere, so there's that.
That's interesting. However, the Vue.js library itself uses the "function" keyword a lot, and the library is part of your applications code. Infact, it uses normal functions almost exclusively.
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.
Saying all arrows functions are bad and evil or that all normal functions are bad and evil is nothing but dogma. Each has its own place and uses, it seems many JS devs would rather not think of this at all and just use one form everywhere.
We're not using arrow functions for everything. Why are you assuming this?
We're using shorthand syntax in methods inside Vue.js objects [1], they also don't need the "function" keyword. In fact, they are suggested in the second link you posted, please read again. Arrow functions wouldn't even work in this situation.
We're mainly using two forms: shorthand and arrow. That's how we only have 21 instances of the "function" word in our entire JS codebase, and we could remove all of them if we wanted. That's what you asked for: a "JS app that completely bans the 'function' keyword". Well, we don't ban but it's possible.
And please read my comment again: I explicitly mentioned that this is not a rule, and I never enforced it. The team (39 committers ATM) reached that result organically, mostly influenced by my own personal style.
And sorry if this sounds harsh, but it seems that you have extremely limited knowledge of Javascript and ES6, so I'd suggest learning before you make such claims before you make a fool of yourself.
Btw, you're seem to be the one holding on to dogma here, since you seem unable to accept that the keyword is not strictly necessary in a large app.
First of all, are you aware of shorthand methods? Are you aware that you can have non-arrow functions without the "function" keyword :) ES6 has grown :)
And there was no goal intended with the grep. This is what you wrote:
> And I'd love to see the codebase of a JS app that completely bans the "function" keyword
I just grepped "function" to give you a personal anecdote of an app that doesn't need to use the "function" keyword much.
That was the first time I interacted with you, I was trying to be nice then, and you were completely hostile. Some of the replies were completely uncalled for.
---
EDIT: You just edited your message to add the part about shorthand methods. My point still stands. I never claimed to be only using arrow functions (in fact, you're the one who DID claim I was only using arrow functions!). I only claimed we rarely use the "function" keyword.
No, and part of the reasoning is to explicitly avoid the chance you might accidentally refer to the wrong `this`. There's an ESLint rule to enforce this: it will complain if you use a `function` without referring to the prototype this. Makes it handy because if I do use `function` I know it's because there's a reason -- e.g. some libraries still make heavy use of the local this.
The problem with frameworks like React is that the version you’re using and its API will become outdated in no time. We started using React in 2014 and their approach to state management changed at least three times since then. Not to mention build systems, tooling and libraries. In my experience that leads to a large fraction of developer time (10-30 percent I’d say) just going into often pointless refactoring that is necessary to keep up with the framework ecosystem, because you don’t want to run “legacy code”. Most large organizations seem to accept that but for smaller ones it can be quite a burden.
The beauty of the native JS APIs is that they are relatively stable: things that worked 10 years ago still work today, and can be done in the same way. Also, standard adherence in browsers has become much better so if you do not need to support legacy browsers like IE you can get away with writing pure JS without any polyfills or frameworks.
When has React's approach to state management changed?
The only change I know of is the introduction of the useState hook, but you don't have to use it.
The React team has done stellar job of maintaining a stable API with very minimal breaking changes. The only major breaking changes I can think of is the move of React.createClass to react-create-class and replacing the lifecycle methods through a slow and steady push over multiple major versions. I'm sure there were some smaller ones, but nothing that required any significant amount of time to fix.
As far as build systems and tooling, that's only as complex as you want it to be and doesn't have to change with the seasons. I've been using the same Webpack/Babel/React setup on one of my projects for about 7 years now with minimal work on my end (the only major upgrade was Babel 6 > 7, and Webpack 2 to 3, which took about maybe half a day to complete both).
Talking about global state management (not local state/props), when we started working with React their recommended method of state management was via Mixins. Those became deprecated in 2017 (I think). They then recommended to use only higher-order components (HOCs) for state management. Last year they deprecated this in favor of hooks. The context API has changed several times as well, though since that was never meant to be an end-user API I think it's less problematic. They also deprecated a bunch of life cycle methods (e.g. componentWillMount), though that is probably also a minor nuisance.
As you said you can still use the old ways of managing state (except mixins I think which were really removed for good), the thing is just that most of the ecosystem of third-party libraries (routing, state management etc.) quickly moves to the latest paradigm, so if you do not want to run outdated code with potential security vulnerabilities you will need to constantly refactor your code as well just to keep up with the ecosystem.
You're conflating several different things: patterns specifically recommended by the React team, patterns in vogue in the community, specific libraries from the community, and actual API changes in React itself.
The React team did definitely tell folks to stop using mixins and try using HOCs instead [0]. HOCs have some limitations as well, and hooks are designed to help address those [1], but it doesn't mean HOCs are suddenly broken and you can't use them.
React's actual APIs are quite stable. As the React team has pointed out, Facebook has something like 100K components in their codebase, and many of those are still using older APIs. For example, even `React.createClass` still works. Granted, it was moved to an external package `create-react-class` package a while back because it's discouraged, but the API still works (and that's what had mixin support).
The community jumped on render props, and the React team never specifically recommended them as a generally-encouraged pattern that I know of. The only example of render props in React's actual APIs is the `<Context.Consumer>` component.
The context API never "changed", per se. There's the original `this.context` API, which is now definitely considered legacy and deprecated, _but_ it still works fine as of React 16.x. The new `createContext()` API, added in React 16.3, is a new API that solves the same use case.
The deprecation of lifecycle methods is real, but the React team has been warning about that for a while. Note that even in future code, renaming them to `UNSAFE_componentWillReceiveProps` will still work, and the React team has provided codemods to make that fix if you want to keep using that code as-is.
The churn in the resulting ecosystem is a more valid point of concern. React-Router is a frequent target of complaints. That's _partially_ justified, as their API has changed a couple times.
As a Redux maintainer, I'm very happy that we've managed to keep the React-Redux API stable across multiple major versions and internal rewrites [2]. If you were using React-Redux v4.x, you _should_ be able to jump to the current v7.x just by bumping the package version.
Well, I'm glad you're happy with your work, just describing my epxerience working with React over the years and the frustration of having to keep up with an ever changing flow of changing paradigms and programming styles. People value different things in frameworks, for some frontend developers it's probably exciting that the community comes up with so many new things all the time and that they can learn a new state management paradigm every year and spend time refactoring their codebase, for me it's more a nuisance.
The problem of React is not that the core API is not stable, but that it's not a full framework for developing frontend apps as it misses e.g. routing and app-level state management, it only becomes useful in combination with libraries that provide this functionality (unless you want to write your own, which is also an option). It's the rapid pace of churn in the community eco-system that's a problem for me. Probably I'm just getting old.
I agree with you about the React team being very careful about maintaining backwards compatibility as much as possible. The API is however still a moving target, and some patterns or ways of doing things are actively pushed more than others. For example you can still use mixins and createReactClass now without any problems, but the docs and tooling all have one recommended way, which slowly shifts over time.
The problem just isn't with React though, I think the problem is with the culture that expects an opensource project to always be constantly evolving and putting out new things. I'm guilty of it myself... when checking out a library in github and I notice it hasn't been updated in awhile I get suspicious of it.
You're conflating several different things: patterns specifically recommended by the React team, patterns in vogue in the community, specific libraries from the community, and actual API changes in React itself.
This is fair, but I'm not sure how much it matters.
In reality, we build software as part of an ecosystem. Even if the foundation of an ecosystem remains stable, much of the value often derives from what is built on that foundation. It's the other tools. It's also the blog posts and forum comments and training courses and YouTube videos. It's also the collective experience of the community in using those tools, which is reflected in all of those sources of information, as well as simply passed on from one developer to another in person.
I'm not sure React can truly claim to be stable any more, though it's certainly done better at that than many projects in front-end web development. But even if that's true, the community has moved on from the older APIs to the newer ones. The new resources are built using the new APIs and written about the new APIs. If you're still using the older version of things, even things that React itself still intends to fully support, the reality is that you're going to be excluded from many opportunities elsewhere in the ecosystem.
Why would you want to use the old APIs for new code? Surely the benefit of API stability is that your old code that you don't want to change still works? It's not like they're introducing new things every week. It's more like once a year there are major new features, and the old ones still work.
Why would you want to use the old APIs for new code?
Consistency. A code base that has been maintained for several years but now does similar things in four different ways because of which APIs were fashionable at the time each of them was implemented isn't going to be great to work with.
Or maybe you just liked the old APIs better, perhaps because they were more helpful for your particular application than the new ones, or because some other tool or library you find useful works better with the old API.
Browser APIs have changed quite a bit in the last 10 years. Yes, the same approaches are still supported, but there have been many additions and modifications to core APIs. Ten years ago you would have never dreamed of trying to build complex front end behavior without something like JQuery, but now it’s totally unnecessary as all browsers mostly adhere to the standards. I guess my point is I don’t think React has changed any more or less than browser APIs - both have just steadily updated best practices just like any other piece of software since ever.
Just because the APIs remain largely backwards compatible does not mean that they didn't change. Just the fact that querySelector and querySelectorAll was introduced and started actually being usable across all the major browsers is a huge change IMHO.
This. Framework maintenance is something that takes a lot of time from our development team. Compared to other ecosystems (Python, Java), the frontend teams spend much more time dealing with updates to their stack (webpack, react).
Once a year I update my webpack, React, and TypeScript versions. And this is for a completely custom webpack toolchain. I don't think that's unusual compared to other technologies.
I think the main pain point is towards front end appearance/interactions. Js as a language has gotten more ergonomic, but it's been Turing complete forever. As a practical matter, the pain comes when you say "I want to align x" and come to learn that every browser has different flags to accomplish the task. I'm sure you've seen the fat stacks of moz/ie/opera checks and flags before. I know that example is bad, but I can't think of a good one at the moment, I rarely touch front end.
If you don't refactor and update your dependencies regularly you can easily end-up in a corner.
You can be hit by a bug in your dependencies, be it a functional one or a security one, but if your dependencies are completely out of date and there is tons of API incompatibilities between the version you are using, and the version implementing the bug fix, it will be really painful and take a long time to update, with stakeholders breathing down your neck expecting a fix asap.
Also, maintaining old tool chains can be a real drag (maintaining older building hosts, developer machines or VMs).
Updating frequently to be near enough the latest version is generally preferable.
In theory yes, but in practice even with frameworks codebases can turn into messes, and/or tends to become solid but completely frozen on a particular feature set. Small changes suddenly becomes daunting because the initial architecture needs to be changed to accommodate and surprise all is tightly coupled under the cover. With vanilla JS and spaghetti it's painful and boring but at least if I need to change a behavior on a page usually I'm done with a few lines of code. Edit: it's a tradeoff, but in early stages I found being able to make one the fly changes in a few minutes/hours to accommodate a customer instead of weeks (or never if it's too painful to evolve the perfect architecture) very valuable.
It really depends on the use case, and sure frameworks are awesome in the right context, but I think the current "best practice" of defaulting to one in any project no matter the business trajectory, product market fit maturity and team size is misguided.
At my position, there are at least 5 different interpretations of how to do React. Each project has an overseer who enforces a particular philosophy/design. JS frameworks are frameworks. They don't make the problem easier, they just change the terminology and add new abstractions which inevitably turn into angel hair pasta.
React is not a silver bullet. It solves one problem and it solves it very well: dealing with dynamical updating DOM views. There are still many different ways to architect your application but it stops the bikeshedding and reduces the opportunity for bugs at the view layer.
Agreed. This is my main issue with the "you don't need frameworks" rhetoric.
If you're a small team or a solo dev working on a simple app, and you know the source code very well, frameworks might not be the best choice.
However, if you've ever worked on a team of revolving contributors, constantly shifting requirements, or have any reason to reuse code across apps/repos, frameworks help immensely.
The biggest benefit to using something like React imo, is that when we hire somebody familiar with React, they can hit the ground running and start contributing immediately. Unless your app is dead simple, you won't be able to have the same velocity in a homespun framework (and given enough time, most "vanilla" apps turn into homespun frameworks).
> when we hire somebody familiar with React, they can hit the ground running and start contributing immediately
This is one of the selling points, but never really realizable in a large scale project. I've seen people become productive with an in-house template system, vanilla javascript + custom libraries even faster than on a "standard" React project.
As they emphasize in their own docs, React is not a framework. The amount of moving pieces you need around it for a working project ends up being more complex than your cut-to-size custom framework. There are many other positives to adopting standard tools, but this one is a red herring.
We've adopted a framework as a small team and it has nothing to do with onboarding new people. We adopted it became clear that if we stuck with vanilla JS, we'd end up re-building something like jQuery to keep our code and abstractions manageable. And then we'd build something like React, while doing a much poorer job of it. Once your app has some "click X and A, B and C should update" logic you quickly descend into a tangle of tracking dependencies by hand.
> Once your app has some "click X and A, B and C should update" logic you quickly descend into a tangle of tracking dependencies by hand.
I managed to deal with moderately difficult scenarios with about 7 files in typescript. I ended up using webpack but that is a dev-dependency which doesn't really count.
I built this for me, but if you employ some basic patterns and use something that is a little more powerful than JavaScript it isn't that hard. I also very rarely ever use a DOM selectors in my JavasScript.
I don't particularly like frameworks these days because you end up spending more time dealing with the framework than actually getting things done.
You could learn to pick better frameworks. I can’t remember the last time I dealt with a framework bug in react and I’m working on multiple teams on about two dozen web apps. And that’s without including other jobs.
It sounds like you’re not really working on apps frameworks like react are supposed to deal with, (7 files of typescript) so why do you care?
> You could learn to pick better frameworks. I can’t remember the last time I dealt with a framework bug in react and I’m working on multiple teams on about two dozen web apps. And that’s without including other jobs.
I have used quite a few frameworks over the years and there is always some PITA issue you have to deal with.
> It sounds like you’re not really working on apps frameworks like react are supposed to deal with, (7 files of typescript) so why do you care?
You don't need large frameworks to scale something. You can just do it with applying the right patterns (that these large frameworks use) and get 80% of the benefit. However that requires (shock and horror), thinking for yourself and learning how things work properly.
Could you share this? I'm a backend developer and I just want to make light frontends with flexbox, grid and javascript. But it'd be nice to scale to more complex UIs also with a few functions.
Just use vanilla JS to begin with. If your app has a lot of interaction, you can use React with create-react-app makes things easier.
You can still use vanilla JS, HTML and CSS. And it's not morally wrong.
Assess the requirements. Lots of moving parts and not a whole lot of time? React or Vue lets you draw the big lines quite simply. Need something simple or with fancy animations? Vanilla may be your best bet.
Personally I use vanilla for simpler stuff and React for more complex apps.
Don't worry, just make cool stuff. Nobody ever cares how you built it, just that it works.
Trello still uses CoffeeScript. It really does not matter as long as it works.
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).
"descend into a tangle of tracking dependencies by hand."
What is your definition of "by hand"? What constitutes by hand and what does not constitute by hand?
My definition is declaring each dependency explicity. "A, B and C depend on D or E." Add a watcher on D and E to go update A, B and C. Repeat for every combination of dependencies. When app is complex enough I threw that away for a framework that tracked dependencies for me.
Sorry, I don't understand. How would the framework know what the dependencies are if you don't declare them, even indirectly in some fashion? In what sense are they dependent?
Isn't this also simply true in the corporate world in general? Frameworks and best practices of doing something means that things are standardized. Standardization means that a vocabulary is shared and people understand each other.
You want to make people as swappable as possible. At least that's how I look at it from a management perspective (not a manager, but one can dream).
Not necessarily. Using popular frameworks will always widen the pool of contributors you have access to, no matter what "sector" your project falls under.
The problem is every dev thinking that every single project has to be resume buzzword compatible and super complex to hide the complexity they're sure is coming. But these requirements really only occur if you're forced into them by working on something in order to make money. The web is more than just the commercial web.
I'm using far more ridiculous, buzzwordy and complex tools in my non-commercial projects though. (In fact, that's usually the point of those projects.)
>In fact, that's usually the point of those projects.
And are you doing it because you truly enjoy the needless complexity or because the buzzwords would look good on your resume? If the later, again, that's profit motive and commercial web. Like how the only point of using kubernetes for personal stuff is to learn kubernetes for non-personal stuff.
> The problem with vanilla JS is not APIs, API is the easy thing.
Then the problem is really the API, if one needs to write tons of helpers just to make that thing bearable. Never had to write a framework on top of QT or WPF just to develop apps on these platforms. Web Components tries to make things a bit easier by allowing people to write their own widgets that know how to clean up themselves when removed, but it's not there yet apparently.
IMHO what the DOM needs is a good DOM diff API directly included in the browser. Right now it's either modifying DOM nodes themselves manually or just innerHTML string trickery, when wanting to update an entire tree of DOM nodes.
events are already a solved problem thanks to event delegation. It's DOM modification that is still painful.
This list of recipes doesn't solve the large front-end app at scale problem.
So personally right now, all I need IS a DOM-diff library. Using external widgets is a bit trickier, but with event handlers I can do required instantiation and clean-up provided the third party widget has the necessary event hooks.
> 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.
> Diffing isn't really needed - usually you either replace a subtree completely or change a few attributes, which isn't hard to write code for.
Replacing the entire page on model change doesn't work for interactive forms and I don't want to micro-manage every attribute. My model drives the view automatically so diffing is necessary. The memory cost isn't that big if the diff algorithm is implemented efficiently.
The problem is that the Wild West and unnecessary complexity has just been shifted up a level or two as devs are now facing the Wild West of frameworks, de ops has turned into a monster with an unnecessary large toolbox.
It really depends how much complexity you shift to js - if most of the work is done on the server, you really don't need to lean on js very much and you can have relatively simple js which just annotates certain elements and updates content in response to user actions. You don't need a framework if you're not trying to shift the entire view layer to js.
>The problem is building proper architecture, so code won't quickly turn into spaghetti [...] With vanilla JS it's the wild west.
This is a "problem" that I solved for myself years ago. It's not even that hard. I've started by noting that most of the issues with JS come from a few sources.
- Managing code dependencies.
- Navigating DOM. (Manipulating DOM is trivial.)
- Managing events.
- Synchronizing JS state with DOM state consistently.
If you pause to think about those, each of them has a straightforward solution that does not require a framework.
- Do not make libraries that directly depend on external code. Use DOM and HTML events for configuration and communication.
- Use CSS queries.
- Use timers or document-level events. They will continue to operate regardless of how elements change.
- Use DOM as your state storage. (Custom attributes + occasionally symbols.) This way your code itself is completely stateless.
There is more to it, but this is the foundation.
One of my favorite libraries is one that checks for specific attribute that contains a CSS query, then runs it, then outputs the result as a parameter on the original element. Couple dozen lines of code, countless applications. Best of all, you don't have to write any page-specific glue code. You load the library and it just works.
I hope then someone in your team is responsible for continuously documenting these patterns, however trivial they may seem to the author. I use frameworks for their documentation more than anything else. Maybe it's the UK developer culture but I haven't come across any codebase that has even remotely useful documentation in the past five years in three jobs. These "intuitive patterns" only exist in the senior dev's head. New comers have to either constantly ask or figure it out slowly by going through source files. Homegrown "simple and intuitive" solutions only benefit the rockstar who wrote them, not the other members of the team who are there now and who will come after the rockstar is gone.
Please use well documented frameworks, otherwise we're trading away the entire teams productivity in favour of the rockstar to have his say.
This is a real problem, but I'm not sure the root cause is that senior developer.
We've been building software far more complex than any web front-end for many, many years. Much of it was built without the help of all-encompassing frameworks. Much of it has stood the test of time longer than any web app, too.
Doing this requires a basic understanding of general programming principles from all developers. It requires a solid understanding of software design and architectural concepts from at least the more senior developers.
These things aren't rocket science. Millions of developers around the world have these skills. Many books and conference talks and training courses have been created to pass on the knowledge and the important ideas behind it.
Unfortunately, lots of people get into web development without ever learning even the basic skills of their trade. They learn by copying and pasting snippets from Stack Overflow or some YouTube video they found, jumping from one trendy framework or tool stack to the next every five minutes, with no awareness that those snippets were often also written by people who never learned the basics. Rookie mistakes are everywhere, and the culture often favours shiny new things over solid, well built solutions to real problems.
You can't really fix this just by getting developers to use a well-documented framework. For one thing, a lot of those frameworks aren't great themselves, either in their design or (not coincidentally) in their longevity, because they too were written by people with limited experience and understanding. But even if you do find a good framework, if your developers don't understand how to use it and the trade-offs it makes, they will still make dumb mistakes. When you have requirements that can't be implemented by just joining one framework dot to another until you're done, you definitely want someone who knows what they're doing writing that code.
As is often the case, the key to improving this is probably better training, particularly in the early stages of a career. But that doesn't always work in business, where resume driven development means developers will stick around long enough to add a few buzzwords and then jump ship to a better paid job somewhere else, taking the value of any accumulated experience with them. Until businesses start looking for real skill instead of buzzwords when they're hiring and start rewarding real and growing skill with their compensation packages, unfortunately the cycle will continue.
I disagree with storing your state on the DOM. Querying the DOM can be pretty slow, but also now you're state is going to be stringy-typed which will involve parsers and a whole mess of reasons you don't want that. If you want to keep the logic simple, a view should be a function from a state/model to some 'visual' representation (be it DOM, canvas, Qt, ASCII, a quilt pattern, etc).
A DOM node's attributes are strongly typed, but it is an object and you can still set Node.foo = barObject if you're so inclined. Not saying it's not without it's tradeoffs, but if you want state housed in the DOM rather than another state manager it's not hard to conceptualize.
What is the library you use for running functions based on CSS query?
I am working on a project where I initialize some DOM elements with data- attributes and control their visibility in response to a form input change event. It would be nice to somehow run the visibility check in more of a declarative/reactive manner without having to commit to writing my templates with a front end framework and build tooling.
Are there any reactive JavaScript frameworks that treat DOM and data- attributes as first-class citizens?
>I am working on a project where I initialize some DOM elements with data- attributes and control their visibility in response to a form input change event. It would be nice to somehow run the visibility check in more of a declarative/reactive manner without having to commit to writing my templates with a front end framework and build tooling.
Here is an approach you can use:
const name = 'check-if';
const aState = name + '-state';
run();
function run() {
document.querySelectorAll('[' + name + ']')
.forEach(update);
setTimeout(run, 50);
}
function update(target) {
let selector = target.getAttribute(name);
let matchedSomething = document.querySelector(selector) !== null;
if (target.getAttribute(aState) !== matchedSomething.toString()) { //only update when change is necessary
target.setAttribute(aState, matchedSomething);
}
}
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.
I'd say the bigger problem with vanilla JS or any other imperative UI framework is exactly that, the imperative nature of these tools. React introduced the frontend world to a declarative approach for keeping the DOM in sync with your state. Until we have something similar in the native API, React and co. will continue to exist.
Frontend development is a tricky beast because its hard to separate business logic from view logic. Since all your code relates to the view, its temping to just stick all your code into the view component or controller. This makes your components huge, untestable, and brittle. An great frontend developer will keep extracting models and business logic from view code until the view code is lean and really only renders. Some things are easy to extract like http calls or parsing logic. Other things are harder to see - like logic that might drive a step wizard. Even code like this can be expressed in plain models with plain functions, but its a lot harder to see and extract. Most people don't get there, or just don't care, so many frontend codebases end up with spaghetti view modules that you edit and pray things still work.
THIS a x1000 THIS !! There will never be a perfect framework, and jquery for a multi-person big project. It WILL be a mess in due time ! a Framework(even the most of the crappy ones) at least give you some opinionated standard ways of doing stuff. You can't pay me enough to work in jquery straight... Not saying it can't happen with frameworks. Just saying if you do a 100 projects with jquery or 100 projects with frameworks... There will be more chance the jquery ones will be a mess.
I learned jQuery on a project where everyone was expected to be full stack but only 2.5 of us could do any deep work on the front end.
I have done much, much harder things than convincing my coworkers to distinguish between 'important' nodes in a composition and incidental ones. Never put the incidental ones in your selectors.
If I'm a "Select All" checkbox, I need to find all of the checkboxes in "my" block of HTML that are not me, and select or unselect them. I don't give a shit if that's two divs up, one over and three down. Or if some IE bug means now it's three divs up and two over. I care about some top level element, and any of its children at any depth.
That's it. If I write my element selectors that way, I'm done and the layout people can put in a scrollbar later, or an expando. Also if I write my CSS the same way, it's easy to make these sorts of changes and it's easy to correlate the CSS with the Javascript that affects the same elements.
So much simpler than spending all day in a debugger when you're not in bug triage.
Most of those query selectors we relied on now have feature parity in the spec. I don't see why you couldn't use the same strategies in a vanilla situation today.
Could you expand upon what you mean when you say a checkbox has "my" block of html? That a given element should not make changes in elements that are at a higher level in the tree?
There are a bunch of elements we add to the page or remove to get certain visual effects to work well but they really have nothing to do with the logic of the page. Few if any interactive components ever care about them, or only for one specific interaction.
Classic example of the 'only one interaction' situation: the coworker who thinks he can use string concatenation for query parameters and you know that if you just wrap it in a form element, all of that is cheap or free and you just have to hook the form submit event to turn it into an AJAX request instead of a navigation. But that means that you've wrapped all of his DOM in a form element and now all of the CSS and half of the handlers stop working because they're looking for body>div>div>option and now it's body>div>div>form>option and now you wish you hadn't even touched this stinking pile but it's the principle and by god you're gonna finish this.
Or you had a block of elements on a page and now your boss wants it on the other side of the page, on another page, on every page, all over this page, or on a completely separate site.
What you want to solve these problems in a way that mostly stays solved is to try for a query selector with the lowest specificity (and no IDs) that still exactly identifies the DOM elements you are looking for. So there is some titular 'owner' element that all of these interactions are contained in, and they find each other by walking up until they find a particular shared parent and call parent.querySelectorAll() to find their peers, and only their peers. Not some other random element halfway down the page.
So for instance a click on .preferences .selectAll should find the first parent with class 'preferences', call querySelectorAll(".options"), and then invoke foo.selected = true on all of them. Not parent.parent.parent and then down through div>div>ul>li>input[type="checkbox"]
On the topics of speed and lightness: does Svelte really have a proven track-record in real-world usage at this point? I understand that it has a neat compiler and some clever ideas behind it (no virtual-DOM), but still.
It doesn't have to be wild west but I don't disagree it usually turns into that.
Before frameworks I spent a lot of cycles learning (usually the hard way) how to organize jQuery/JS code so it wasn't a total mess. I like to think I finally got it fairly maintainable for reasonable sized code bases. But by that time existing frameworks made a lot more sense so that's a bunch of thinking I'll never get back. I would guess I'm not the only one in this situation either.
Here's a really good book BTW if someone isn't aware of it.
That's true of every language. It's the software developers job to build the architecture.
I am an advocate for frameworks in commercial projects, for ease of knowledge sharing, speeding up onboarding and having a strong architectural philosophy built in. But we can't forget that we are the makers, we make the frameworks. React and friends are Javascript, anything they can do we can do too.
I am happy to use them for work. But I find all frontend frameworks too tooling heavy and full of arbitrary details you have to learn once and promptly forget. In my personal projects I have a simple architecture I use to organise my code in vanilla JS, no tooling and it's simplicity lends well to small projects sprinkled with only some dynamic UI.
The problem with frameworks is that they tend to drive the functionality of the site itself. It's easy for developers to start thinking in terms of what fun new things the framework allows rather than what the site actually needs.
I think frameworks are great, but you have to develop a self restraint from using every bell and whistle that's in it.
A trick I use to make the JS code more maintainable is to wrap code into pure functions that returns an element. For example if you need an input that only accept numbers: var input = makeInputThatOnlyAcceptNumbers() where the function returns the element, and all nitty gritty state handling is done inside the function.
Are transpilers included in Vanilla JS? If not, then IE 11 and Edge prior to 15 don't support async/await, which would mandate two codebases for lots of use-cases. Similarly, lots of other stuff has uneven support, hence polyfill, which also isn't "Vanilla JS" sensu stricto.
Well at least with vanilla JS you know your skills will be useful again in the future. With frameworks such as Angular or React, they can disappear and be replaced by the next flavor of the month pretty fast.
From what I have seen React is not better. It may not be spaghetti but then it is an exercise in architecture astronautics with way too many layers of indirection that is might as well be that spaghetti bowl.
I completely agree. What's everyone's favorite extremely lightweight view frameworks? And for those of us writing SPAs, favorite controller and routing frameworks?
The thing I really, really like about Vanilla JS is that it has 0 (zero) dependencies.
If something breaks in Vanilla JS, you know with 100% certainty that it's your code that's failing. With a framework, it's mostly the fault of your code - but there's always an outside chance that it's somebody else's fault, buried deep in some 3rd party dependency that may-or-may-not have been maintained.
I like React and Vue (I love Svelte!) - on a well-planned project they can perform miracles. But I see no reason to hate on Vanilla: it has its place too ... if you know what you're doing.
> If something breaks in Vanilla JS, you know with 100% certainty that it's your code that's failing.
If you're lucky enough to have the same developers for the duration of the project. Otherwise it'll be your predecessor who worked at the company 4 years ago's code. I've had to do far too much "reverse engineering" of "we don't touch that" code.
On the other hand, I've literally never encountered a bug in React. I guess it must have them. But I think not all that many.
I don't disagree. I still live in hope that one day I'll work on a project where all functions and variables have relevant and informative names and the Runbook is (accurately!) updated with latest changes on a weekly basis.
The point I was trying to make wasn't about previous developers on a project. Rather, it's the way frameworks ask me to trust them about the choices made by unknown developers to include NPM packages by other unknown developers in the framework's build. That, to me, is the definition of "wild west".
React is backed by Facebook. When it comes to frameworks I'm a lot happier to trust an open-sourced codebase backed by a company with a big vested interest in making sure that all the NPM modules they include (and all their dependencies, etc) are solid, safe and up-to-date. Even so, React's package.json file lists a devDependency for core-js - whose main developer is currently serving 18 months in a Russian jail[1].
How much trust we choose to put into other, unknown developers and their code is a risk to any project, is all I'm saying.
> If something breaks in Vanilla JS, you know with 100% certainty that it's your code that's failing.
Or the browsers' code which is a bigger problem.
I've been burned in the distant past by a blackbox framework that didn't work well with my use case (JSF) so I can sympathize with your position. These days I'd rather hit the occasional framework and polyfill bug than deal with a wide range of interopt issues.
Can confirm. Before I started using Preact, my client-side code was a large vanilla script. I would rather go work on a farm in Mongolia than go back to that.
Doing interviews I've heard a lot of this - react is more efficient than using the DOM directly, etc but no one can tell me why - they are just parroting what they hear or get taught at coding camps and make a fool of themselves.
I don’t think there is anything wrong with building your own ‘framework’. I feel like there is a lot of good experience gained, and learning to be had from taking this approach. Especially for less experienced devs.
It forces you to brush up on fundamentals, fill knowledge gaps, and practice/ learn design patterns. Also the end result is there is no ‘magic’, you know everything that is happening because you implemented it yourself.
Frameworks are great, but I don’t like reaching for them when I start new toy projects, I want to use it as an opportunity to improve my core JS skills.
I agree. I'm stubborn to take on frameworks as I have a vision and want to code it now; rather than learn and understand the framework to do what I want to create which by then my idea has deflated.
The company I am currently contracting for use Ansible. I've never used it prior and I get where the hype is but to me the whole system is just a mess. Asking the younger developers on "why isn't this working" feels quite embarrassing.
Five different folders, within more folders and then more folders on that; then you've got YAML which if you have one wrong space spews errors. I'm not dissing any of it as when it works when it works they do have their reasons for existence but it just feels so convoluted to do something you could write simply in bash.
Maybe I'm just a cynical SysAdmin throwing "get off my lawn" while wanting to see the world burn. But the era where I am from, where the internet was truly developmental; where if you wanted a CMS you built it from scratch. If you wanted a forum, you built it from scratch is kind of almost deleted from internet history.
Wordpress came a long and it ended all that, though I suppose it had to happen if you wanted more features from the users on the internet. It was a niche in the early 00's to have your own website but now my 70 year-old mother administrates her own website.
No disrespect, but I think you proved @vbezhenar's point. The right way to structure the code is with a framework of some kind, even if it's homegrown.
If there is anything I am trying to prove it is that you don't need complicated frameworks like Angular or React. Those frameworks have gotten too complex for what they do.