Evolution of the JS toolchain

from jsmin to vite

Hi, I am @debelbot

me remembering the good old days

We use a LOT of tools

  • đŸ“Ļ Package management
  • đŸ–Ĩī¸ Local development
  • âš—ī¸ Improving code quality
  • 🔨 Building & bundling
  • âš™ī¸ Optimization
  • đŸƒâ€â™‚ī¸ Running task & deployment
  • 🤖 AI agents

And God said "let there be tools!"

and perfect tools appeared and everything was perfect

And God said "let there be tools!"

and perfect tools appeared and everything was perfect

In reality,

the tools we take for granted today are the result of years of feverish evolution

1991 - 2000

Dawn of the web

Dino Jesus

(when the dinosaurs still roamed the Earth)

1991:  humble beginnings

There was no need for a "build step"

first web page

deployment happend mostly through ..FTP 😱

1995:  The birth of JavaScript

Brendan Eich created a language in 10 days

netscape, now with javascript

and we're still fixing his bugs today

Welcome the professionals

Established software developers came in with their familiar tools

the old guard with their tools

(when all you have is a hammer...)

1998:  Microsoft Script Debugger

The first browser wars leads to a wave of dedicated tooling

things are starting to move

2001 - 2009

Stone, bronze and iron

js pyramids

(when the JS pyramids where built)

2002:  The good parts

Doug Crockford writes his famous book and creates jslint and jsmin.

the good parts

JavaScript starts to be seen as a real language!

 A strong foundation

It is important to acknowledge just how influential "the good parts" and jslint were for the development of the language, the tooling and the web!

2006:  jQuery

still the most popular library in the world

2006:  Firebug

Our modern browser dev tools are not that different from the original the best frontend IDE

2009:  Chrome & v8

JavaScript gets a new, faster engine!
logo

2009:  node.js

Ryan Dahl publishes a revolutionary server side runtime for javascript


  const http = require('http');

  const server = http.createServer(function (req, res) {
    res.end('Hello, World!');
  });

  server.listen(8080);

demonstrating the power of the event loop and non-blocking IO

2009:  ES5

the first update to the JS spec in 10 years

all those sexy new features

2010 - 2018

Industrial revolution

modern dev meme

(the prolifiration of framework drives the tooling)

logo

2010:  npm

the first JS package manager

  • PRO: a vast repository of ready-to-use tools and libraries
  • CON: enabling side-chain attacks since before it was cool

enabling a vibrant and enthusiastic community

logo

2010:  Backbone.js

The first popular js framework

  • PRO: familiar and flexible
  • CON: stuck in the MVC past

  const Todo = Backbone.Model.extend({
    defaults: { title: '', completed: false }
  });

  const TodoView = Backbone.View.extend({
    render: function() {
      this.$el.html(' ' + this.model.get('title'));
      return this;
    }
  });
logo

2010:  Angular

Google releases its own framework

  • PRO: full featured with routing, forms and batteries included
  • CON: heavy and brittle

  angular.module('todoApp', [])
    .controller('TodoCtrl', function($scope) {
      $scope.todo = { title: 'Angular', completed: false };
      $scope.toggle = function() {
        $scope.todo.completed = !$scope.todo.completed;
      };
    });

creating a new class of developer: the framework ninja

logo

2010:  CoffeeScript

The first popular JS variant

  • PRO: forced the development of JS itself
  • CON: very opinionated, confusing syntax

  compose = (f, g) -> (x) -> f g x

  square = (x) -> x * x
  addSix = (x) -> x + 6

  addSixThenSquare = compose square, addSix

  console.log addSixThenSquare(9)

  console.log [0..4].map square
logo

2010:  jasmine

The first popular JS testing framework


  describe("A suite is just a function", function() {
    it("is the same with spec", function() {
      expect(myFunc()).toBe(true);
    })
  })

2010:  Source maps

mapping from transformed and minified code to the original, much easier to debug

leave source maps on in prod
logo

2011:  Browserify

The first node.js based bundler

  • PRO: provided browser shims for the builtin node modules
  • CON: simple concat, only works with CommonJS (require)

  browserify main.js -o bundle.js
logo

2012:  Grunt

The first purpose built js task runner

  • PRO: large plugin ecosystem
  • CON: verbose and rigid JSON config

  grunt.initConfig({
    concat: { /* concat config */ },
    uglify: { /* uglify config */ },
    my_src_files: ['src/*.js', 'vendor/*.js'],
  });
