CommonJS is not a problem – the Javascript ecosystem is

Recently I came across this post saying that CommonJS is hurting the JavaScript world. And while I do agree that the CommonJS specification was not a good one, I also disagree a lot with the article. As someone who have strong opinions about the subject, I decided to write a post about it.

So, here’s the problem: supposing that you have a legacy system that’s years old, and that basically is modular, meaning that people write extensions, or libraries, to that. Like for example, NodeJS’ CommonJS. Now, here’s the problem: if that legacy system is flawed, and you need to change somehow, and your solution is “let’s do something that is better in any way than the older model, it’s faster, etc, but also completely incompatible with the old stuff” – meaning that we have to rewrite everything to be able to be used on this new format – then you’re doing it wrong.

The empire built over beach sand

Completely inspired on this post:, and my experiences with Pulsar.

The Node.JS Ecosystem, together with so many others, is broken. Maybe beyond repair.

Let’s review the foundations of good software: good code, automated tests, a server that checks if the software works (usually called CI Server), a server that publishes the software continuously as soon as everything is working (usually called a CD Server), and reproducibility – meaning, if something fails, it needs to always fail if we send the same parameters, and always fail in the same place in the same way; if it passes, it must always pass on the same condition.

Now, onto Pulsar

The impossibility to maintain Atom

Atom Editor was, and still is, an amazing piece of technology. It was the first practical example of web technologies running locally, applied to a really hard problem: text editors. It it was, and still is, darn good at handling code.

But it’s hard, close to impossible, to maintain as the way it is. I want you to take all my opinions with a grain of salt, because these represent my own ideas and feelings on the project – I’m not a full-time Atom developer, nor I intend to be one. I just closely followed its development cycle, helped find bugs and problems in the first editions, and I still am in love with the editor, even when it’s clearly dying.

And while I would love to modernize the editor, making some PRs and fixing some issues, it’s close to impossible to do it. I believe the problem lies on the fact that Atom was an editor, and then Electron was extracted from it. I made the same choice on Chlorine too: I first made the plug-in, then extracted REPL-Tooling from it. Even on a WAY SMALLER codebase (Chlorine), this was HARD: there are still internal, private data that is used inside Chlorine that is not on REPL-Tooling.

Atom is the same. The “setup project” for Atom (prepare Electron, parse cmdline args, etc) is INSANELY huge. There are insane cyclic dependencies (TextEditor depends on components, UI, etc, and these depends back on the editor), there are NPM modules that depend on the editor (so you have code living in Atom that is used on NPM packages, and these also access internal state instead of going thought the public API) and there are outdated web features. There’s also some insanity happening: using newer versions of Node.JS got me 404 trying to run npm install, and even using the node version that Atom says to use in the documentation (that’s also NOT the current LTS version of node, mind you) didn’t work reliably. The only way I was able to install all dependencies was by running yarn install FOUR TIMES, and that did the trick (I got a different error every try, but at least, it worked).

But the problem is not this one: there’s simply too much code that lives “outside” Atom.

The state of JS in 2021

So… I recently found out that I had no space left on my SSD. When I tried to debug what was consuming my space, my projects folder were the culprit. How? I mean, I take photos, store them in RAW format, so how source code can be consuming more than my photos?

Turns out that by running rm -Rf (find -name 'node_modules'), (FISH shell) I was able to free 20gb of space!

So… let’s see how bizarre is the Javascript ecosystem in 2021.

Strangely big libraries

Sometimes, when I have to generate projects, they ask me to install yo. Yo is just a CLI to run generators – it does not include any generator. Yo occupies 89mb of space in my disk. Installing the react-webpack (manually by running npm i generator-react-webpack, because otherwise yo will try to install globally) means that your node_modules now occupies 180mb.

Let’s thing a little bit about this number: Windows XP, minimalist install without any add-on, requires 1.5gb of space. So a SINGLE GENERATOR occupies 12% of a full operating system.

So, create-react-app is more gentle – it just installs under 5.3mb. Generating a react app creates a node_modules folder with… 242mb. One of the dependencies is global-modules, that is just a single file with an if to define how to call things. It’s also only used in a single file – react-dev-utils/printHostingInstructions.js – in the folllowing code:

ClojureScript vs clojure.core.async

I’m going to make a somewhat bold statement: core.async does not work with ClojureScript. And, in this post, I’m going to show some examples why this is true, at least for the current versions of core.async.

So let’s start by understanding a little bit about the runtime: Javascript is a single-threaded runtime that implicitly runs an event-loop. So, for example, when you ask to read a file, you can do it synchronously or asynchronously. If you decide to run in that asynchronously, it means that as soon as you issue the fs.readFile command, you need to register a callback and the control is returned to the “main thread”. It’ll keep running until it runs out of commands to execute, then the runtime will wait the result from the callback; when it returns, the function that you registered will be called with the file contents. When the function ends, the JS runtime will await to see if there’s any other pending call, and it’ll exit if there’s nothing else to do.

The same thing happens in browser environment, but in this case the callbacks are events from the DOM: like clicking on buttons or listening for changes in some elements. The same rules apply here: the runtime is single threaded and when something happens it will first execute everything that needs to be executed, then it will be called back with the event that happened.

So maybe we can change these callbacks with core.async channels right? But the answer is no, because core.asyncs go blocks will not run in different threads (because, again, the runtime is single-threaded). Instead, it creates a state machine and it’ll control of when each of these go blocks will be called, at what time, eventually replacing the event-loop that Javascript environment already have.

My fading frustration with ClojureScript

