On this page


  1. Daring Fireball, John Gruber, and Threads
  2. Tagged Template Literals Are the Worst Addition to Javascript
  3. There's nothing great or particularly amazing about Angular and its build processes
  4. The broken promise of Web Components
  5. Why I'm not using Google's closure compiler
  6. Javascript Tools: A Story in Disgrace
  7. Javascript: Fatigue vs. Stockholm syndrome
  8. Поговорим о "мышь против клавиатуры"
  9. Ok, W3C and WHATWG, don’t die, but…
  10. W3C and WHATWG should die a quick and horrible death

John Gruber, Meta, and privacy

There's no end of John Gruber advocating for privacy and fighting Meta/Facebook. These are just some of the quotes, and I really like the last one: "The entitlement of these fuckers is just off the charts."

5 February 2021

And Apple’s new tracking-related features are not “anti-tracking”. They’re simply about raising user awareness of tracking and giving users control over it.

Let’s say a cottage industry arose where commercial companies were, unbeknownst to most people, plugging their fleets of electric vehicles into the outdoor power outlets on people’s homes overnight. “No one told us not to plug our electric delivery vans into these homes’ freely available power outlets.” And then, after this practice comes to light, the electric company adds a feature where every time a new vehicle is plugged into your outdoor power outlet, you, the homeowner, need to authorize that vehicle as being allowed to charge using the electricity you pay for. If you don’t authorize it, they don’t get the juice.

27 May 2021 about Facebook's reaction to AppStore privacy labels

Let’s get them some lollipops, make the boo-boo feel better.

(Alternative quip: “By sharply reducing burglaries, police are limiting the ability of pawn shops to create value from stolen goods.”)

16 December 2020

Apple’s “Privacy Nutrition Labels” launched this week on the App Store... It’s worth going right to the source to know what Apple is requiring here, because the companies who are coming out of this looking bad are attempting to misdirect attention.

To see them in action, just go to any app’s listing and scroll down a bit, and you can’t miss them. View the details for apps that respect your privacy and you’ll see a concise listing. View the details for apps that don’t — like, say, Instagram or Facebook — and you’ll get screen after screen showing just how much information about you they collect. Instagram and Facebook’s app privacy listings look like those crazy-long receipts from CVS.

16 February 2022

There’s also an implication here that Apple didn’t give the companies who’d be affected by ATT sufficient notice before instituting the changes. And we all know who the primary “company” is: Facebook. I’d say Apple bent over backwards to give Facebook time, and how Facebook reacted is instructional.

3 September 2020

This new ad from Apple touting iPhone privacy protection is good, and genuinely funny. But what makes it funny — the premise is a series of people loudly sharing in the real world the sort of information that gets unknowingly tracked online — is actually the perfect analogy to help explain how the tracking industry — what ought to be considered the privacy theft industry — has grown into existence.

Consider the new ad-tracking privacy protection feature in iOS 14. The tracking industry, led by Facebook, is up in arms about it

The entitlement of these fuckers is just off the charts. They have zero right, none, to the tracking they’ve been getting away with. We, as a society, have implicitly accepted it because we never really noticed it. You, the user, have no way of seeing it happen. Our brains are naturally attuned to detect and viscerally reject, with outrage and alarm, real-world intrusions into our privacy. Real-world marketers could never get away with tracking us like online marketers do.

John Gruber, Meta, and Threads

In summer of 2023 Meta rushed its release of Threads hoping to capitalise on yet another one of Musk's inane decisions.

At the time of its release Threads:

But most importantly: Threads didn't launch in the EU.

The reason is ridiculously simple:

Gruber's reaction to this has been stellar. It started even prior to this, when many Mastodon admins have decided to pre-emptively block Threads if it ever implements ActivityPub protocol. But he definitely went ballistic when Threads launched. Both over at Daring Fireball and in his personal accounts:

06 July 2023

Threads is the most fun, most interesting new product of the year, and no one in the E.U. can use it, or will be able to use it anytime soon, because their own elected officials passed a law that effectively bans it.

Nice job. Have fun over here in the library.

13 July 2023

Threads is not available in the E.U. yet, but is in North Korea

