Search posts, tags, users, and pages
What?? :-\ It sounds lot like you know a lot, but then it also sounds like you haven't touched a new framework in years.
There certainly are disadvantages to manipulating the DOM directly with native methods, namely tight coupling of application logic to the presentation/rendering system. JavaScript logic is not easily unit-testable when it directly manipulates the DOM. You also cannot swap out DOM rendering for another rendering system, such as how a framework like NativeScript does so that it can render native GUIs on Android and iOS. You can't do server-side pre-rendering such as how Angular Universal does.
I honestly don't understand what your gripe is about. Do you really need to squeeze a small, negligible amount of performance out of your JavaScript code? Forgive me if I'm mistaken, but if you've maintained a JavaScript codebase with 10,000 LOCs, the cognitive overhead (and time!) that another layer of abstraction saves me is well worth it. Besides a framework like Angular with its ahead-of-time (AOT) compilation can preprocess the HTML for your components at build time to generate optimized JavaScript that will do direct DOM manipulation under the hood.
There certainly are disadvantages to manipulating the DOM directly with native methods, namely tight coupling of application logic to the presentation/rendering system.
Could you actually explain that, I see words but no meaning. In particular this:
JavaScript logic is not easily unit-testable when it directly manipulates the DOM.
I don't understand how/why/where that would be an issue or even a problem; be it something simple like node walking or doing createElelement, createTextNode, appendChild, insertBefore, etc, etc... What's the problem compared to "hurr durz eyes canz queryAll ans innerHTML"? I'm not even certain what you mean by that as I see the words but... Could you give me a real-world snippet example of where it goes bits-up face-down in that way?
You also cannot swap out DOM rendering for another rendering system, such as how a framework like NativeScript does so that it can render native GUIs on Android and iOS
... and innerHTML style query-selector style methodology can?!? Bullcookies!
I honestly don't understand what your gripe is about. Do you really need to squeeze a small, negligible amount of performance out of your JavaScript code?
It's not small and insignificant when we're talking 25% difference in scripting, and cutting the memory footprint in half or MORE since triggering the parser will bleed a mobile unit's battery dry. Bypassing the parser saves battery and I have YET to hear a single ACTUAL explanation of ANY reason why it is avoided. Or at least, not one that I can read as anything more than marketspeak double-talk. Again, its' a bit like academia white-papers where they use a slew of words but they hold ZERO meaning for me.
That said:
but then it also sounds like you haven't touched a new framework in years.
My experience with current frameworks is undoing them BECAUSE THEY KEEP SCREWING OVER THE CLIENTS WHO COME TO ME FOR BEING IN COURT OVER WCAG VIOLATIONS AND SEO FAILINGS! In particular asshattery like vue.js and react are INSTANT violations since they are more often than not used for scripting only render with no graceful degradation. Never fails that most of the clients I have knocking on the door, the problem is some "gee ain't it neat" framework fanboy who knows jack-all about HTML, CSS, JavaScript, or accessibility norms has pissed all over the place with that rubbish.
... and most of those clients have ALSO been screwed over by Photoslop jockeys under the DELUSION they are "web designers" spanking out pretty pictures with ZERO knowledge of HTML, CSS, limitations of the medium, emissive colourspace, graceful degradation, semantics, logical document structure, or standards like the WCAG (web content accessibility guidelines).
My bread and butter has been ripping these "modern" frameworks OUT of clients websites whenever they are screwed by them. Hasn't really endeared any of them to me and is why just the word "framework" has come to have a negative connotation for myself and others who work directly in UI/UX/Accessibility! From halfwitted idiocy like bootcrap and w3.css pissing on the entire reason HTML and CSS are separate in the first place, to equally mentally befuddled derpitude like relying on JavaScript ONLY to deliver what's actually important -- CONTENT -- it all seems carefully crafted to tell large swaths of potential visitors to websites to go f*** themselves!
... and I think what's REALLY pissing me off about this is year after year as this derpitude gets more and more popular with more nubes and rubes duped by the propaganda, bunko -- and even outright lies -- I'm having to tell more and more clients that the ONLY solution to their woes is to pitch EVERYTHING in the trash and start over from scratch; as well as suggesting they sue and/or fire those who saddled them up and took them for a ride in the first place!
My freelancing is quickly going from "accessibility consultant" to "hatchet man"... and I already worked that job in the late 1990's -- it's not fun being the guy handing out pink slips. EVEN when it is well deserved.
Regarding tight coupling:
I work with Angular these days so I'll explain in the context of how Angular addresses this issue. To start here is a caution statement straight out of the Angular documentation (see ElementRef):
Relying on direct DOM access creates tight coupling between your application and rendering layers which will make it impossible to separate the two and deploy your application into a web worker.
Angular provides a service named Renderer2 that serves as an abstraction on top of the rendering engine. This enables you to write one renderer for rendering to the browser DOM, another renderer for rendering, say, an Android layout tree, another for server-side rendering, another for web workers, etc. Using dependency injection you can then swap in different renderers without needing to rewrite your application logic. This approach enables you to deploy the same application logic to a web application, a native mobile app, or a desktop app.
Under the hood Angular is not using innerHTML to insert DOM elements (the same for React, Vue, etc.); even Angular warns of the XSS vulnerability with this approach (see here). It is using a parser, but its own specialized parser for parsing its special markup language. That parser will generate an abstract syntax tree that is then used to wire up data bindings and event handlers, and finally to build up a render tree with good old native DOM manipulation. As I mentioned before, this parser can be run offline ahead of time to eliminate the need for parsing at runtime.
Regarding unit testing:
I presume that since you have a disdain for frameworks you are also not separating application logic and presentation by leveraging any sort of MV* pattern or by componentizing your HTML and JavaScript. So let's take the sorted list example from the demo section of your library's site.
Suppose I've made an Angular component of a sortable list.
@Component({
selector: 'sortable-list',
template: `
<ul>
<li *ngFor="let item of items">{{item}}</li>
</ul>
`
})
export class SortableList {
items = [];
constructor(items) {
this.items = items;
}
sortAsc() {
this.items.sort();
}
sortDesc() {
this.items.sort().reverse();
}
}
To test that the Angular component properly sorts a list, I only have to instantiate a new list component, call its sortAsc() and sortDesc() methods, and test assertions on the items property on the component. Because I've separated application logic and markup and because I can trust the templating engine (as it's been thoroughly tested), there's no need for building up a DOM tree.
describe('SortableList', () => {
const items = ['A', 'E', 'B', 'D', 'C'];
describe('sortAsc()', () => {
it('should sort the list ascendingly', () => {
// Arrange
const cmp = new SortableList(items);
// Act
cmp.sortAsc();
// Assert
expect(cmp.items).toEqual(['A', 'B', 'C', 'D', 'E']);
});
});
describe('sortDesc()', () => {
it('should sort the list descendingly', () => {
// Arrange
const cmp = new SortableList(items);
// Act
cmp.sortDesc();
// Assert
expect(cmp.items).toEqual(['E', 'D', 'C', 'B', 'A']);
});
});
});
Now let's consider the direct DOM approach where the model is stored directly in the view (i.e. as text nodes in an HTML unordered list):
<ul id="sortList">
<li>A</li>
<li>E</li>
<li>B</li>
<li>D</li>
<li>C</li>
</ul>
Hopefully you can see that the setup and teardown steps to insert the snippet above into the document are much more involved, as is the logic necessary to prepare for assertions.
describe('SortableList', () => {
beforeEach(() => {
/* Here's one place where direct DOM manipulation becomes inconvenient.
* The setup procedure becomes quite involved, not encapsulated,
* and difficult to maintain. */
// I'll leave the actual setup as an exercise for the reader.
});
afterEach(() => {
/* As will teardown as DOM manipulation becomes more involved. */
document.querySelector('#sortList').remove();
});
describe('sortAsc()', () => {
it('should sort the list ascendingly', () => {
// Arrange
const sortList = document.getElementById('sortList');
// Act
_.USort.element(sortList, function(a, b) {
return _.Compare.string(a.data, b.data);
});
/* Note that I haven't maintained encapsulation here so my unit test
* is prone to deviate from the main source. */
// Assert
const values = [];
const listItems = sortList.querySelectorAll('li'); // Sorry but not wasting any more time to "walk the DOM" here
listItems.forEach((item) => {
values.push(item.textContent);
});
expect(values).toEqual(['A', 'B', 'C', 'D', 'E']);
});
});
describe('sortDesc()', () => {
it('should sort the list descendingly', () => {
// And do it all again.
});
});
});
I only tested one simple list here. But imagine how complicated the unit test becomes if you have a full page of intermingled application logic and presentation code when you haven't componentized elements.
See to me that's taking something simple -- sorting stuff you already HAVE on the DOM, and throwing endless pointless code at it for Christmas only knows what! It's nonsensical garbage like that which made me reject Angular in the first place... just like all these other garbage frameworks and the convoluted hoops of fire they seem to expect you to jump through for relatively simple tasks.
Much less the derpitude of doubling-down on the memory footprint!
At least, if you're doing this CLIENT SIDE, aka the place where the DOM exists and matters. Server-side tHEN I could MAYBE see what you are saying, but at that point the HTML and DOM should have jack-all to do with the data processing if you maintain separation of concerns. LIVE changes like LIVE sorting ARE the huffing view, that's why you use the view to do it! You're not actually changing the data!
So much of what you've put there reeks of the conceptual/academia double-talk and not actually caring about efficient development. Shoe-horning programming 'paradigms' and models into things in a manner that's more akin to driving a screw with a hammer.
That entire final snippet calling my elementals library making me want to pound my forehead into a wall with the obtuse syntax and pointless gibberish. All that describe and assert bullshit -- just write the huffing code! It is EXACTLY that garbage that makes me think the people who use systems like angular and react don't know enough about HTML, CSS, or JavaScript to be working in any of them! You're just slopping more complexity on top of things for NOTHING!
Oh, and as to having it's own parser -- that's part of the problem. Dicking around with excess string processing to make a 'dom', then to not use it as a dom, to then make it as a dom... yeah, huffing brilliant. Nothing like adding more steps and more processing instead of bothering how to use the client side technologies of HTML, CSS, and JavaScript properly... a situation only made worse by basically writing two to ten times the code necessary AND transmitting same!
It's one giant colossal programming circle-jerk! ALL because programmers either can't be bothered to use HTML properly, or cannot wrap their head around actually using the DOM to do what the DOM does CLIENT side!
Particularly when you have the GIBBERISH of "oh but it uses the dom, but it has a parser server-side" -- then what the F*** is it sending client-side? Marzipan and kittens?
But of course, what usually ends up client side is nothing more than flipping the bird at accessibility. Cute for a full stack crapplet, ZERO huffing use on a website if you actually care about delivering content to as many users as possible.
Dude, are you trolling us? If you need to be stubborn and sanctimonious to get along, that's your perogative. You claimed you were asking for a genuine answer; but I guess you only wanted to broadcast your diatribe.
I think I'll stick with opinions about development practices from the company who has actually written a browser. Feel free to curmudgeonly handicap yourself with your archaic development practices.
And by the way, that "obtuse syntax and pointless gibberish [and] all that describe and assert bullshit" is what you call an automated unit test. It's what professional software engineers use to ensure high quality code free of errors and regressions.