Why Build Tools Exist
js1-1 introduced JavaScript with the simplest possible setup: a <script> tag, a browser, done. That model is still exactly correct for a small page — and it's exactly why almost no real application actually ships that way. This chapter explains precisely where it breaks down, and previews the three distinct jobs a modern build step exists to do instead.
The <script src> Model — And Why It Breaks Down
Recall the plain model: each <script> tag loads and runs one file, in the order the tags appear, sharing one global scope. It works — right up until a project needs more than a handful of files.
Three real problems, all of which get worse as a project grows: the loading order has to be tracked by hand, with nothing checking it for you; every file shares one global scope, so two libraries defining the same variable name silently collide; and there's no way for the browser itself to understand "this file needs that one" as an actual dependency graph — it just runs whatever's next in the list.
npm Packages Generally Aren't Written for Direct Browser Use
node1-2 covered CommonJS — require() and module.exports — as Node's own module system. Most published npm packages still use exactly that system. The problem: browsers cannot execute CommonJS natively at all. require() depends on Node's own file-system-based module resolution, something that simply doesn't exist inside a browser tab. This is the concrete, practical reason a build step isn't optional the moment a project pulls in npm packages — something has to translate CommonJS (or bundle ES modules) into a form a browser can actually run, because the browser has no built-in way to do it itself.
What a Build Step Actually Does
"Build tooling" is really three separate, distinct jobs, often performed together by one pipeline — but worth naming separately now, since later chapters treat each one as its own concern with its own dedicated tools:
Bundling
Combining many files into fewer files, automatically resolving the "this depends on that" graph the plain script-tag model left to manual ordering. Full treatment in Chapter 2.
Transpiling
Converting modern JavaScript (or TypeScript) syntax into a form older browsers understand. Full treatment in Chapter 4.
Minifying
Stripping whitespace, shortening variable names, and removing dead code to shrink what actually ships to production. Full treatment in Chapter 8.
A Concrete Before/After
Before — manual global-scope wiring, exactly the fragile ordering problem above:
After — an explicit, bundler-readable dependency:
import statement is exactly what lets a bundler build the dependency graph this chapter only described in words — Chapter 2 covers precisely how a bundler reads a project's imports and turns them into an ordered build.
node_modules or a production deployment enters the picture, "just add a script tag" stops being an option, regardless of which framework (or no framework at all) is in use.
Coding Challenges
Using this chapter's own three-script example, explain specifically what would break if the <script> tags for api.js and utils.js were swapped — and explain how a bundler's own dependency graph makes this class of bug impossible rather than just less likely.
📄 View solutionUsing this chapter's own explanation and node1-2's own CommonJS material, explain precisely why a typical npm package using require()/module.exports cannot be loaded directly via a <script src> tag in a browser.
📄 View solutionList the three distinct jobs (bundling, transpiling, minifying) this chapter names, and explain why it's worth thinking of them as separate concerns even though a single real-world tool often performs all three together.
📄 View solutionChapter 1 Quick Reference
- js1-1's own plain <script src> model works for small pages, but breaks on manual ordering, global-scope collisions, and having no real dependency graph
- Most npm packages use CommonJS (node1-2), which browsers cannot execute natively — a build step is required, not optional, once npm packages are involved
- Bundling — combining files via a dependency graph (Ch.2) · Transpiling — modern/TS syntax → older-browser-compatible JS (Ch.4) · Minifying — shrinking output for production (Ch.8)
import/exportgives a bundler an explicit, machine-readable dependency graph — no more manual script-tag ordering- Build tooling isn't framework-specific — any project using npm packages or shipping to production needs it
- Next chapter: Module Bundling Concepts — the dependency graph and entry-point model, CommonJS vs. ES Modules