JavaScript Build Tools and Module Formats

Hero image for JavaScript Build Tools and Module Formats. Image by Wenzy Wong.
Hero image for 'JavaScript Build Tools and Module Formats.' Image by Wenzy Wong.

For a long time, frontend JavaScript was mostly a collection of files added to the page with script tags.

That still works, and for small sites it may be all you need. But as soon as a project has shared utilities, repeated components, dependencies, and different pagelevel behaviours, the old approach starts to creak.

The difficult part in 2015 is not that there are no options. It is that there are several competing options, and they all come with their own vocabulary.


The Old Script‑Tag Model is Simple until Order Matters

Script tags are easy to understand. The browser downloads the files and runs them in order.

That simplicity breaks down when files depend on each other:

  • a plugin expects jQuery to exist
  • a component expects a shared utility
  • a page script expects both of those to have run
  • a later script accidentally overwrites a global name

This is where many projects end up with comments like "do not move this file". That is not a build system. It is a fragile loading order.

Globals are not automatically wrong, but they need discipline. A small namespace can be enough for a modest project. Once the dependency graph becomes difficult to reason about, a module format starts to earn its keep.


AMD Favours Browser Loading

Asynchronous Module Definition, usually seen through RequireJS, was designed with browser loading in mind.

The article on AMD in JavaScript covers the basic shape. Modules declare their dependencies, and a loader handles when those dependencies are available.

AMD can be a good fit when the browser is responsible for loading modules separately. The tradeoff is that the syntax can feel heavier than ordinary script files, and the project now depends on a module loader.

For teams moving from simple script tags, AMD can feel like a big jump. It solves real problems, but it changes how files are written.


CommonJS Favours Tooling

CommonJS is familiar from Node.js. Files use require() and module.exports.

The browser does not understand CommonJS natively, so a tool such as Browserify is needed to bundle the files for the browser. That extra build step is the cost. The benefit is a module style that is simple to read and works well with packages from npm.

The article on using CommonJS modules in JavaScript explains the pattern in more detail.

CommonJS is often attractive when the team already uses Node tooling, wants to share small utilities, or wants more structure than globals without moving to a heavier framework.


Build Tools are There to Make the Browser's Job Predictable

Build tools can do many things:

  • concatenate files
  • minify JavaScript
  • bundle modules
  • transpile newer syntax
  • copy assets
  • run tests
  • watch files during development

It is tempting to add a tool because other projects use it. Start with the problem instead.

If the problem is only that five scripts need to be joined together, a small task runner may be enough. If the problem is that files need proper dependencies, a bundler is more relevant. If the problem is future JavaScript syntax, transpilation is part of the discussion.


Keep the Build Understandable

A build process should reduce confusion, not become a new source of it.

Good signs:

  • there is one obvious command for development
  • there is one obvious command for production assets
  • source files have clear ownership
  • vendor code is separated from project code
  • errors point back to source files where possible
  • the output can be inspected in the browser

Bad signs:

  • nobody knows which task produces which file
  • generated files are edited by hand
  • source maps are absent during development
  • a simple change requires understanding the whole build chain

That distinction matters because many build tools run in Node even though their output runs in the browser. The build environment and the runtime environment are not the same thing.


Choose for the Project You Have

A small website with two interactive behaviours does not need the same build process as an application with shared modules, tests, and several developers.

The right choice depends on:

  • team familiarity
  • browser support
  • dependency size
  • project lifetime
  • deployment process
  • debugging needs

It is better to have a modest build that everyone understands than an impressive one people are afraid to touch.

That period is easier to understand with hindsight in JavaScript build tools before framework CLIs took over. The tooling was messy, but it was solving real problems around dependency order, shared code, and browser delivery.


Wrapping Up

JavaScript build tools and module formats are really about making dependencies explicit.

Globals and script tags are fine when the project is small and the loading order is obvious. AMD and CommonJS help when the codebase needs stronger boundaries. Build tools help when the browser output needs to be produced consistently from organised source files.

Pick the smallest approach that makes the project easier to work on, not the one that looks most fashionable.

Key Takeaways

  • Script tags are simple, but file order becomes fragile as projects grow.
  • AMD is browserloader friendly, while CommonJS works well with bundling tools.
  • Build tools should solve a concrete project problem.
  • Keep generated files separate from source files.
  • A clear, boring build is better than a clever one nobody can debug.

Postscript

This article is part of an archive restored from a previous version of my website on 27 May 2026. The original publication date is accurate. The article has since been restored and lightly edited for formatting, imagery, broken links, and current internal references.


Looking for technical direction?

I support teams that need senior judgement on React, Next.js, headless CMS architecture, performance, migrations, and technical SEO.