I’ve talked about at another post on how ClojureScript frustrates me, mostly because I was doing some Node.JS work and Figwheel simply wasn’t working correctly. Now, it’s time to revisit these points:

A little update: I talked a little with Thomas Heller, Shadow-CLJS creator, and he pointed me some issues with this article, so I’ll update it acordingly


Figwheel and Lein are not the best tools to work with ClojureScript. Since I discovered shadow-cljs, things are working way better than before: I can reload ClojureScript code from any target, and I’m even experimenting with Hubot (and it works really fine too). The only thing I’m missing is my profiles.clj file, but I can live with that (and I can always use Shadow with Lein if I need profiles.clj).

Also, I’m working on a new package for Atom (and in the future, for another editors too) called Chlorine. One of the ideas is to offer better ClojureScript support (we have Autocomplete now!), using Socket REPL for solutions (even self-hosted REPLs like Lumo and Plank) and even wrap UNREPL protocol in Clojure. So far, is still in the very beginning but things are looking promising!

The stack

Forget Figwheel at all: Shadow-CLJS is probably the best tooling for ClojureScript ever. It auto-reloads ClojureScript code for the browser, for node.js, for node modules, and it integrates with almost everything that you want. It controls release optimizations, have sensible defaults, and even have post-compile hooks (so you can hook Clojure code to do something after some compilation phases). Also, it integrates with node-modules (no more maven-wrappers for JS libraries!) and have some warnings when you use some kind of ClojureScript code that would break :advanced compilation. And, let’s not forget that you can control the refresh reload phase, it adds a userful :include-macros in ns form (that will include all macros from the namespace being required), and controls exports in a sane manner. But first let’s begin with the feature that I found most useful: :before-load-async.

There’s a little Haskell in your Javascript

This may seem a little strange, but althrough Javascript is a dynamic language, with very loose typing (automatic convertions, equals signs that only works on arrays/numbers/undefined/nil), lots of things that are “falsy” by default, with the new promise-based approach of Javascript, the language is borrowing some very interesting concepts from Haskell.

And yes, this is a great thing. And yes, this will probably change the way we program.

Let’s begin by talking about Javascript, and its new features. Old async-javascript code was probably like this:

some_io_function(function(result) {
  find_name_in_db(result.person_id, function(name) {

Now, it’s like this:

  .then((result) => find_name_in_db(result.person_id))

And, with new ES6 features:

async () => {
  var result = await some_io_function();
  var name = await find_name_in_db(result.person_id);

Now, what does this have to do with Haskell? Multiple things, but the most important: Functors!

Alguns meses com CoffeeScript

Recentemente, resolvi testar o editor Atom… Mas isso eu já falei em outro post.

O que eu vim falar agora é sobre CoffeeScript, e a forma como eu tenho programado recentemente envolvendo Javascript.

Estando no mundo Rails, é bem comum a gente acabar usando as ferramentas que o Rails nos disponibiliza. Embora seja uma boa idéia no começo, há uma tendência a ficarmos meio “engessados” numa única tecnologia. Então, resolvi começar um projeto meio ousado de fazer uma UI inteira em HTML + CoffeeScript, sem a intervenção do Rails, e por hora, nem sequer com backend. Talvez eu fale sobre isso num post futuro, mas especificamente agora quero falar de Coffee.

Eu nunca gostei de CoffeeScript, na verdade, por causa da idéia de “indentation-based”. Outra coisa do Coffee é que ele basicamente não faz milagres – tudo no fim das contas é Javascript, e é essa a parte difícil e chata de entender.


Experiências com o Atom

Para adicionar um pouco de fogo na velha “editor wars”, eu resolvi testar o SublimeText, Zed, e o Atom.

Antes, um disclaimer: eu sou um usuário VIM. Não um super usuário VIM – eu, por exemplo, uso as setas para navegar dentro de um arquivo (oh, o horror!), uso poucos plugins, enfim. Aí resolvi testar o SublimeText, e achei ele fantástico – rápido, estável, e funciona bem. Só tem um problema: 70 dólares.

Eu acho válido pagar por algo que você vai usar todos os dias. Mas 70 dólares é 1/3 de um Office. Já que eu tinha alternativas, resolvi testar o Atom. Antes disso, eu tinha feito um plugin para o Sublime, para rodar coisas pelo TMUX, e resolvi portar o mesmo aplicativo para o Atom, como um exemplo.

O Atom usa tecnologias web – HTML + CSS + JS + Node.JS para funcionar. Basicamente, plugins (e customizações do Atom) são escritos em Coffeescript ou Javascript, usando Node.JS, toda a interface do Atom, incluindo menus, abas, telas, são feitas usando HTML + CSS, você pode re-estilizar a tela toda usando LESS ou CSS, e os arquivos de config são em CSON ou JSON. O ponto negativo disso é que basicamente o Atom consome tanto de memória como o Chrome / Chromium, já que na verdade, ele basicamente É a mesma coisa – um browser rodando uma página. Há muitas vantagens na abordagem do Atom – a tela inteira do seu editor é customizável.

O veredicto final eu achei bom: eu acabei gostando do Atom. Ele é um pouco mais lento do que eu gostaria, e consome uns 300 – 400mb de memória na minha máquina (o que é bem ruim na verdade para pessoas que tem máquinas com pouca RAM) . Outra coisa que é perceptível é a facilidade de se fazer plugins (há um “scaffolding” de plugins no Atom) e quão fácil é integrar dependências externas, testes dos próprios plugins, etc. O ponto baixo sempre será o consumo de memória e de disco, que o Atom simplesmente precisa melhorar – e muito.

Sobre cada um dos detalhes: