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.
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.
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.
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.
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.
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.
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.
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.
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
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 => {
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.
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
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?
>> 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 functionsBtw, 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...
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 happenTo 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.
const doThing = event => {
input.value = event.value;
input.focus();
sound.play();
}
button.onclick = doThingThe 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.
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...
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.
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.
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.
The problem usually isn't react, but that most projects using it directly use it wrong.
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.
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.
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).
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.
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.
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.
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).
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).
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.
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.
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.
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.
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.
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"]
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.
I think frameworks are great, but you have to develop a self restraint from using every bell and whistle that's in it.
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 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...
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.
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.
Easier said than done when best practices shift every 6 months.
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.