Drakonian and confusing Digital Markets Act (later removed from original text, but internet remembers, see comments: https://mastodon.social/@daringfireball/110665232720661773)

Threads doesn't track you and I'm totally serious. What exactly do you think Threads can glean about users other than what they're posting/doing in the app?

And the zinger:

14 July 2023

(quoting Aaron Levie)

Why doesn’t the EU just turn off the web?

There are countless more where he defends Threads from any possible angle.

John Gruber and the tragedy of preaching to the choir

Let's skip the obvious conspiracy theory that John Gruber is paid by Meta to promote and defend Threads. I think the reason is much simpler and sadder.

Over the years Daring Fireball has built a loyal following. It has always been a good source of Apple gossip, decent summaries of tech-related discussions etc. And a lot of that audience has been sycophantic.

In the mad rush to exit Twitter several things happened:

Mastodon isn't sycophantic in the least. Every time Gruber praises Threads and bashes privacy regulations Mastodon audience is not amused, and it's a polite way to phrase it.

I think Gruber now yearns for the days when he could mostly preach to the choir. Unfortunately for him, the alternatives to Twitter (Mastodon and BlueSky) never gave him this opportunity. An app from fuckers whose entitlement is just off the charts might just be it.

What are tagged template literals?

I will borrow the excellent straightforward definition from Exploring JS:

The following is a tagged template literal (short: tagged template):

tagFunction`Hello ${firstName} ${lastName}!`

Putting a template literal after an expression triggers a function call, similar to how a parameter list (comma-separated values in parentheses) triggers a function call. The previous code is equivalent to the following function call (in reality, first parameter is more than just an Array, but that is explained later).

tagFunction(['Hello ', ' ', '!'], firstName, lastName)

Thus, the name before the content in backticks is the name of a function to call, the tag function. The tag function receives two different kinds of data:

  • Template strings such as 'Hello '.
  • Substitutions such as firstName (delimited by ${}). A substitution can be any expression.

Additionally, tag functions get two versions of each template string:

  • A “raw” version in which backslashes are not interpreted (\n becomes \\n, a string of length 2)
  • A “cooked” version in which backslashes are special (\n becomes a string with just a newline in it).

This is literally all there is to tagged template literals. It’s a function call with an array of strings (each string is in two versions), and an array of substitutions between the elements of said strings.

What are tagged template literals presented as?

I believe this is the future of JSX, and it’s only just getting started. There are some very interesting optimizations Tagged Templates make available, like identifying and hoisting static parts of a view (essentially memoizing them).

Jason Miller

Writing HTML in HTML files, writing code between <script> tags, writing Javascript in .js files is the same as writing code in string blobs and parsing them at runtime.

A conversation among several people

These are tagged templates, not strings. They work as code at runtime, and it already has support to optimize it, compile it, etc. This is JS all the way down.

magicalist

You parse the string literal, just like you parse the string that is the contents of a JavaScript file.

spankalee

There are many more, but they all basically come down to the same thing: //there’s no difference between a JS-file loaded into and run by the JS VM, and run-time function calls with arrays of opaque strings//. And this is the future, and it’s amazing.

So why do I think these are bad?

Once again, I’ll steal a quote:

…we’ve learned not to write code in strings. You’d think this would be a fundamental law of software engineering

Writing code, not strings, means you can do everything to it that you can do to code. You can type check code. You can lint it. You can optimize it, compile it, validate it, syntax highlight it, format it with tools like Prettier, tree shake it…

stevebmark

In a language that’s already a laughing stock for its insane dynamic type system, we said: “It’s all right, we’ll have all our code in strings now, thank you very much, and we’ll make sure we parse it at runtime because what can possibly go wrong”.

The only reason projects like lit-html, HTM and some others can boast about their “accomplishments” building fast, effecient libraries is because string handling has been insanely optimised by the modern Javascript VMs. And that .innerHTML is no longer the slowest operation on the DOM. Let’s look at some examples, shall we?

Examples

lit-html

Project: https://github.com/polymer/lit-html, https://lit-html.polymer-project.org.

Tagline: “An efficient, expressive, extensible HTML templating library for JavaScript.”

Alternative tagline: “Next-generation HTML Templates in JavaScript.”

Sample code:

html`<h1>Hello ${name}</h1>`

html`<input .value=${value}>`

html`<button @click=${(e) => console.log('clicked')}>Click Me</button>`

Yup. It’s not just template literals. It’s an additional templating syntax on top of template strings.

lit-html literally parses HTML with regular expressions, appends a bunch of strings together, and then just dumps them into the DOM via .innerHTML.

NΘ stop the an​*̶͑̾̾​̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨe̠̅s ͎a̧͈͖r̽̾̈́͒͑e n​ot rè̑ͧ̌aͨl̘̝̙̃ͤ͂̾̆ ZA̡͊͠͝LGΌ ISͮ̂҉̯͈͕̹̘̱ TO͇̹̺ͅƝ̴ȳ̳ TH̘Ë͖́̉ ͠P̯͍̭O̚​N̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘ ̶̧̨̱̹̭̯ͧ̾ͬC̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔̀ͅ.

HTM

Project: https://github.com/developit/htm

Tagline: “Hyperscript Tagged Markup: JSX alternative using standard tagged templates, with compiler support.”

Alternative tagline: “htm is JSX-like syntax in plain JavaScript - no transpiler necessary.”

Sample code:

html`
  <div class="app">
    <${Header} name="ToDo's (${page})" />
    <ul>
      ${todos.map(todo => html`
        <li>${todo}</li>
      `)}
    </ul>
    <button onClick=${() => this.addTodo()}>Add Todo</button>
    <${Footer}>footer content here<//>
  </div>
`;

JSX-like syntax in plain Javascript is somewhat of a lie. That’s HTML(-like) syntax inside plain strings that are processed by plain Javascript at run time. So I guess it still makes this plain Javascript I guess 🤷‍♂️?

When I first heard of HTM, it looked something like this. Of course, it was doing exactly the same thing as lit-html: regular expressions, string blobs, and innerHtml before it got React/Preact integrations.

TO͇̹̺ͅƝ̴ȳ̳ TH̘Ë͖́̉ ͠P̯͍̭O̚​N̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘ ̶̧̨̱̹̭̯ͧ̾ͬC̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔̀ͅ.

Thankfully, the current version is smarter and smaller. It creates what is essentially an AST of the parsed structure that’s then passed on to the actual rendering function. However it’s still the same thing: parsing a bunch of opaque strings at run time. Opaque because neither the JS VM nor the browser know what’s in those strings.

And I mean… Why parse strings and build (potentially huge) ASTs at runtime when you can do actual function calls which, you know, can be optimised by the VM etc.? But I digress.

Styled Components

Project: https://github.com/styled-components/styled-components, https://www.styled-components.com

Tagline: “Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅”

Sample code:

const Button = styled.a`
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;

  ${props => props.primary && css`
    background: white;
    color: palevioletred;
  `}
`

The codebase for Styled Compomnents is huge.

It maintains its own list of tags (new tags and web compoinents are out of question?), it will generate and inject styles on render by going to great lengths to figure out what the hell we got passed, there are some regexps here and there.

Well, you got the gist. String blobs are being painstakingly parsed, and then reassembled.

Others

There are other projects like sql-tag or node-sql-template-strings. There’s common-tags.

They all do the same thing: the parse the strings at runtime. In many cases they concatenate some strings or produce some objects. They return some result or just directly dump it into the DOM.

Why is this bad again?

Because this isn’t code. This is literally taking a bunch of opaque string blobs, parsing them at runtime, and producing some result. All of programming has been busy moving away from coding in strings and parsing stuff at runtime. For the past few years Javascript has been happily re-introducing the worst programming practices. And devs get away with it, too, just because modern Javascript VMs and browser DOM are optimised way more than they have any right to.

Are they DSLs or embedded DSLs? They are probably weak embedded DSLs, but I’ll let people more knowledgeable than I decide.

They also lead to some horrible developer experiences. You cannot place a breakpoint on a string. You can place a breakpoint on the interpolated expressions inside one, or on the actual tagged literal function call, but good luck figuring out if you made a type somewhere.

Since these are just arbitrary strings, no common tools will be able to lint them, analyse them, optimise them unless you write a very specific tool for this particular very specific string structure. And yes, that includes JS VMs.

As you’ve seen above, people are in all seriousness talking about re-implementing optimisations that compilers already do for actual code: memoisation, inlining, optimising common paths, code elimination. Pure madness.

You wanted macros? Here, have run-time string concatenation and regexp parsing, and stringly-typed everything.

Originally published as a gist

There's nothing great or particularly amazing about Angular and its build processes.

Everything Angular does is fighting against its own architectural decisions. On a high level it's like this:

So, nothing really changed (only the build chain is becoming increasingly complex and impossible to reason about), and yet "OMG Angular is so great: Google makes it possible to use it with Bazel and Closurescript instead of the circus that is Webpack and UglifyJS" 😂

Fanboys are fanboys.

Disclaimer: I talk a lot about React here, but you can substitute your favorite library: Inferno, Preact, Vue, snabbdom, virtual-dom (or non-js libraries and frameworks like Elm, Om, etc.). Similarly, replace Polymer with Vaadin, or X-Tag, or…

Also, read Rob Dodson’s excellent response to this article: https://robdodson.me/regarding-the-broken-promise-of-web-components/

Brief, incomplete, and mostly incorrect history of Web Components

Ancient times

By 2011 Internet had grown. It had Facebooks and Gmails, and Twitters, and Asanas, and Google Docs, and countless other online things that could no longer be called sites, or Single Page Applications. They were, for all intents and puposes, applications. As simple as that.

And woe was to the devs who were developing them.

State of the art for Web GUIs at the time was probably a templating language glued together by some serverside logic and/or a client-side library. Backbone if you were lucky. jQuery UI or Sencha/ExtJs if you were enterprise enough.

This was cumbersome. This was limiting. You could not prototype easily and quickly. You could not easily escape the limitations of UI libraries. etc. etc. etc.

And you were limited to the same set of HTML elements as ever: divs, ps, formss…

In 2011 Alex Russel proposed a vision of the future (emphasis mine):

I think we’re stuck today in a little bit of a rut of extensibility. We wind up leaning on JavaScript to get things, because it is the Turing complete language in our environment. It is the only thing that can give us an answer when CSS and HTML fail us. So we wind up piling ourselves into the JavaScript boat. We keep piling into the JavaScript boat.

Bruce yesterday brought up the great example of an empty body tag, and sort of this pathological case of piling yourself into the JavaScript boat, where you wind up then having to go recreate all of the stuff that the browser was going to do more or less for you if you’d sent markup down the wire in order to get back to the same value that was going to be provided to you if you’d done it in markup. But you did it for a good reason. Gmail has an empty body tag, not because it’s stupid. Gmail does that because that’s how you can actually deliver the functionality of Gmail in a way that’s both meaningful and reliable and maintainable. You wind up putting all of your bets, all of your eggs, into the JavaScript basket.

It takes browsers time to implement stuff. We have to get it out to users, now users have to start using it, and then we have to look at our deployed population and go, “OK, now I can use this feature, I can target this feature.”

So as developers, this is the sort of things we thrive on. The faster that this crank turns, the more chances we get to see new features enter the market that we can start to target. “OK, well, this is good.”

So we wind up with this unspoken tension between deep pragmatism and the Platonic ideal of where we would like to be. But we don’t have a really good model for thinking about it.

The more of this behavior [behavior agreed-upon, known to devs, and implemented in the browser] that we take into ourselves, the more we do in JavaScript, the more we get away from the idea of shared ambiguity, which is what makes the world work.

We want to feed this process of progress. I think we get stuck in a place where we consider HTML5, we’re done.

And then he goes on to introduce and demo Web Components, which at the time were three different things: Scoped CSS, Shadow DOM and Web Components. (I also highly recommend his talk in general)

But then W3C happened. In true w3c fashion it went ahead and spent another 5 years defining the Platonic ideal and never feeding the progress as a result.

Cue in Facebook

Facebook application is complex. It might not look like it, but it is. Those little boxes everywhere on the page have surprisingly complex layouts which have to be repeated, and/or customized, and/or adjusted in various contexts. A developer would naturally want to do the following: take this box element, and put it here, and apply these random styles to it without disturbing anything on the page.

And it has to be reasonably fast. Because, well, DOM updates are notoriously slow, and there are countless articles detailing how you absolutely must reduce the number of times you access the DOM.

It’s so bad that innerHTML, a sign of horrible smelly code, is on par with or faster than DOM manipulation.

So, what did Facebook do? Oh, simple, they basically wrote their own implementation of Web Components entirely in Javascript. With an XML-based DSL to boot. They called it React and unleashed it unto the world in 2013.

React provides you with following:

No wonder React took the world by storm. Those who weren’t writing it were surely talking about it. It spawned several competitiors that are aiming for the same feature set (Inferno, Preact) or various subsets, most notably Virtual DOM (Snabbdom, virtual-dom etc.).

2017

In 2017 React fulfills all the promises of Web Components: it lets you write performant reusable self-contained components. It can run on almost any Javascript-enabled browser (React doesn’t support IE < 9).

As the ecosystem blossomed, it went far beyond the scope of Web Components. If I’m not mistaken, CSS Modules proposal appeared because it was first implemented in, and for, React.

In 2017 Web Components are in development despite already spawning two versions each of two of underlying standards.

At the time of this writing the situation for Web Components looks like this:

So what’s this broken promise I hear about?

Well, the main failure is obvious: they are nowhere to be seen. The promise of “feeding the process of progress” is unfulfilled. By their 6th year they spawned a total of 6 standards. Two of them are already deprecated. Only one major browser is commited to supporting them (sorry, Opera, you’re no longer a major browser, and you run on top of Chrome these days).

The other broken promise is the one bandied about in the Internets these days: interoperable custom components without vendor lock-ins.

And this is the one that got me writing this overly long piece of thinking out loud.

Because there’s Polymer.

Polymer is Google’s attempt at creating a Web Components-compliant implementation:

Unlock the Power of Web Components. Polymer is a JavaScript library that helps you create custom reusable HTML elements, and use them to build performant, maintainable apps.

Polymer shows the main problem with Web Components: they are DOM.

The DOM

Consider the following code in React:

<MyComponent style={{border: '1px solid gray'}}>
  {
     ['Hello', 'world'].map((text) => <p>{text}</p>)
  }
</MyComponent>

This is a custom component. Its style is defined by a JavaScript object. Its children are defined by maping over an array of values and producing another component. In this case it’s a <p>, but it could be anything. This component’s children is the current array value.

This XML-like DSL is directly translated into JavaScript:

React.createElement(
  MyComponent,
  { style: { border: '1px solid gray' } },
  ['Hello', 'world'].map(text => React.createElement(
    'p',
    null,
    text
  ))
);

A similar feat in WebComponents would be … well…

If you go for HTML as a counterexample for React’s DSL, it’s impossible:

<my-component style="only strings are allowed in attributes">
  ... nothing here ... 
  only other components or text allowed here
</my-component>

What about JS APIs? Remember I told you Web Components is DOM?

const MyComponent = document.createElement('my-component')
MyComponent.style.border = '1px solid gray'

['Hello', 'world'].forEach(('text') => {
	const p = document.createElement('p')
	p.textContent(text)
	
	MyComponent.appendChild(p)
})

This gets progressively worse as your components grow in complexity. Imagine adding a span around the text in p?

React? Easy-peasy. Just add it:

['Hello', 'world'].map((text) => {
   return <p><span>{text}</span></p>
})

Web Components? Well, it’s DOM:

['Hello', 'world'].forEach(('text') => {
	const p = document.createElement('p')
	const span = document.createElement('span')
	span.textContent(text)
	p.appendChild(span)
	
	MyComponent.appendChild(p)
})

Ad infinitum.

Let’s break compatibility

I assume the limitations described above were the immediate problem that Polymer faced. How do you work around this? Well, you invent your own not-really-JavaScript-but-kinda-Javascript kinda-templating-kinda-scripting kinda-language. That can only exist in strings.

Work your way through Polymer’s data system for a full overview. Below are just some examples.

Note: none of these [[]], {{}}, $= etc. are in the Web Component spec

<template>
  <div>[[name.first]] [[name.last]]</div>
</template>

<my-input value="{{name}}"></my-input>

static get properties() {
  return {
    active: {
      type: Boolean,
      observer: 'userListChanged(users.*, filter)'
    }
  }
}

<div>[[_formatName(first, last, title)]]</div>

<a href$="{{hostProperty}}">

etc. etc. etc.

And my favorite one:

Commas in literal strings: Any comma occurring in a string literal must be escaped using a backslash ().

 <dom-module id="x-custom">
   <template>
     <span>{{translate('Hello\, nice to meet you', first, last)}}</span>
   </template>
 </dom-module>

I mean, wat.

Seriously, y’all

In all seriousness though. Web Components ended up delivering hardly anything from their original promises (or have hardly answered any of the originally raised questions):

These are just a few warts I could come up wth off the top of my head. I haven’t seen them really truly discussed anywhere.

React team went as far as to say

We’re not going to use it at all at Facebook. We’re not going to build React on it because there’s a strong model difference – imperative in Web Components to declarative in React. Web Components doesn’t have an idiomatic way to define things like where events go. How do you pass data when everything is a string? We see it more as an interop layer that lets various frameworks talk to each other.

Nowadays React lets you have them as the leaf nodes in the component tree because React assumes any component name that starts with a lowercase to be a DOM element.

To quote Pete Hunt:

There’s a lot of stuff in Web Components spec that is nice. Being able to customize how select work for example (like dropdowns). So there’s a lot of great stuff in Web Components, but it’s not gonna be the way you structure your applications. and that’s what React tries to solve: how do you structure your application, manipulate the DOM.

Web Components are more of the same regular DOM API. What I like to think of it is: it standardized the worst practices.

There are very very few discussions about these issues except for comments on Twitter or on various articles. The consensus seems to be “Web Components is the glorious interoparable fast performant future”.

Is it?

Rob Dodson posted excellent response to this article: https://robdodson.me/regarding-the-broken-promise-of-web-components/. I highly recommend it.

Credits

Originally published as a gist

The question

tl;dr: Closure compiler makes little to no sense outside of Google's ecosystem.

Nolan Lawson conducted a very nice research on how various Javasctip tools bundle/compile Javascript. I highly recommend it: The cost of small modules.

This article has made several rounds on Twitter and many people have asked: Why aren't more people using Closure? There are many reasons for that.

Considering the dire state of Javascript tools today, Google's Closure compiler is yet another cryptic, badly configured, half-baked tool to throw into the ever-growing pile of twigs and sticks called Javascript infrastructure.

Documentation

There's basically none.

The Quickstart shows how to create a page that contains basically exactly one line of Javascript code. Instead of showing you how to do more, the next step is Advanced compilation which is basically Javascript one-liners interspersed with Python code to invoke the compiler service.

All these are unanswered.

Let's download the app then. There could me more info.

To run this you need a library you don't need

The README for the compiler has this nugget:

If you're using globs or many files, you may start to run into problems with managing dependencies between scripts. In this case, you should use the Closure Library. It contains functions for enforcing dependencies between scripts, and Closure Compiler will re-order the inputs automatically.

If you follow the link, this is the page you land on:

The Closure Library is a broad, well-tested, modular, and cross-browser JavaScript library. You can pull just what you need from a large set of reusable UI widgets and controls, and from lower-level utilities for DOM manipulation, server communication, animation, data structures, unit testing, rich-text editing, and more.

WAT?

I want to handle my dependencies, not have a UI library. Maybe they refer to ClosureBuilder? I have no idea.

Let's maybe run it?

I have some code in my app that consists of multiple modules, relies on some third-library code (node_modules) etc. The entry point is index.js

How do I run it so that it generates code I need to run my app in the browser?

However you run it, it only produces some minified code that:

At this point I'm ready to give up because, well, I already have my sweet set up that handles everything, transpiles, and compiles, and minifies, and bundles all code.

Switching to ADVANCED compilation modules may pollute your console output with mutiple warnings or errors that are also not helpful in the least.

In (small) conclusion

Google's Closure compiler makes no sense outside Google infrastructure. When you have set up everything the Google way and there are people to help you along as you run into problems, you're ok.

When you're alone (as most devs are), you will either spend an unknown number of hours going through error-messages, disassembling the setups of other projects (ClojureScript, Angular 2)...

Or just use the tools which you kinda sorta can setup without going insane

Why am I even writing about this?

Building JavaScript apps is overly complex right now

Among other things The State of JS 2016 asked developers if they disagreed (1), were neutral (3), or agreed (5) with the following statement: Building JavaScript apps is overly complex right now.

123455%11%27%29%30%

A full 59% of developers agree that Building JavaScript apps is overly complex right now. Only 16% disagree.

Javascript fatigue is real, no matter how hard some people try to shrug it off (see this for an example).

We’re told: move fast and break things. For once, just for once, I would like to stop breaking things and stick to something that works. Half of the issues here is something I’ve encountered in the past two weeks alone, when trying to create a project from scratch.

Developer Experience

Developer Experience is not a lost art. It’s an art that has never been discovered. It was briefly discussed a few years ago and then forgotten. These days if you ever hear it mentioned, it’s usually in the context of APIs.

However (emphasis mine):

As software consumes the world around us, good design in our tools is a growing competitive advantage

Our tools shape our work, and great tools change the shape of our industry.

We talk a lot about the importance of a strong engineering team, but not enough about the design of our tools and the impact it has on the quality of the products we build. We should be talking about DX more, and it’s not enough to talk about UX alone.

Steve Boak

Javascript tools are quite literally death by a thousand cuts. The whole experience of working with and building for Javascript is, at the very least, an excercise in frustration. The landscape is utterly hostile to developers. With experience you learn to navigate it, somewhat safely. Is it an experience you need, though?

Falsehoods programmers believe about Javascript tools

  1. Tools work when you run them
  2. Tools can be configured
  3. In JSON
  4. In Javascript
  5. Can be pointed to different config file
  6. Don’t use hidden/special files like .something.rc
  7. Tools fail if their config is incorrect
  8. Tools warn you about invalid values in configs
  9. Tools ignore invalid values in config
  10. Tools use defaults instead of invalid values in config
  11. Tools don’t ignore valid values in config
  12. Well, at least tools report non-config errors
  13. At least fatal errors?
  14. Tools propagate errors from their plugins or sub-tools
  15. At least fatal errors? I asked that one already, didn’t I?
  16. You can tell if an error originated in the tool, in a plugin or in a sub-tool
  17. At least, errors are clearly stated on screen/in logs
  18. At least, with reasonable and relevant information
  19. Tools can be invoked from command line
  20. Tools can be run on a list of files
  21. With glob patterns
  22. Minor versions of tools, or their plugins, or their sub-parts keep backwards compatibility
  23. Tools fail if none of their requirements are satisfied
  24. Tools fail if some of their requirements are not satisfied
  25. Errors or warnings if this happens
  26. There is only one way to do things
  27. There is more than one way to do things
  28. These many ways lead to the same result
  29. Your tool will be relevant 5 years from now
  30. Ok, a year from now

So, let’s talk tools.

npm

npm is the ubiquitous javascript tool. You may still run into bower occasionally, but that battle seems to have been lost.

npm is:

It probably does other tasks, but these are the most important ones. It does its job quite well, and I cannot recommend this post highly enough. Still, there are gotchas.

Run whatever I think you want, not what you want

This is relatively a minor WTF, but it’s there nonetheless:

If the specified configuration param resolves unambiguously to a known configuration parameter, then it is expanded to that configuration parameter. For example:

npm ls --par
# same as:
npm ls --parseable

In the example above --par is an invalid parameter. npm will not silently ignore it (which would be bad). npm will silently expand it to whatever parameter or combination of parameters it fuzzy matched.

npm has been notoriously bad at detecting actual errors. For example, until version 3.x (!) it would not fail if its configuration file was invalid.

Depend on whatever I you think you want, not what you want

Let’s consider npm install --save. This installs a dependency and adds it to the dependency list in your project’s package.json. And by saving I mean “take the list of dependencies, sort it alphabetically, and write it back to disk”.

This would not be a problem, save for this:

The npm client installs dependencies into the node_modules directory non-deterministically. This means that based on the order dependencies are installed, the structure of a node_modules directory could be different from one person to another. These differences can cause “works on my machine” bugs that take a long time to hunt down.

Yarn: A new package manager for JavaScript

Brilliant, isn’t it?

Remove all the things

Well, you know/remember this one: Rage-quit: Coder unpublished 17 lines of JavaScript and “broke the Internet”

Many were quick to attribute the problem to the horrible programmer culture of JavaScript, where people have forgotten how to program. It’s not the case. JavaScript community has whole-heartedly adopted Unix’s philosophy of “one package has to do one thing, and do it well”, but may have taken it to extremes.

The problem, or rather problems (plural) are all laid out here: https://github.com/npm/npm/issues/12045, so I’m not going to re-iterate.

npm and npm’s registry are essential to developers and to developer experience. The way some/many of arising issues are handled by npm’s organisation are clearly detrimental to developer experience.

Your package name doesn’t matter. Until it matters

First, this story.

So after a search for various of keywords I found out that the module name npmjs was still available in the registry. In the four years that the registry existed nobody took the effort in registering it. This module was and is a perfect fit for my module.

On the 22th I received an email from Isaac, the CEO of npm Inc (which recently raised more than 2M in funding for his company) and creator of npm with a question:

Can you please choose another name for this module? It’s extremely confusing. Thanks.

It didn’t even matter what how right or wrong I was for using npmjs as a module name Isaac had clearly already decided to destroy the module as he stated there wasn’t any negotiation and that it would be deleted no matter what.

Arnout Kazemier

Sounds bad, doesn’t it? Ok, what about this story then (emphasis mine)?

For a few minutes today the package “fs” was unpublished from the registry in response to a user report that it was spam. It has been restored.

More detail: the “fs” package is a non-functional package. It simply logs the word “I am fs” and exits. There is no reason it should be included in any modules. However, something like 1000 packages do mistakenly depend on “fs”, probably because they were trying to use a built-in node module called “fs”.

Incident Report for npm, Inc.
  1. Should you even allow publishing a module that has the same name as an intenal one?
  2. If npmjs is confusing, how is fs not confusing?
  3. If thousands of packages depend on it, how can you remove it considering the SNAFU you had just several months prior?

npm devs are clueless? (added 2016-12-27)

Event though npm is a rather nice package manager, its devs often behave like they haven’t got a clue as to what’s happening, or how development should happen.

Performance drop by 40% or more

At one point npm implemented a new progress bar which slowed down installation speeds by 40% and more. See related issue. Worse still, it was now enabled by default (disabled by default in the previous version).

You’ve got to love some comments from the npm dev team:

I’ve been aware of this as an issue for a while and the fix was literally 10 minutes or so of effort, but it hadn’t bubbled up in priority as I hadn’t realized how big an impact it was having.

Or, in a related issue (this appeared after the release):

Profiling would be grand… Put together a minimal benchmark to work against… Ideally I’d like this benchmark to be 2.x and 3.x compatible so we can directly compare different parts.

We break your stable branch, we’re not going to fix it

Look at this issue. Here’s the problem:

I leave this with no comments

Semantic versioning all the way! Not!

NPM swears by semantic versioning. The CLI will even warn you if your packages do not conform to the SemVer.

Meanwhile, npm project itself couldn’t care less about semantic versioning.

You may wish to check any of the changelogs for any release, including patch releases (for example, 4.0.2).

And this really leads to the following question:

Can we even trust our core tools?

This all leads to rather horrible questions:

Also, see the rationale behind Yarn, Facebook’s alternative package manager.

Build tools

The number of build tools (subsets and supersets of Makefiles and npm, or combination of all of the above) for Javascript is simply staggering.

Grunt, Gulp, Broccoli, Brunch, Jake, Mimosa, Webpack, Bower…

They are all broken in more ways than one. Let me just quote from my own experience (read the whole article for more than just this one snippet):

Let’s step back for a second, and consider:

  • Grunt does not transform code, it’s a “task runner” The task it runs is called browserify
  • Well, the problem with the browserify task8 is that the task runner cannot run it. It needs a plugin called grunt-browserify* to do that
  • Oh, and browserify has to run babel on the source code before it can do anything with it.
  • And the problem is that browserify cannot run babel directly. It needs babelify to work

All in all the whole toolchain to produce a Javascript file is grunt -> grunt-browserify -> browserify -> babelify -> babel. And someone in that chain decides that babel missing all of its specified plugins is not a reason to throw an error, stop and report.

Javascript: Fatigue vs. Stockholm syndrome

Are these problems fixed now? I don’t know. I no longer even care if they are fixed or not. I got myself new shiny better toys to play with. Or did I?

webpack

Webpack is almost the latest and greatest in a web-developer’s life (there’s a more latest now, called Rollup).

On the surface it does the following: take all the modules that your app has, figure out dependencies between them, bundle them up in a single file that you can serve to your website.

All webpack understands is ES5 and some common module structures: CommonJS, AMD etc. It can invoke so-called loaders whose job is to take a file and produce an ES5 output which Webpack will then take and bundle.

As a result, you can somewhat easily depend on anything: modules written in ES6, or in TypeScript, or in Coffeescript, or… You can even depend on CSS files or PNGs. If there’s a loader for that type of file, Webpack can bundle it.

Boilerplates

Also as a result, Webpack’s configuration is inane. And I don’t say it lightly.

Search github for “boilerplate”, and you will come away with easily hundreds of “this is configuration you need to get you started” because it is very nearly impossible to configure webpack.

Webpack is not alone to blame for this. It’s also the fractured tools, the fractured libraries etc.

loaders:[{
   test: /(\.css)/,
   loader: "css-loader?module&localIdentName=[path][name]--[local]--[hash:base64:5]"
}]

Yes, the above is configuration for css-loader. Yes, it is a string that contains URL-like structure where parameters you pass in are, well, URL query parameters. Because reasons.

There’s a reason for that, obviously. There always is.

First, you can pipe loaders for a file type:

loaders:[{
   test: /(\.css)/,
   loader: "style-loader!css-loader?importLoaders=1!autoprefixer-loader"
}]

This configuration pipes a .css file through style-loader then css-loader with options then autoprefixer-loader.

Second, you can do the same thing from within your code because why the fuck would you not want to do that?

require("style-loader!css-loader?importLoaders=1!autoprefixer-loader!...")

Did you know you could exclude things from a loader, if, well, there’s such an option?

loaders:[{
   test: /(\.css)/,
   loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss')
}]

This is a plugin. Acting as a loader. It has a pre-loader, style. And a loader. Which is a combination of two loaders, css and postcss. Oh, and we exclude autoprefixer (plugin? feature?) from the css loader.

"You were so preoccupied with whether you could, you didn’t stop to think if you should."

Yes, if there’s just one loader, you can provide its parameters as a regular JSON structure (feast your eyes on the query parameters section). However, this is yet another impendancy mismatch you have to deal with when trying to figure out what, where and how to configure all the moving parts.

You go an look for docs on a *-loader, and you run into anything: config as strings, config as objects, a mix of it. And if something goes wrong, you are left alone, there’s no way to know what failed.

But honsetly. How much time do you have to spend to come up with this: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss')?

Learn to love the stacktrace

Let’s pretend you are a C++ developer. You use a Makefile to invoke the gcc compiler on your source code. If there is an error in your source code, you will see the relevant error.

For some reason you will never see the stacktraces from either the make tool or from gcc

Not so in Javascript. Because internal stacktraces from the build tools are the bread and butter of everyday JS development.

Enjoy.

> webpack --config webpack.config.js --progress --colors -w -d

Hash: 6f816ab5f143490174a0
Version: webpack 1.13.2
Time: 3176ms
     Asset     Size  Chunks             Chunk Names
    app.js  1.11 MB       0  [emitted]  main
app.js.map  1.25 MB       0  [emitted]  main
   [0] multi main 28 bytes {0} [built]
    + 226 hidden modules

ERROR in ./js/app/fsm/payment-flow-fsm.ts
Module parse failed: /Users/dmitriid/Projects/project/node_modules/awesome-typescript-loader/dist/entry.js!/Users/dmitriid/Projects/project/js/app/fsm/payment-flow-fsm.ts Unexpected token (3:18)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token (3:18)
    at Parser.pp$4.raise (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/acorn/dist/acorn.js:2221:15)
    at Parser.pp.unexpected (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/acorn/dist/acorn.js:603:10)
    at Parser.pp$3.parseExprAtom (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/acorn/dist/acorn.js:1822:12)
    at Parser.pp$3.parseExprSubscripts (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/acorn/dist/acorn.js:1715:21)
    at Parser.pp$3.parseMaybeUnary (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/acorn/dist/acorn.js:1692:19)
	<...skip 20 or so lines...>
    at Parser.parse (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/acorn/dist/acorn.js:516:17)
    at Object.parse (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/acorn/dist/acorn.js:3098:39)
	<...skip another 20 or so lines...>
    at nextLoader (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:290:3)
    at /Users/dmitriid/Projects/project/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:259:5
    at Storage.finished (/Users/dmitriid/Projects/project/node_modules/webpack/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:38:16)
    at /Users/dmitriid/Projects/project/node_modules/webpack/node_modules/enhanced-resolve/node_modules/graceful-fs/graceful-fs.js:78:16
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:380:3)
 @ ./js/app/index.tsx 9:25-58

