Engine & Tooling
The JavaScript you write is almost never executed verbatim. First the engine (V8 in Chrome and Node) takes it — parses it into an AST, compiles it to bytecode, interprets it, and recompiles hot paths on the fly with a JIT compiler into machine code. Around the engine sits the runtime (the browser, Node, Deno), which provides the host APIs — DOM, timers, file system, fetch — and, importantly, the event loop itself. And before it reaches the browser the source passes through a build pipeline: transpilation, module bundling, tree-shaking, minification, and polyfill injection.
Three boundaries are reliably tested. First, engine versus runtime: the event loop and fetch belong to the runtime, not the engine — which is why document throws a ReferenceError in Node. Second, transpilation versus polyfilling: the former rewrites syntax, the latter adds a missing API, and one does not replace the other. Third, static ESM versus dynamic CommonJS: tree-shaking is possible only over a statically known import graph. Each mechanism is broken down in the layers below.
Topic map
- The JavaScript engine — parsing, bytecode, JIT, hidden classes and the inline cache, and where the garbage collector lives.
- Runtimes — how the browser, Node, and Deno differ in host APIs, and who owns the event loop.
- Module systems — CommonJS versus ES modules, live bindings, and interop via dynamic
import(). - Transpilation — what
Babeldoes, and how transpiling syntax differs from polyfilling an API. - Bundling and tree-shaking — the bundler, minification, code-splitting, source maps, and why tree-shaking needs static ESM.
- Polyfills — implementing a missing API, how it differs from a shim, and feature detection at runtime.
Common traps
| Mistake | Consequence |
|---|---|
| Placing the event loop inside the engine | It belongs to the runtime; this muddles every explanation of async |
| Calling JS purely interpreted | Ignores the JIT — hot code is compiled to machine code |
| Conflating transpilation and polyfilling | Babel will not add Promise itself — you need core-js; syntax and API are different layers |
| Expecting tree-shaking from CommonJS | A dynamic require with a computed path defeats static analysis |
| Shipping the whole polyfill library | A bloated bundle instead of only the APIs the targets lack |
Confusing setImmediate with setTimeout(0) | Different loop phases; top-level order is not guaranteed |
| Thinking a source map changes behavior | It only aids debugging; the shipped code is unchanged |
Interview relevance
The topic is asked to separate those who "just write code" from those who understand how it runs and ships. A candidate who says "the event loop is the runtime's, not the engine's; the engine gives you the call stack and the heap" instantly looks stronger than one who memorized "JavaScript is single-threaded".
Typical checks:
- The engine's execution stages and why the JIT speeds up hot code.
- How the browser, Node, and Deno differ in APIs and what they share (the engine).
- The difference between CommonJS and ESM and why tree-shaking works only for ESM.
- That transpilation transforms syntax while a polyfill adds an API.
Common wrong answer: "Babel polyfills Promise and Map". Babel is a syntax transpiler; missing APIs are pulled in by core-js. Blurring these two roles is the single most common mistake in this topic.