logo

2012:  webpack

still the most popular build tool

  • PRO: code splitting & lazy loading
  • CON: slow build times, hard to configure

  {
    entry: './src/index.tsx',
    output: { filename: 'bundle.js', path: './dist') },
    devtool: 'source-map',
    resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'] },
    module: {
      rules: [
        { test: /.tsx?$/, use: 'ts-loader' },
        { test: /.jsx?$/, use: 'babel-loader' }
      ]
    },
    optimization: { minimize: true }
  };
logo

2012:  TypeScript

the most helpful but annoying linter

  • PRO: you can use types in your javascript
  • CON: I have to use types in my javascript

  type LightSwitchConfig = { on: boolean; off: boolean; toggle: () => void };

  type LightSwitch = Omit<Pick<LightSwitchConfig, keyof LightSwitchConfig>, 'toggle'> & {
    state: Awaited<Promise<Extract<keyof Pick<LightSwitchConfig, 'on' | 'off'>, string>>>;
    flip: (...args: Parameters<LightSwitchConfig['toggle']>) =>
      ReturnType<typeof Promise.resolve<void>>;
  };
logo

2013:  react

starts the component revolution

  • PRO: uni-directional dataflow, JSX
  • CON: complex rendering flow infects every aspect of the page

  class TodoItem extends React.Component {
    state = { completed: false };
    
    toggleComplete = () => {
      this.setState({ completed: !this.state.completed });
    };
    
    render() {
      return (
        <div onClick={this.toggleComplete}>
          {this.props.todo.title}
        </div>
      );
    }
  }
logo

2013:  Gulp

A task runner with a better API

  • PRO: very flexible API
  • CON: more manual and more complex

  gulp.task('build', () => {
    return gulp.src('src/**/*.{ts,tsx,jsx}')
      .pipe(sourcemaps.init())
      .pipe(ts({ jsx: 'react' }))
      .pipe(babel({ presets: ['@babel/preset-react'] }))
      .pipe(concat('bundle.js'))
      .pipe(uglify())
      .pipe(sourcemaps.write('.'))
      .pipe(gulp.dest('dist'));
  });

the ordering of these pipes is very significant

logo

2013:  eslint

One linter to rule them all

(just admit you imported the airbnb config without even thinking...)

it's not the tools its how you use them
logo

2013:  electron

Now your desktop app can be slow and bloated too!


  const { app, BrowserWindow } = require('electron/main')

  app.whenReady().then(() => {
    const win = new BrowserWindow({ width: 800, height: 600 })

    win.loadFile('index.html')
  })
logo

2014:  vue

Evan You releases "the framework for the rest of us"

  • PRO: approachable and incremental
  • CON: bespoke template syntax

  <template>
    <div @click="completed = !completed">
      <input type="checkbox" v-model="completed" />
      <span>{{ todo.title }}</span>
    </div>
  </template>
logo

2014:  babel

With the rapid evolution of the language came the need for transpilation


  {
    "plugins": [
      "@babel/plugin-transform-react-jsx",
      "@babel/plugin-transform-typescript"
    ]
  }
logo

2014:  jest

Facebook open-sources their testing framework

  • PRO: easy mocking and snapshots, react-ready
  • CON: lots of dependencies, problematic ESM support

  describe('my beverage', () => {
    test('is beer', () => {
      expect(myBeverage.type).toBeInstanceOf(Beer);
    });

    test('is sour', () => {
      expect(myBeverage.sour).toBeTruthy();
    });
  });

2015:  ES6

JavaScript finally gets all the features it has been dreaming of

all those sexy new features

2015:  unpkg

cdn for the masses (of npm packages)

[some people thought they would never need a build tool again..]

logo

2015:  rollup

Rich Harris releases a bundler made for speed and extensibility

  • PRO: native ESM, tree shaking
  • CON: no code splitting, no assets handling

  {
    entry: 'src/index.js',
    dest: 'dist/bundle.js',
    format: 'umd',
    moduleName: 'MyLibrary',
    plugins: [
      resolve({ jsnext: true, browser: true }),
      commonjs(),
      babel({ presets: ['es2015-rollup'] }),
      uglify()
    ]
  }
logo

2015:  yarn

move aside npm there is a faster cowboy in town

  • PRO: lockfile, faster than npm (at the time)
  • CON: lock file conflicts, disk space usage
logo

2016:  next.js

React with batteries included!

  • PRO: full stack framework
  • CON: vendor lock-in

  export default async function TodosPage() {
    const todos = await fetchTodos();

    return (
      <div>
        {todos.map(todo => (<Todo {...todo} />))}
      </div>
    );
  }
logo

2016:  svelte

Rich Harris releases his compiler-based framework

  • PRO: no virtual DOM, fast!
  • CON: smaller ecosystem and community

  <script>
    let completed = false;
    let todo = { title: 'Learn Svelte' };
  </script>

  <div on:click={() => completed = !completed}>
    <input type="checkbox" bind:checked={completed} />
    <span>{todo.title}</span>
  </div>
logo

2016:  pnpm

an even better package manager

  • PRO: dependency deduplication, even faster than yarn
  • CON: compatiblity & symlinks issues

2016:  Language Servers

Microsoft releases the first ever LSP..

..for TypeScript

language + server = language server
logo

2017:  prettier

format code automatically - no more tabs vs spaces

logo

2017:  parcel

Some tools don't last, but they pave the way

  • PRO: zero configuration out-of-box
  • CON: harder to extend, smaller ecosystem

  {
    /* even this not needed in the majority of cases */
    "extends": "@parcel/config-default",
  }

2017:  Web Assembly

the web can now run serious languages

performant sandboxed cross-platform

2018:  Lighthouse

making your site fast is easy - just remove all the bloat

a blank page is a fast page

2019 - 2026

pre-post-Anthropocene

here to help you

(or the period soon to be referred to as "the good old days")

logo

2019:  nx

Put all your projects in one basket

logo

2020:  esbuild

a golang-based js/ts bundler focused on speed

logo

2020:  swc

a rust-based js/ts complier focused on speed

logo

2020:  vite

Evan You has a dream - a universal build tool

  • PRO: fast and extensible
  • CON: requires modern browsers

  defineConfig({
    plugins: [react()],
    build: {
      sourcemap: true,
      minify: 'terser',
      rollupOptions: {
        output: { entryFileNames: 'bundle.js' }
      }
    },
    esbuild: { jsx: 'automatic' }
  });
vite is just rollup with extra steps
logo

2020:  deno

Ryan Dahl strikes again!
FAST js runtime written in rust with builtin TS/JSX support

logo

2021:  bun

FAST js runtime written in zig with builtin TS/JSX support
(but with JavaScriptCore instead of v8)

logo

2022:  turbopack

Vercel develop a bundler 500x faster than webpack

turbopack is just swc with extra steps
logo

2022:  unjs

a collection of independent JS tools

a lego style tool-chain for people who hate tool-chains

logo

2022:  astro

a meta framework focused on SSG

  • PRO: flexible - supports most all rendering frameworks
  • CON: custom syntax, immature server/api support

  ---
    import {logo} from '../assets/logo.svg'
    
    const { data } = Astro.props;
  ---

  <Layout>
    <header><Image src={logo} />My project</header>
    {data && <Chart data={data} />}
  </Layout>
logo

2023:  biome

an even more opinionated linter and formatter

thanks gofmt...

logo

2023:  jsr

a package registry for the new age

2024:  runtimes everywhere

almost all major platforms have their own js runtimes:

  • cloudflair workerd
  • amazon LLRT

2025:  wasm v3

making the web an even more viable compiler target

logo

2025:  oxc

a unified high-performance toolchain for JavaScript

parser linter formatter transpiler minifier resolver

2026:  faster typescript compiler

ironically written in golang, not typescript

 everyone has a compiler now

almost all major frameworks have their own compiler

sveltesvelte astroastro reactreact vuevue svelte next  oxc  oxc  

Where is the tooling going next?

I don't know.. đŸ¤ˇâ€â™‚ī¸đŸ˜…

Lessons learned

  • đŸĻ‹ The tools will continue to evolve
  • âš™ī¸ Vendors are baking complex functionality into the tooling
  • đŸŒŠī¸ With the rise of WASM, tooling can be written in any language
  • 🏃 Things are moving too fast for pure open-source to keep up
  • 📚 Projects & Web Standards are trying to be aligned

The tools we take for granted today are the result of years of ongoing evolution

the web is still thriving against all odds

the web is still king

(walled gardens, cryto scams, ai slop, etc)

Thank you!