Frontend development in Docker is pain in 2020. But it gets better

Frontend development in Docker is pain in 2020. But it gets better

Table of Contents

I've just started building a  dashboard for my new project, which is an opionated Node.js API gateway (still in its infancy), with Clickhouse for logging: https://github.com/restyler/api-gateway.

Here is what I'm telling you: in case you forgot, frontend world is full of bloat. Transpilers, bundlers, and compilers, paired with watchers, which recompile your project on save, and try to make hot reload work in browser, make the life of an average JS developer full of  pain and misery. Especially in Docker.

Here is a concrete list of Vue related projects, where I've encountered dev environment issues during recent 6 months (all using Macbook Pro, 15" and 16"):

Nuxt

https://nuxtjs.org/

Minimal hacking around starter app constantly made macbook fans screaming, and browsers constantly hot-reloading, with many comments on their github issue queue about the same problem.

Vuestic Dashboard

https://github.com/epicmaxco/vuestic-admin  

I liked the design and the level of detail of this Vue dashboard, and decided to adapt it for my project. In Docker, on Macbook Pro 16", it starts for 2+ minutes in dev mode, with com.docker.hyperkit showing 400% CPU. Well, it even could not build the prod version of files at all, with 4GB RAM dedicated to Docker. It managed to build prod assets with 6GB RAM + "delegated" volume Docker setup, which I applied according to VS Code docs: https://code.visualstudio.com/docs/remote/containers-advanced#_update-the-mount-consistency-to-delegated-for-macos

Saving any file in dev mode still took 10+ seconds to recompile.

Why?

The bloat of JS world is amplified with Docker development setup.

From what I understand, is that when you bind your host OS folder to Docker volume, and god forbid do some file save in your fancy JS project, bazillions of file events are generated with https://github.com/paulmillr/chokidar or similar library to do a recompile, and this avalanche of unoptimised shit keeps the hardware busy. This is not what happens on prod build though. There, it's just the compilers and bundlers which manage to make the macbook and its owner cry.

It may be manageable for a guy who works with single JS/TS project every day for months, and does not use Docker, and instead creates a mess of technologies on his host OS, but it may be very upsetting for a full stack guy with many projects who loves VS Code Containers, like me (I'll tell you about my VS code setup in the next post, stay tuned).

Yes, Docker has its issues on its own, but it definitely  looks like a boring technology to me, for recent 2-3 years, at least. This time I was firm that I wanted to use VS Code Containers and Docker for my development because it gives me so much value in terms of conveniency, flexibility, and bullet-proof reproducible environments.

The solution: esbuild

https://github.com/evanw/esbuild

Disclaimer: you don't need to "know" or "learn" esbuild. It is just the technology used under the hood of Vite, Vue 3 dev bundler.

esbuild is another JavaScript bundler and minifer. Well, this time it is really worth it.

Just look at these graphs:

How is it possible?

It's written in Go, a language that compiles to native code
Parsing, printing, and source map generation are all fully parallelized
Everything is done in very few passes without expensive data transformations

This looked too good to be true for an almost desperate developer like me, but it indeed turned out to be a solution. Vue 3 uses esbuild in their Vite bundler so I realized I need to urgently switch to Vue 3 and ESM for the sake of my mental health.

I've replaced vuestic with https://github.com/wobsoriano/v-dashboard which uses Vue 3 and Tailwind. To do that, I had to learn (again? new tech every day!):

  • Tailwind,
  • how ES modules work
  • Vue 3 Composition API with all its quirks
  • figure out where I can get ESM version of Axios and everything
  • start adapting Chart.js without https://vue-chartjs.org/ because it is not ready for Vue 3

but I was ready to do it after I saw how Vite managed to compile my new Dashboard.

Here is how Vite works

Vite uses two things – ES modules and esbuild – to be super fast. I told you about esbuild above, so...

ES modules

It is the "import" statements from our good old friend Typescript. Major news here, in case you missed it, is that you can now use them in browsers. Directly. Without Babel and such! Wohoo!

https://kentcdodds.com/blog/super-simple-start-to-es-modules-in-the-browser

This won't work for every visitor of your website, may be for another year, but it works fine in latest Chrome and Firefox, so it can be used for development right now.

So, Vite cuts corners in proper places and does not bundle JS files for dev builds.

I should mention that esbuild does not validate the correctness of Typescript during compilation, but your VS Code with lang server already does if for you, right?

Results

  • I use .vue single file components and Typescript in development, like before.
  • Dev start is instantaneous. Cpu load of Docker is zero. Hot reloads are instantaneous.
  • Production build with axios, chart.js, pretty heavy toast library, and all the neccessary things like simple state store management takes 20 seconds. What a drastic change compared to vuestic!

That's all. My day-to-day frontend development is bearable now. I recommend to try Vite in your new projects (and ES modules + esbuild if you are more into React and other frameworks) - it's not perfect, and still in beta, but developer experience is day&night.