Professor Sloth

Free web performance master class

Learn about web performance and how to make your site faster, delivered straight to your inbox.

Breaking Out of Webpack Based Build Chains

JavaScript build chains have gotten outrageously complicated. Let’s create one that isn’t. Request Metrics monitors how real users experience the performance of your production websites. We won’t get far without a javascript agent to pull performance data out of the browser!

The new agent is a Typescript based project that compiles to browser supported JavaScript. We like to start new projects with only the tools need to start. New tools and features are added as they become required, not when we think they look shiny.

Build TypeScript Without Webpack

The only package we absolutely need to compile Typescript is the compiler. We avoid the need to remember compiler commands by using npm scripts. Typescript start working in just a few steps:

1. Install Typescript Compiler From NPM

> npm install typescript --save-dev

2. Add a Build Script to package.json


{
  "name": "my-app",

  // ...snip - other package.json boilerplate...

  "scripts": {
    // Build typescript files
    "build": "tsc -p tsconfig.json",
  },
  "devDependencies": {
    "typescript": "3.7.5"
  }
}
package.json

3. Configure The Typescript Compiler to Output Simple JavaScript


{
  "compilerOptions": {
    // Simplest, browser runnable setup we could find:
    "module": "none",
    "target": "ES5",
    "outDir": "dist",

    // Enable source maps so browsers can show original TS in the debugger:
    "sourceMap": true,
    "inlineSources": true
  },
  "include": [
    "source/**/*"
  ]
}
tsconfig.json

4. Write Some TypeScript to Compile


class TestClass {
    constructor() {
        console.log("I HAVE BEEN CONSTRUCTED!");
    }
}

var test = new TestClass();
source/index.ts

5. Run Build Script

> npm run build

Automatically Rebuild When TypeScript Code Changes

Our beautiful Typescript is now compiling down to the sad state of affairs that is JavaScript with browser support. The above command must be run every time there code should be re-compiled. That’s a problem because I don’t care to continually run commands during development. Luckily, the Typescript compiler supports automatic recompiling out of the box!

1. Add a Watch Script to package.json


{
  "name": "my-app",

  // ...snip - other package.json boilerplate...

  "scripts": {
    // Build typescript files and rebuild on change
    "watch": "tsc -p tsconfig.json --watch"
  },
  "devDependencies": {
    "typescript": "3.7.5"
  }
}
package.json

2. Run Watch Script

> npm run watch

Run A Simple Express Server

Our Typescript is compiling like they’re no tomorrow. The whole point of this exercise is to run some JavaScript in the browser. It is helpful to actually run our agent in the browser. With a small smattering of express, we get it done:

1. Install Express From NPM

> npm install express --save-dev

2. Write a Basic Express Server


var path = require("path");
var express = require("express");

var server = express()
  .use("/dist/", express.static(path.resolve(__dirname, "../dist/")))
  .use(express.static(path.resolve(__dirname, "public")))
  .listen(3000, () => {
    console.log("demo site listening on http://localhost:3000");
  });
demo/server.js

3. Add a Demo Script to package.json


{
  "name": "my-app",

  // ...snip - other package.json boilerplate...

  "scripts": {
    // Build typescript files and rebuild on change
    "demo": "node ./demo/server.js"
  },
  "devDependencies": {
    "express": "4.17.1",
    "typescript": "3.7.5",
  }
}
package.json

4. Run Demo Script

> npm run demo

Do It All at Once: Run a Server And Watch For Changes With a Single Command

Unbelievably, we sometimes find a bug in our code and need to recompile. Currently, we need to jump back and forth between build’ing and demo’ing our Typescript agent. The npm-run-all package gets us out of the jam by letting us do both at once!

1. Install npm-run-all From NPM

> npm install npm-run-all --save-dev

2. Add a Start Script to package.json


{
  "name": "my-app",

  // ...snip - other package.json boilerplate...

  "scripts": {
    // Build typescript files and rebuild on change
    "demo": "node ./demo/server.js",
    "watch": "tsc -p tsconfig.json --watch",
    "start": "run-p demo watch"   // Run these scripts in parallel with npm-run-all
  },
  "devDependencies": {
    "express": "4.17.1",
    "npm-run-all": "4.1.5",
    "typescript": "3.7.5",
  }
}
package.json

3. Run Start Script

> npm start

We now have a simple, fully functional Typescript build and development pipeline with not a trace of Webpack to be found. As the agent grows we may run into a problem that Webpack solves nicely. Until then, we’ll do without.

Jordan Griffin
VP Engineering Request Metrics