ERROR in [default] /Users/dmitriid/Projects/project/js/app/fsm/payment-flow-fsm.ts:3:15
Expression expected.

The relevant ticket for this is webpack/webpack#1245. Note no one even asks the most obvious question: “why in the seven hells would I need internal stacktraces if I’m not a webpack/plugin developer?” Well, not until yours truly came along.

Can you understand what actually failed?

So, I’m running this:

> webpack --config webpack.config.js --progress --colors "-w" "-d"

Hash: 578f6adad579fede3e98
Version: webpack 1.9.6
Time: 3224ms
     Asset     Size  Chunks             Chunk Names
    app.js  1.12 MB       0  [emitted]  main
app.js.map  1.27 MB       0  [emitted]  main
   [0] multi main 28 bytes {0} [built]
    + 227 hidden modules

ERROR in ./js/app/fsm/state-manager.ts
Module not found: Error: Cannot resolve module 'machina' in /Users/dmitriid/Projects/js/app/fsm
 @ ./js/app/fsm/state-manager.ts 2:14-32

Can you immediately tell me if it’s webpack or typescript failing?

Ok, how about this:

> webpack --config webpack.config.js --progress --colors "-w" "-d"

Hash: ab8d7ccc3d611479ca81
Version: webpack 1.9.6
Time: 4464ms
     Asset     Size  Chunks             Chunk Names
    app.js   2.4 MB       0  [emitted]  main
app.js.map  2.77 MB       0  [emitted]  main
   [0] multi main 28 bytes {0} [built]
    + 341 hidden modules

ERROR in [default] /Users/dmitriid/Projects/js/app/fsm/state-manager.ts:1:25
Cannot find module 'machina'.

As you can clearly see, the first one is a webpack error. The second one is TypeScript error. Relevant issue: webpack/webpack#2878 (there are probably others).

All your options are belong to us

Specifically, the watch option. Could be others. I don’t know and don’t care at this point.

So, if you provide watch: true in Webpack configuration, Webpack will:

Enter watch mode, which rebuilds on file change.

Webpack documetation

This is, unsurprisingly, not entirely correct. See, if you ever decide to create your own build script, and invoke webpack trough its node.js API, you will see that:

Except

Because, I guess, reasons. And, surprisingly, the “short” version with webpack(config, callback) works as expected. Who’d a thunk it.

Forget continuous builds (added 2016-12-27)

Just read through this issue. Tl;dr: if webpack fails, it exits with a status code of 0. Because reasons.

And yes, despite this being a majot bug in the main version currenlty used, it has not been fixed in the two years since it was reported. Because reasons.

Nothing works out of the box anymore

Install and run? Sane defaults? These things are becoming a rare beast in the Javascript world. It seems that nothing works out of the box anymore.

In JS world, sadly, going through hoops and withholding crucial information from the developer is now the accepted norm.

Babel

The only job that Babel does is compiling a next version of JavaScript to the current version of Javascript.

I mean this is what says on its site:

Babel is a JavaScript compiler.

Use next generation JavaScript, today.

Babel transforms your JavaScript

You put JavaScript in

[1,2,3].map(n => n + 1);

And get JavaScript out

[1,2,3].map(function(n) {
   return n + 1;
});
https://babeljs.io

THIS IS A LIE. A lie so blatant that the next line on the site says it’s a lie:

Start by installing the Babel CLI and a preset

npm install --save-dev babel-cli babel-preset-latest

Create a .babelrc file in your project (or use your package.json)

{
   "presets": ["latest"]
}
https://babeljs.io

Understand this: out of the box the javascript compiler does not do a single thing. You have to install a number of plugins/presets before it even does anything.

Moreover, if there are no presets and no plugins installed, babel will not even complain about it. It will just … do nothing.

Given this index.js file:

[1, 2, 3].map(n => n + 1);

Running freshly installed babel will not even warn you, and will do nothing:

> node_modules/.bin/babel index.js
[1, 2, 3].map(n => n + 1);

Only if you install a preset and specify it, you get back what you need.

Babel has the “latest” preset which is:

This is a special preset that will contain all yearly presets so user’s won’t need to specify each one individually.

The answer is yes in any world other than Javascript.

Typescript

I’ve decided to talk about Typescript, because why not. More often than not Javascript is only used as a target language. Multiple other languages exist that compile/transpile into Javascript while promising nicer features, syntax, tools and so on and so forth.

Typescript is a superset of Javascript developed by Microsoft. It introduces type checks and various niceties into the language.

It includes a nice fast compiler which removes the need for Babel, but, obviously, it introduces a whole host of other problems.

Loaders

Not a typescript issue per se, but still.

When invoking from Webpack, you will deal with either ts-loader or awesome-typescript-loader.

The former one is recommended in typescript docs. The latter one is used in 99% of Webpack boilerplates. Good luck figuring out how they are different, what features they support or don’t support etc.

I haven’t had much experience with ts-loader (yet?), but I’ve alredy run into the following with awesome-typescript-loader.

Who cares about your configs. Part I

Project from scratch. Forgot to create tsconfig.json. No errors whatsoever, obvously. Webpack fails because it cannot parse the non-processed .ts file.

Why did .ts compilation fail? Was it due to a missing tsconfig.json. Wouldn’t it be just so nice if the tools involved could report this?

Who cares about your configs. Part II

When trying to clean up configs I decided to move tsconfig.json to a config directory. Provided path to this file as tsconfig option as per README.

Provided the following invalid option to the compiler in the tsconfig:

{
  "compilerOptions": {
    "target": "absdefg",
  }
}

The config above was accepted, and silently ignored. Everything got compiled. Was the config file even picked up? Well, webpack didn’t fail, so probably it was (see Part I). Who ignored the error? TS compiler? awesome-config-loader? No one knows, and it is impossible to find out.

Third-party modules, do you speak it? (upd. 2016-11-16)

Sooner or later you will have to import modules written in or transpiled to Javascript. Unless you develop a library with no external dependencies (quite possible) or something that only depends on other libraries written in Typescript (highly unlikely).

So, you will find yourself typing something like this into your Typescript code:

import machina from 'machina';

Which will fail:

[default] ...app/src/fsm/state-manager.ts:1:25
Cannot find module 'machina'.

See, Typescript needs type definitions describing the stuff your import. And here’s a type definition that will work just fine:

declare module machina;

You will ask however, “Is that it?”. Yes, that is it.

Edit (Nov 16): This will finally be fixed in TypeScript 2.1.3

Because reasons. Go ahead and try to make sense of the ambient modules section in the docs.

Types, types everywhere

Libraries are developed in whatever language authors prefer. To provide proper static type checking Typescript needs more than the stub module definitions. It needs actual type definitions for libraries.

Thanks to countless contributors to DefinitelyTyped there are quite a few definitions Typescript can use.

Well,…for some definition of “can”.

> npm install @types/superagent

[default] /Users/dmitriid/Projects/keyflow/keyflow-website/app/node_modules/@types/superagent/index.d.ts:83:30
Cannot find name 'Promise'.

See, despite the fact that this is not a single isolated problem, there are no solutions to this.

Well, except one: maybe try a newer version of npm, namely npm 3.x.

I personally have a problem with this. node.js has this thing called Node LTS, Long Term Support. And at the time of this writing it was:

> node -v
v4.6.0
> npm -v
2.15.9

I know, I know. I probably shouldn’t run cutting edge stuff on non-cutting-edge platforms, yada yada.

The problem is there, the problem exists. And, obviously, it exists for some modules, and for others (@types/react works, @types/superagent doesn’t, ad nauseam). Because reasons.

Wrapping up

I’m not sure this warrants a conclusion. I’ve stopped detailing my experience as I was approaching the 4000 word mark. However, there are so many more things that break, run amok, break in unpredictable ways, etc. etc. etc.

I’ll leave you with these quotes:

…never have I worked in an ecosystem where the knowledge attained while becoming a master of the craft goes out of date so rapidly, or where solutions are quite so brittle.

The JS world’s obsession with small tools mean that they combine in endless permutations, causing endless issues to debug.

When the tower of abstractions falls down in a steaming pile and you need to figure out what’s gone wrong and fix it, you then end up sinking hours and hours into it (all the more because you don’t really understand what’s going on, because you didn’t set it up from scratch).

Or you waste a month figuring out how to plug all the tools together. If I have a complex project I know full well I’m going to want code coverage, a proper module system, minification, etc. etc. The initial time investment to investigate the options here and get it all working is faintly ridiculous compared to ecosystems like Java or .NET (or even C++, for that matter).

I’m not even going to talk about the cavalier attitude various popular parts of the ecosystem (e.g. react-router) have towards API stability.

It’s deeply irksome, at best.

Alastair Maw

…the JavaScript community suffers from a very serious case of NIH syndrome, compounded by a neglect for long term sustainability of software projects.

Don’t get me wrong, every single language in the 20 or so years of web development has gone through the framework phase, where people would experiment with solutions for every one of those problems.

The difference is that every one of those languages very quickly converged into good solutions and then made those good solutions into effective tools to get things done.

The JavaScript community, otoh, doesn’t seem to get to the converging part…

Daniel Ruoso

It’s been said that “Javascript fatigue” appears because developers are lazy.

It’s been said that “Javascript fatigue” is because developers don’t want to learn anything new.

These arguments are null and void…

  • there’s nothing lazy in trying to make your build tool work
  • there are exactly zero useful things to learn from that experience

The time I spent trying to figure out the exact motions of all the moving parts I could spend on learning something genuinely new.

Instead, I now have a build toolchain that I have exactly zero confidence in (because it will break unexpectedly at the very next update of any of the fourteen hundred moving parts in it).

Yours truly

Originally posted on Medium

Programmers are the worst. They will vehemently defend the tool of their choice even though it’s the worst tool in the universe. See any vs in the programming community. Tabs vs. spaces. Emacs vs. vim. C++ vs. PHP. You name it.

tl;dr: Javascript fatigue is real. If you deny it, you have a case of Stockholm syndrome. The problem isn’t new, see these two excelent blog posts: http://blog.keithcirkel.co.uk/why-we-should-stop-using-grunt/ and http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/ for a calmer discussion.

A little true story

All joking aside, I think that Javascript programmers are even worse than the worst. Here’s a little true story that happened to me three weeks ago.

We have a project which started way before Webpack was in any useable shape or form. So, it uses Grunt. It’s all been fine, and Grunt has been chugging along quite happily (chugging, because, well, you need to concat all/some/some magic number of files before it can figure out what to do with them. Yes, concat. Sigh). Until we imported a small three-file component which was written in — wait for it — ES6.

ES6 is the next version of Javascript (erm, ECMAScript) which is supported in exactly zero browsers, and exactly zero versions of any of the Javascript virtual machines. Through the magic of transpilers it can be converted to a supported version of Javascript. Therefore half of the internet publishes their code in ES6 now.

Oh my. I know what we need! We need Babel! The best tool to convert pesky ES6 into shiny ESwhatever-the-version (I’m told it’s 5).

Install Babel. Run.

>> ParseError: ‘import’ and ‘export’ may appear only with ‘sourceType: module’
Warning: Error running grunt-browserify. Use — force to continue.

Ok. Bear with me. Babel, whose job 99% of the time consists of transforming ES6 code into ES5 code no longer does this out of the box. I have no idea if it does anything out of the box anymore.

But it comes with nice presets! One of them does the job! It’s even called, erm, es-2015. Whatever. Specify it in options, run grunt be happy.

>> ParseError: ‘import’ and ‘export’ may appear only with ‘sourceType: module’
Warning: Error running grunt-browserify. Use — force to continue.

Ok. Bear with me. A preset is an umbrella name that specifies a list of plugins Babel will apply to code. If these plugins are not present, Babel will fail silently.

Oh, it doesn’t fail in your particular setup? Oh, how so very nice to be you. The problem is: there is exactly zero info on which of the moving parts of the entire system silently swallows the error.

Let’s step back for a second, and consider:

All in all the whole toolchain to produce a Javascript file is grunt -> grunt-browserify -> browserify -> babelify -> babel. And someone in that chain decides that babel missing all of its specified plugins is not a reason to throw an error, stop and report.

Unwind. Relax. Breathe. Solve differential equations in your head. Install whatever’s needed for babel. Run grunt.

>> ParseError: ‘import’ and ‘export’ may appear only with ‘sourceType: module’
Warning: Error running grunt-browserify. Use — force to continue.

Oh, Jesus Christ on a pony! What now? Ok. I’m a smart developer. I can figure this out. I mean, if I cannot debug my own toolchain, what good am I?

So, grunt has a -d option which means debug. Awesome.

Ok. Bear with me. The debug option passed to grunt does not propagate through the mess of twig and sticks called a toolchain. Grunt does not pass the debug option to grunt-browserify does not pass the debug option to browserify does not pass the debug option to babelify does not pass the debug option to babel.

You have to provide separate debug options to every piece of the toolschain and pray to god that this piece provides such an option and does not ignore it.

Let’s add debug: true to babelify.

>> ParseError: ‘import’ and ‘export’ may appear only with ‘sourceType: module’
Warning: Error running grunt-browserify. Use — force to continue.

Exactly. Was the debug: true option ignored? Or is this all the debug info I can get? I have no idea.

Ok. Bear with me. Grunt has a specific list of files and components it needs to process. I can only assume that the broken ladder of crap called the toolchain gets this list from Grunt with instructions: “These are the files. Process them.”

Despite all that, Babel by default does not process files from node_modules. Even when invoked from grunt-whatever-theplugin-is-i-dont-care will not process them, and will silently skip them. You have to explicitly provide a separate global: true option to all places in grunt->grunt-broswerify->babelify config where you think that code from node_modules may be imported/invoked/whatever.

No, it’s Stockholm syndrome

I’ve been told that this article is a valid argument against “Javascript fatigue”.

It’s not. It’s Stockholm syndrome.

Nothing can excuse the terrible horrible mess that the state of Javascript development is in right now. Step back, and look at your tools. Really look at them. There is a reason we have a million “webpack starter packs”. Because nothing works unless you invoke a number of semi-arcane incantations with increasingly inane combinations and versions of options.

loaders:[{
   test: /(\.css)/,
   loader: "css-loader?module&localIdentName=[path][name] — -[local] — -[hash:base64:5]"
}]

Really?!

I will not even go into how half of these tools don’t support recursing directories or globs. Or how another half of them doesn’t support monitoring the file system and recompiling stuff on the fly (what? recompiling on the fly with dependency tracking wat?).

Why are you supporting this?

I’m not lazy. I don’t not want to learn

It’s been said that “Javascript fatigue” appears because developers are lazy.

It’s been said that “Javascript fatigue” is because developers don’t want to learn anything new.

These arguments are null and void. If you read the first part of the story, you’ve seen that:

The time I spent trying to figure out the exact motions of all the moving parts I could spend on learning something genuinely new.

Instead, I now have a build toolchain that I have exactly zero confidence in (because it will break unexpectedly at the very next update of any of the fourteen hundred moving parts in it).

And yes, I will be removing some of those moving parts. It doesn’t mean that I will enjoy it or learn anything remotely useful from it.

(imgur style): send me your **-starter-packs :)

Изначально было опубликовано на Медиуме

Полный текст того, с чем я спорю, тут: http://plan9.bell-labs.com/wiki/plan9/Mouse_vs._Keyboard/index.html

Самая главная проблема как этого текста, так и текстов, на которые он ссылается, это то, что он полностью и безнадежно устарел. При том, что сам текст датируется 2011-м годом, он ссылается на тексты 1989 и 1991 годов, а сам борется только и исключительно с vim’ом.

С 1989-го года прошло уже 26 лет, а вместо vim’а есть и другие интсрументы (да-да, и вместо emacs’а, который там упоминается вскользь, тоже).

В целом, основной аргумент в пользу «надо часто пользоваться мышью» сводится к следующему:

ORLY?

Ниже по тексту используются Apple’овские комбинации клавиш. В Линуксе и Винде Cmd заменяется на Ctrl.

Чувак, ты противоречишь сам себе

It is true that it is slower to use the mouse for, say, deleting a tab from the beginning of every line than it is to use the keyboard and type “^xjxjxjxjxjxjxjxjxjxjxjxjxj” in vi. But at that point you’re basically programming the editor (with a manually unrolled for loop) more than actually editing.

Говорит нам человек, и тут же предлагает следующее:

When the mouse is properly accelerated, many of us find that it’s faster and easier to highlight the lines in question and then type and execute Edit s/^<tab>//g in acme or just type s/^<tab>//g in sam’s command window. This is such a common operation that acme provides two shell scripts so you can leave |unind and |ind in the tag of your window and click on them whenever you want.

Стоп. Чем исполнение команд в окне команд и shell-скрипты (!) отличаются от программирования редактора? Да ничем, абсолютно. Особенно позабавило «разместите кнопочки для вызова этих команд в окошечке, и кликайте на них».

Во-первых, что-то мне подсказывает, что в vim’е можно точно так же выделить линии и набрать s/^<tab>//g

Во-вторых, что-то мне подсказывает, что в vim’е можно точно так же привязать короткие команды к скриптам(хотя да, нельзя их будет разместить в окошке)

В-третьих, в какой-нибудь IDEA я могу выделить все строчки и нажать Tab для смещения вправо или Shift+Tab для смещения влево (комбинация клавиш, которая работала, емнип, еще в Delphi в начале 2000-х, и имеющаяся в большом количестве редакторов). Что в разы удобнее, чем регулярки, пусть даже в виде кнопочек на панели

В четвертых, в той же IDEA я могу нажать Cmd+R (replace) и ввести то же регулярное выражение. Ах, да. Даже не задумываясь о том, что мне надо тянуться за мышью.

В мире есть не только vi

but all I can think is "damnit, if I could just click where I want to go I’d be there by now."

Чувааак, в мире есть не только vi. Да, мышь — полезная штука для таких действий, но никто это и не отрицает. Ты придумал себе, что кто-то с этим спорит, и активно борешься с вымышленными оппонентами.

Наверное, все редакторы, кроме vi, имеют возможность ткнуть, куда угодно, скроллбары и возможность выделять текст мышкой. Да, потому что это удобно. Нет, это не значит, что за мышкой надо тянуться постоянно (например, чтобы переключиться в другое окно или чтобы запустить скрипт из кнопочки)

Если тебе нужны костыли, значит, что тебе костыли не нужны

It’s important to have a good mouse, of course. It needs three real buttons, not two button with an intelliwheel in the middle.

А можно и без этого обойтись, а дать людям возможность пользоваться твоим мега-редактором с минимальным использованием мыши.

Использование мыши в той же IDEA:

Зачем мне три кнопки, да еще на мыши, когда абсолютно все мне доступно с клавиатуры?

В мире есть и другие редакторы кроме emacs’а

When one makes a mistake in a search string, in emacs one uses ctl-S and ctl-R, it’s a pain to correct the mistake; the “Look” command in acme allows you to just edit the tag and rerun the search.

В IDEA я нажимаю Cmd+F, редактирую слово (если надо), нажимаю ввод и — магия! — происходит поиск. Да как это можно без мыши сделать-то?!

Вообще, в целом, человек явно как жил в 1989-м году, так там до сих пор и живет. Ему невдомек, что есть что-то, кроме vi и emacs’а. Ему невдомек, что большинство современных редакторов используют мышь там, где надо, и предлагают удобный доступ с клавиатуры для большинства операций.

Я думаю, что когда ему покажут, что в IDEA можно использовать Cmd+F или там в любом современном редакторе текста можно выделять, например, куски текста через Cmd/Alt+Shift+стрелки, его хватит апоплексический удар.

Тексты, на которые он ссылается, комментировтаь даже не стою, так как в первом же идет разговор о том, что много комбинаций не стандартизировано. 26 лет спустя много комбинаций стандартизировано.

Это я еще умолчу, что банальные требования по accessibility обязывают, чтобы вся функциональность системы и приложения была доступна через клавиатуру (если система или приложение хотят быть сертифицированы).

Originally published on Medium

I’ve received a fair amount of responses to my previous text. Time for a follow up.

What’s up with the rant?

The most valid complaint is: less rant and rage, more sense. But hey, what’s internet without rants? ;) However, the complaint is oh so true. Less rant in the follow up, I promise.

Oh. I also have much less gripe with WHATWG, than with W3C ☺ HTML5 and even DOM are kinda ok ☺

Breaking changes are hard

Another valid point: it’s very hard to introduce any breaking changes to the web and get people to adopt and to adapt. This fear is especially true for browser implementers, because implementing a breaking change may cast their browser away, to the sideroads. However…

So, it’s still risky, but not impossible to introduce major/backwards incompatible/breaking changes to the web… In a gentle way. Keep the old stuff working, actively promote and ecourage the new stuff. Yes, some of the old sites may never die. But don’t forget the 80/20 rule. It might be beneficial to the entire web eventually leave only the absolute minimum support for some old features (hey, remember the <blink> tag?).

It’s not impossible to imagine a backwards incompatible CSS4 with a separate renderer that:

So, render old stuff with the old renderer, render the new stuff with the new renderer.

I wouldn’t worry about the standard being picked up, provided it does away with the cruft, bloat, legacy and inconsistencies of the old standard. Even sites with huge user shares eventually drop support for older browsers (see, e.g. Facebook: 1, 2, 3) and pick up new features. Also, nowadays browsers are updated rather quickly.

Also, we are at a weird point in time when browser implementors and vendors more or less agree with each other. Can I Use is a testament to that. There’s actually hardly a specification without wide or upcoming support.

Why would browser implementors want to get rid of their current implementations?

Because they are programmers.

This is not a scientifically backed up argument, but still: no one wants to work on an old, complex (and getting increasingly complex) code. Especially if it’s millions of lines of code. Especially if it’s a system that gets burdened with more and more layers of rules on top of each other (hey, kids, how do you reconcile css3-align with css3-grid-layout in a css3-flexbox in a float in a …). There’s rules in rules on top of rules hampered or overriden by other rules and so on. And it has to be insanely fast. And it has to be correct, for some definition of correct, as there’s no reference implemetation, only tests (which are woefully incomplete and may target outdated versions of HTML: 1, 2).

BTW, the lack of tests is not a jab at their authors. The sheer amount and complexity of the specs make it impossible to create enough tests (css3-align in a css3-grid-layout in a… you get the point). I’m half expecting CSS to finally adopt C++’s approach and add “implementation-dependent” or “undefined” clauses ☺

Hey, this funny guy makes fun of my title

One problem I have with some/many/most of the specs that come out of W3C and WHATWG is that I don’t feel they are made by people who are doing any serious frontend web-development, or at least haven’t done it for a looooong time.

The main reason for thinking so is that it’s very hard to find evidence of any authors doing any of the (let’s call it) modern web-development. Yes, they hold high positions at various companies/groups/ universities/committees, they hack specs/work on web standards, they work on browser code. But what of actual frontend web-development?

I mean, have you ever developed a complex and/or beautiful website? There are quite a few of them around: Facebook, Gmail, Asana, Google Docs/iCloud, Medium, CSS Zen Garden, various Tumblr designs, Pinterest, Rdio — you name it.

Because if they’d ever develop such a site, we wouldn’t end up in a situation when a simple menu requires 4-level nesting of <div>’s to display a simple menu even on the web-site dedicated to promoting CSS3:

<div class="main">
  <div class="content_holder">
    <div class="menu_search">
      <div class="menu">
        <ul>...

(W3C own site manages to do it with only 3 nested divs. Medium needs 4, and each element is another div. Well, you get the picture)

As an aside: I was told that Facebook is a trivial site to implement in CSS. But have you actually looked at what a Facebook page is? There’s multiple layouts, panels, panels within panels, buttons and drop-down menus everywhere, floating content, fixed content, pop-ups, highlights, embedded content, tigers, and lions, and bears, oh my. It’s not trivial.

Another reason I don’t believe they are doing any serious web-development is the time it takes some features to appear (if ever).

Cases that stuck in my mind.

In an extended Twitter conversation I was told that most of the discussion is driven by the browser implementers. Maybe that’s the reason behind the weird specs, late or non-existent features and the continuing unsuitability of CSS for anything but the most basic layout. People who are good at implementing browser code might not necessarily be good frontend web-developers (or web-developers at all).

Join, review, speak up

It was suggested (and this is also a very valid point) that anyone who has anything to say on the matter, should join the mailing lists, speak up, and review the specs.

However, I must confess: I don’t believe in this approach. The problem with too many people having an input is that:

I would rather like to see a smaller, more focused group of people working to implement a lean and mean standard than a thousand people debating whether a particular fringe/weird case is relevant.

Questions, do you ask them?

Any and all specs by necessity contain only the simplest examples. A single floating div. Four divs in a grid. And so on. The real web is much more complex than that.

I’m not too familiar with W3C’s or WHATWG’s discussions, but I wonder if people ever ask questions beyond simple examples?

And so on. Replace Facebook with any website (or even Sencha’s examples), rinse, repeat. Until you get an actual pragmatic solution. Ditch the fringe cases. Ditch the theoretical “I can imagine when x could be useful”. Go for pragmatic.

Also, look at what people are doing to improve CSS (or HTML/DOM for that matter) (jQuery, SASS, LESS, Grid Style Sheets) and go and standardise those. These are the things that people want and need.

Originally published on Medium

Note: there’s also a followup.

tl;dr: W3C and WHATWG are a useless bloated bunch of people who don’t care in the least about making the web a better place. Both W3C and WHATWG should die a quick and horrible death, and the development of web standards should be given to a lean and mean group of people, all of whom are actual web developers.

For the sake of all that’s good and holy: why?

Web-developers have the worst ever Stockholm syndrome ever in the history of the world ever. Whatever inconherent inconsistent overlapping multi-million-page abomination of a spec spewn from either of the two committees we cheer them on and ask for more.

And this just goes on.

Why do we keep believing that these self-aggrandizing bloated useless monstrosities work to make the lives of developers easier? Or the web better? What evidence is there?

{ vertical-align: fuck off, any-align: fuck-off }

(Original tweet by Lewis King lost, here's just a quote from it)

We have landed a robot on a comet 317 million miles from Earth and yet we still can't vertically align things easily in CSS.

Yes, it’s true, folks. In the age of SOA applications, and facebooks, and twitters and mediums, there’s still no way to align anything against anything.

Good fucking grief.

Please, do visit these two links, read, and weep: %% units and “flow” attribute. Unlike W3C and WG, the author of these extensions uses them in commercial software that is actually used to build UIs. These extensions cover, oh, I don’t know, 80–90% of a web-developer’s needs?

So, here’s the story. %% units and the “flow” attribute were proposed to W3C. Can’t find the discussion now (it was 7 years ago, at the very least), but the proposal was shot down. Fast forward 7 years, and lo and behold: flexbox, grid-layout and multicol. Bloated, inconsistently named and overlapping each other. And yes fringe cases.

See, folks at W3C and WG act as if they were pure academics.

“Hey, guys, I have this purely theoretical problem which will look nice in a book somewhere. What do you think?”

“Awesome! Bring it on. No, bring two or three of those”

Just as an illustration, http://css-tricks.com/snippets/css/a-guide-to-flexbox/

.container { flex-direction: row | row-reverse | column | column-reverse; }

Can you name/find a single person on this Earth who would need *-reverse directions? Yes, there could be a few: writing books and tutorials that will include this utterly useless piece of garbage. However, since this is a theoretical fringe case, it no doubt was discussed at length and included at the incsistence of “prominent members” of the W3C community.

Damn them all to hell.

Instead of solving real-world problems they play in a nice academical theoretical sandbox, solving non-existing problems. Look at each and every steaming pile of horse manure that they produce: all this bloat, all these insane attributes and measurements stem from the fact that someone somewhere produced an insanely convoluted theoretial example of a non-existent problem and produced a solution to it.

Obviously, it’s not constrained just to alignments. It’s 2015 and it’s still easier to make sites based on exact pixel measurements than sites based on relative percentages. It is impossible for any sane person to create a responsive site without the use of CSS Frameworks (which are themselves bloated and limiting — out of necessity, not by choice). Whole articles on how to vertically align elements or create proper three-column layouts still exist. And the list just goes on and on and on and on…

Do you want to build a sand castle?

Yes. Sand castles.

There’s not a single reference implementation for any of the specs coming out of W3C and WG

Re-read that sentence, and let that sink in. All these specs are purely theoretical constructs that are unleashed on browser implementors and then on web developers.

Hey, you thought Acid tests where the reference implementation? No. Those, too, are theoretical constructs created on a theoretical basis. No wonder browser developers often cheat to make sure their browser passes an Acid test, and only the Acid test, the actual spec implementation be damned.

I’m not even sure the people who come up with the crap they call specs even do any serious web development. I mean, look at W3C’s and WG’s web sites. That’s exactly the type of site you can build using their specs.

I’ll leave this as an excersise to you: go through specs, find their authors, and what they do. Look at their websites, demos etc. You’ll see what I mean. I kid you not, there’s a guy whose job description is “spec hacker”. Jesus…

Is there a way out?

Of course.

Nuke W3C and WHATWG out of existence. As soon as possible. Leave a small team of people (10, maybe 15, tops) to implement a backwards incompatible lean and mean CSS 4:

Last step:

Dig W3C and WHATWG out of their graves, kill and bury them again.

Don’t forget to read the followup.