[{"data":1,"prerenderedAt":2140},["ShallowReactive",2],{"page-\u002Fjs\u002F27-tooling-and-build-systems":3},{"id":4,"title":5,"body":6,"description":119,"extension":2134,"meta":2135,"navigation":35,"path":2136,"seo":2137,"stem":2138,"__hash__":2139},"content\u002Fjs\u002F27-tooling-and-build-systems.md","27 — Tooling & Build Systems",{"type":7,"value":8,"toc":2101},"minimark",[9,13,90,324,431,482,577,638,786,837,1004,1104,1253,1330,1381,1492,1548,1732,1818,1874,2032,2097],[10,11,5],"h1",{"id":12},"_27-tooling-build-systems",[14,15,17,22,56],"question-wrapper",{"language":16},"javascript",[18,19,21],"h3",{"id":20},"q1-why-do-bundlers-like-webpack-vite-esbuild-or-rollup-exist-in-a-modern-javascript-project","Q1. Why do bundlers like webpack, Vite, esbuild, or Rollup exist in a modern JavaScript project?",[23,24,27,38,44,50],"ul",{"className":25},[26],"contains-task-list",[28,29,32,37],"li",{"className":30},[31],"task-list-item",[33,34],"input",{"disabled":35,"type":36},true,"checkbox"," They are required by the JavaScript language specification for any project that uses more than one file",[28,39,41,43],{"className":40},[31],[33,42],{"disabled":35,"type":36}," They combine and resolve a project's module graph into fewer output files, cutting down HTTP requests, and enable whole-program optimizations (like tree-shaking) that aren't possible when analyzing files one at a time",[28,45,47,49],{"className":46},[31],[33,48],{"disabled":35,"type":36}," They exist only to add TypeScript support to a project",[28,51,53,55],{"className":52},[31],[33,54],{"disabled":35,"type":36}," They replace the browser's JavaScript engine with a faster one",[57,58,59,63,71],"details",{},[60,61,62],"summary",{},"Show Answer",[64,65,66,70],"p",{},[67,68,69],"strong",{},"Answer:"," B — They combine and resolve a project's module graph into fewer output files, cutting down HTTP requests, and enable whole-program optimizations (like tree-shaking) that aren't possible when analyzing files one at a time",[64,72,73,76,77,81,82,85,86,89],{},[67,74,75],{},"Explanation:"," Before bundlers, shipping many separate ",[78,79,80],"code",{},"\u003Cscript>"," files meant many separate HTTP round trips and no way to statically analyze which code was actually reachable. A bundler walks the ",[78,83,84],{},"import","\u002F",[78,87,88],{},"require"," graph starting from an entry point, resolves every dependency, and emits a small number of optimized output files — while also unlocking cross-file analysis like tree-shaking and code splitting. Nothing in the ECMAScript spec requires a bundler (option A) — Node and modern browsers can load ESM natively — and bundlers operate on the source code, not the JS engine itself (option D). TypeScript support (option C) is a separate, optional concern usually handled by a transpiler step.",[14,91,92,111,261,295],{"language":16},[18,93,95,96,99,100,103,104,107,108,110],{"id":94},"q2-why-can-a-bundler-safely-remove-multiply-from-the-production-bundle-below-but-couldnt-perform-the-same-removal-if-mathutilsjs-used-commonjs-moduleexports-require-instead","Q2. Why can a bundler safely remove ",[78,97,98],{},"multiply"," from the production bundle below, but couldn't perform the same removal if ",[78,101,102],{},"mathUtils.js"," used CommonJS (",[78,105,106],{},"module.exports"," \u002F ",[78,109,88],{},") instead?",[112,113,114],"code-wrapper",{"language":16},[115,116,120],"pre",{"className":117,"code":118,"language":16,"meta":119,"style":119},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F mathUtils.js\nexport function add(a, b) { return a + b; }\nexport function multiply(a, b) { return a * b; }\n\n\u002F\u002F app.js\nimport { add } from '.\u002FmathUtils.js';\nconsole.log(add(2, 3));\n","",[78,121,122,131,174,203,209,215,233],{"__ignoreMap":119},[123,124,127],"span",{"class":125,"line":126},"line",1,[123,128,130],{"class":129},"sdCPZ","\u002F\u002F mathUtils.js\n",[123,132,134,138,141,145,149,153,156,159,162,165,168,171],{"class":125,"line":133},2,[123,135,137],{"class":136},"svdQ7","export",[123,139,140],{"class":136}," function",[123,142,144],{"class":143},"sIsaT"," add",[123,146,148],{"class":147},"ssxIu","(",[123,150,152],{"class":151},"sCrzJ","a",[123,154,155],{"class":147},", ",[123,157,158],{"class":151},"b",[123,160,161],{"class":147},") { ",[123,163,164],{"class":136},"return",[123,166,167],{"class":147}," a ",[123,169,170],{"class":136},"+",[123,172,173],{"class":147}," b; }\n",[123,175,177,179,181,184,186,188,190,192,194,196,198,201],{"class":125,"line":176},3,[123,178,137],{"class":136},[123,180,140],{"class":136},[123,182,183],{"class":143}," multiply",[123,185,148],{"class":147},[123,187,152],{"class":151},[123,189,155],{"class":147},[123,191,158],{"class":151},[123,193,161],{"class":147},[123,195,164],{"class":136},[123,197,167],{"class":147},[123,199,200],{"class":136},"*",[123,202,173],{"class":147},[123,204,206],{"class":125,"line":205},4,[123,207,208],{"emptyLinePlaceholder":35},"\n",[123,210,212],{"class":125,"line":211},5,[123,213,214],{"class":129},"\u002F\u002F app.js\n",[123,216,218,220,223,226,230],{"class":125,"line":217},6,[123,219,84],{"class":136},[123,221,222],{"class":147}," { add } ",[123,224,225],{"class":136},"from",[123,227,229],{"class":228},"sJ6F3"," '.\u002FmathUtils.js'",[123,231,232],{"class":147},";\n",[123,234,236,239,242,244,247,249,253,255,258],{"class":125,"line":235},7,[123,237,238],{"class":147},"console.",[123,240,241],{"class":143},"log",[123,243,148],{"class":147},[123,245,246],{"class":143},"add",[123,248,148],{"class":147},[123,250,252],{"class":251},"snvgF","2",[123,254,155],{"class":147},[123,256,257],{"class":251},"3",[123,259,260],{"class":147},"));\n",[23,262,264,277,283,289],{"className":263},[26],[28,265,267,269,270,272,273,276],{"className":266},[31],[33,268],{"disabled":35,"type":36}," Because ESM import\u002Fexport bindings are static and analyzable at build time, so the bundler can prove ",[78,271,98],{}," is never referenced anywhere in the graph; ",[78,274,275],{},"require()"," is an ordinary function call that can execute conditionally or dynamically, so the bundler can't prove a given export is unused",[28,278,280,282],{"className":279},[31],[33,281],{"disabled":35,"type":36}," Because ESM files are always smaller in byte size than CommonJS files",[28,284,286,288],{"className":285},[31],[33,287],{"disabled":35,"type":36}," Because CommonJS modules cannot be included in a bundle at all",[28,290,292,294],{"className":291},[31],[33,293],{"disabled":35,"type":36}," Because tree-shaking only works when the project also uses TypeScript",[57,296,297,299,308],{},[60,298,62],{},[64,300,301,303,304,272,306,276],{},[67,302,69],{}," A — Because ESM import\u002Fexport bindings are static and analyzable at build time, so the bundler can prove ",[78,305,98],{},[78,307,275],{},[64,309,310,312,313,85,315,317,318,320,321,323],{},[67,311,75],{}," ESM ",[78,314,84],{},[78,316,137],{}," statements must appear at the top level with a fixed, literal set of names, so a bundler can build a complete, static picture of what's exported and what's actually imported and used — anything unreferenced is provably dead code. CommonJS's ",[78,319,275],{}," and ",[78,322,106],{}," are just regular JavaScript values and function calls; they can be wrapped in conditionals, computed with variables, or reassigned at runtime, so a bundler generally cannot prove a given property will never be accessed and must keep the whole module. This is the core mechanical reason \"tree-shaking needs ESM\" — it's not a licensing or file-size issue (options B, C are false), and it has nothing to do with TypeScript (option D).",[14,325,327,339,381,412],{"language":326},"json",[18,328,330,331,334,335,338],{"id":329},"q3-what-does-setting-sideeffects-false-in-a-librarys-packagejson-tell-a-bundler-like-webpack-and-what-risk-does-it-introduce-if-the-claim-is-wrong","Q3. What does setting ",[78,332,333],{},"\"sideEffects\": false"," in a library's ",[78,336,337],{},"package.json"," tell a bundler like webpack, and what risk does it introduce if the claim is wrong?",[112,340,341],{"language":326},[115,342,345],{"className":343,"code":344,"language":326,"meta":119,"style":119},"language-json shiki shiki-themes github-light github-dark","{\n  \"name\": \"date-utils\",\n  \"sideEffects\": false\n}\n",[78,346,347,352,366,376],{"__ignoreMap":119},[123,348,349],{"class":125,"line":126},[123,350,351],{"class":147},"{\n",[123,353,354,357,360,363],{"class":125,"line":133},[123,355,356],{"class":251},"  \"name\"",[123,358,359],{"class":147},": ",[123,361,362],{"class":228},"\"date-utils\"",[123,364,365],{"class":147},",\n",[123,367,368,371,373],{"class":125,"line":176},[123,369,370],{"class":251},"  \"sideEffects\"",[123,372,359],{"class":147},[123,374,375],{"class":251},"false\n",[123,377,378],{"class":125,"line":205},[123,379,380],{"class":147},"}\n",[23,382,384,390,396,406],{"className":383},[26],[28,385,387,389],{"className":386},[31],[33,388],{"disabled":35,"type":36}," It disables minification for that specific package during the build",[28,391,393,395],{"className":392},[31],[33,394],{"disabled":35,"type":36}," It forces the bundler to always include the entire package in the output, regardless of whether it's used",[28,397,399,401,402,405],{"className":398},[31],[33,400],{"disabled":35,"type":36}," It tells the bundler that importing any module in this package triggers no meaningful top-level side effects, so unused exports (and even entire unused modules) can be safely dropped; if a module secretly does something at import time — e.g. ",[78,403,404],{},"window.foo = ..."," executed at the top level — the bundler may strip it out anyway, silently breaking behavior that depended on it running",[28,407,409,411],{"className":408},[31],[33,410],{"disabled":35,"type":36}," It tells npm to skip running the package's install scripts",[57,413,414,416,423],{},[60,415,62],{},[64,417,418,420,421,405],{},[67,419,69],{}," C — It tells the bundler that importing any module in this package triggers no meaningful top-level side effects, so unused exports (and even entire unused modules) can be safely dropped; if a module secretly does something at import time — e.g. ",[78,422,404],{},[64,424,425,427,428,430],{},[67,426,75],{}," By default, bundlers must conservatively assume any module might do something important just by being imported (register a polyfill, patch a global, run an analytics ping), so they keep it even if none of its exports are used. ",[78,429,333],{}," is the package author's explicit promise that no module in the package needs to run \"just for its side effects,\" which lets the bundler drop whole unused files, not just unused exports. It's a real footgun: if that promise is false for even one file, tree-shaking can delete code the app silently relied on. It has nothing to do with minification (A), it does the opposite of \"always include everything\" (B), and it's unrelated to npm lifecycle scripts (D).",[14,432,433,437,464],{"language":16},[18,434,436],{"id":435},"q4-what-problem-do-source-maps-solve-when-debugging-a-production-javascript-app-in-the-browsers-devtools","Q4. What problem do source maps solve when debugging a production JavaScript app in the browser's devtools?",[23,438,440,446,452,458],{"className":439},[26],[28,441,443,445],{"className":442},[31],[33,444],{"disabled":35,"type":36}," They speed up the browser's JavaScript engine execution at runtime",[28,447,449,451],{"className":448},[31],[33,450],{"disabled":35,"type":36}," They map positions in the minified\u002Ftranspiled output back to the corresponding location in the original source, so devtools can display original file names, line numbers, and variable names instead of one unreadable minified line",[28,453,455,457],{"className":454},[31],[33,456],{"disabled":35,"type":36}," They automatically fix runtime errors before they can occur",[28,459,461,463],{"className":460},[31],[33,462],{"disabled":35,"type":36}," They replace the need for a transpilation step entirely",[57,465,466,468,473],{},[60,467,62],{},[64,469,470,472],{},[67,471,69],{}," B — They map positions in the minified\u002Ftranspiled output back to the corresponding location in the original source, so devtools can display original file names, line numbers, and variable names instead of one unreadable minified line",[64,474,475,477,478,481],{},[67,476,75],{}," A ",[78,479,480],{},".map"," file (or an inline base64 data-URI version of it) encodes a position-by-position mapping between the shipped output and the original authored source. When an error is thrown or a breakpoint is set in the minified bundle, devtools consult the source map to show you the original, human-readable source instead of a single 200KB line of renamed variables. It's purely a debugging aid — it has no effect on runtime speed (A), can't prevent errors from happening (C), and is unrelated to whether transpilation is needed (D).",[14,483,485,492,503,506,537],{"language":484},"bash",[18,486,488,489,491],{"id":487},"q5-a-production-bundle-ends-with-the-line-shown-below-and-the-corresponding-map-file-is-deployed-alongside-it-on-the-public-web-server","Q5. A production bundle ends with the line shown below, and the corresponding ",[78,490,480],{}," file is deployed alongside it on the public web server.",[112,493,494],{"language":16},[115,495,497],{"className":117,"code":496,"language":16,"meta":119,"style":119},"\u002F\u002F# sourceMappingURL=app.min.js.map\n",[78,498,499],{"__ignoreMap":119},[123,500,501],{"class":125,"line":126},[123,502,496],{"class":129},[64,504,505],{},"What is the practical risk of doing this on a public-facing deployment?",[23,507,509,515,521,527],{"className":508},[26],[28,510,512,514],{"className":511},[31],[33,513],{"disabled":35,"type":36}," There is no risk — browsers silently ignore this comment outside of development mode",[28,516,518,520],{"className":517},[31],[33,519],{"disabled":35,"type":36}," It causes the bundled JavaScript to execute twice on page load",[28,522,524,526],{"className":523},[31],[33,525],{"disabled":35,"type":36}," It prevents Hot Module Replacement from working correctly in the next local development session",[28,528,530,532,533,536],{"className":529},[31],[33,531],{"disabled":35,"type":36}," Anyone can open devtools, let it fetch ",[78,534,535],{},"app.min.js.map",", and reconstruct the full original, unminified source — including original file structure and variable names — because the map file embeds the complete original source content; teams that want minification's obfuscation benefit typically exclude source maps from public deploys, or upload them privately to an error-tracking service instead",[57,538,539,541,548],{},[60,540,62],{},[64,542,543,545,546,536],{},[67,544,69],{}," D — Anyone can open devtools, let it fetch ",[78,547,535],{},[64,549,550,552,553,107,556,559,560,563,564,568,569,572,573,576],{},[67,551,75],{}," ",[67,554,555],{},"Debug",[67,557,558],{},"Security"," — A source map's whole job is to reverse minification, so if it's publicly reachable it fully defeats any obfuscation minification provided: the ",[78,561,562],{},"sourcesContent"," field literally embeds the original file text. This comment is ",[565,566,567],"em",{},"not"," ignored outside dev (option A is false) — any browser's devtools will follow it whenever devtools are open, in any environment. It has no effect on double execution (B) or on a ",[565,570,571],{},"future"," dev session's HMR (C); those are unrelated mechanisms. The common production pattern is to still generate source maps (for your own error-tracking pipeline, e.g. Sentry) but upload them out-of-band and keep them off the public server, or omit the ",[78,574,575],{},"sourceMappingURL"," comment from the publicly served file.",[14,578,579,583,614],{"language":16},[18,580,582],{"id":581},"q6-a-teammate-says-we-dont-need-babel-anymore-since-we-already-have-webpack-in-the-build-whats-the-flaw-in-that-reasoning","Q6. A teammate says \"we don't need Babel anymore since we already have webpack in the build.\" What's the flaw in that reasoning?",[23,584,586,596,602,608],{"className":585},[26],[28,587,589,591,592,595],{"className":588},[31],[33,590],{"disabled":35,"type":36}," Bundling (resolving and combining a module graph, enabling tree-shaking and code splitting) and transpiling (rewriting newer syntax like optional chaining or class fields into syntax older engines can parse) are different concerns; webpack orchestrates the build and can invoke Babel as a loader, but without Babel (or an equivalent transform) newer syntax passes through unchanged and will throw a ",[78,593,594],{},"SyntaxError"," in engines that don't support it",[28,597,599,601],{"className":598},[31],[33,600],{"disabled":35,"type":36}," Nothing is wrong — webpack and Babel perform the exact same job, so either one alone is sufficient",[28,603,605,607],{"className":604},[31],[33,606],{"disabled":35,"type":36}," Babel is only relevant for TypeScript projects, so it was never needed here regardless",[28,609,611,613],{"className":610},[31],[33,612],{"disabled":35,"type":36}," webpack cannot process any JavaScript file at all without Babel installed",[57,615,616,618,625],{},[60,617,62],{},[64,619,620,622,623,595],{},[67,621,69],{}," A — Bundling (resolving and combining a module graph, enabling tree-shaking and code splitting) and transpiling (rewriting newer syntax like optional chaining or class fields into syntax older engines can parse) are different concerns; webpack orchestrates the build and can invoke Babel as a loader, but without Babel (or an equivalent transform) newer syntax passes through unchanged and will throw a ",[78,624,594],{},[64,626,627,629,630,633,634,637],{},[67,628,75],{}," webpack's core job is graph resolution and output generation; it has no built-in opinion about JavaScript ",[565,631,632],{},"syntax"," compatibility on its own. Babel's job is purely syntactic: parse newer JS, emit an equivalent AST expressed in older-compatible syntax (plus polyfills for missing runtime features, via something like ",[78,635,636],{},"core-js","). Plenty of projects use webpack with zero syntax-lowering — perfectly fine if you only target evergreen browsers — but the moment you need to support an older runtime, dropping Babel means shipping syntax that engine can't parse, which fails at parse time, not gracefully. Options B, C, and D each conflate two genuinely separate tools with separate responsibilities.",[14,639,640,644,684,687,717,720,750],{"language":16},[18,641,643],{"id":642},"q7-before-minification","Q7. Before minification:",[112,645,646],{"language":16},[115,647,649],{"className":117,"code":648,"language":16,"meta":119,"style":119},"const greet = (name) => `Hello, ${name}!`;\n",[78,650,651],{"__ignoreMap":119},[123,652,653,656,659,662,665,668,671,674,677,679,682],{"class":125,"line":126},[123,654,655],{"class":136},"const",[123,657,658],{"class":143}," greet",[123,660,661],{"class":136}," =",[123,663,664],{"class":147}," (",[123,666,667],{"class":151},"name",[123,669,670],{"class":147},") ",[123,672,673],{"class":136},"=>",[123,675,676],{"class":228}," `Hello, ${",[123,678,667],{"class":147},[123,680,681],{"class":228},"}!`",[123,683,232],{"class":147},[64,685,686],{},"After minification:",[112,688,689],{"language":16},[115,690,692],{"className":117,"code":691,"language":16,"meta":119,"style":119},"const greet=n=>`Hello, ${n}!`;\n",[78,693,694],{"__ignoreMap":119},[123,695,696,698,700,703,706,708,711,713,715],{"class":125,"line":126},[123,697,655],{"class":136},[123,699,658],{"class":143},[123,701,702],{"class":136},"=",[123,704,705],{"class":151},"n",[123,707,673],{"class":136},[123,709,710],{"class":228},"`Hello, ${",[123,712,705],{"class":147},[123,714,681],{"class":228},[123,716,232],{"class":147},[64,718,719],{},"A developer assumed minifying this file would make it compatible with an ES5-only browser (which doesn't support arrow functions or template literals). Why is that assumption wrong?",[23,721,723,729,735,744],{"className":722},[26],[28,724,726,728],{"className":725},[31],[33,727],{"disabled":35,"type":36}," Minifiers remove all modern syntax by definition, so this specific case must be a bug in the minifier",[28,730,732,734],{"className":731},[31],[33,733],{"disabled":35,"type":36}," Minifiers and transpilers are simply two different marketing names for the same underlying tool",[28,736,738,740,741,743],{"className":737},[31],[33,739],{"disabled":35,"type":36}," Minification only shrinks code — renaming variables, stripping whitespace and comments, and similar size-focused rewrites — without changing which language-version features the code uses; the arrow function and template literal survive untouched, so an ES5-only engine still throws a ",[78,742,594],{},". Only transpilation (e.g. via Babel) rewrites syntax down to an older-compatible form",[28,745,747,749],{"className":746},[31],[33,748],{"disabled":35,"type":36}," The minified code is actually less compatible with any browser than the unminified original",[57,751,752,754,761],{},[60,753,62],{},[64,755,756,758,759,743],{},[67,757,69],{}," C — Minification only shrinks code — renaming variables, stripping whitespace and comments, and similar size-focused rewrites — without changing which language-version features the code uses; the arrow function and template literal survive untouched, so an ES5-only engine still throws a ",[78,760,594],{},[64,762,763,552,765,768,769,771,772,775,776,778,779,781,782,785],{},[67,764,75],{},[67,766,767],{},"Idiom"," — Notice the minified output still contains ",[78,770,673],{}," and a template-literal backtick — a minifier's job (tools like Terser) is purely about ",[565,773,774],{},"output size",", not language-version compatibility. It happily shortens ",[78,777,667],{}," to ",[78,780,705],{}," and drops whitespace, but it has no concept of \"rewrite this arrow function as a ",[78,783,784],{},"function"," expression for older engines\" — that's transpilation's job, a semantically different transform. Confusing the two is a real production trap: teams sometimes ship a minified-but-not-transpiled bundle assuming \"smaller\" implies \"more compatible,\" and it silently breaks on the exact old browsers they meant to support.",[14,787,788,792,819],{"language":16},[18,789,791],{"id":790},"q8-what-does-hot-module-replacement-hmr-in-a-dev-server-like-vites-or-webpack-dev-servers-do-that-a-full-page-reload-on-save-does-not","Q8. What does Hot Module Replacement (HMR) in a dev server (like Vite's or webpack-dev-server's) do that a full page reload on save does not?",[23,793,795,801,807,813],{"className":794},[26],[28,796,798,800],{"className":797},[31],[33,799],{"disabled":35,"type":36}," It permanently deploys the current change straight to production automatically",[28,802,804,806],{"className":803},[31],[33,805],{"disabled":35,"type":36}," It swaps only the updated module(s) into the already-running application in the browser, preserving in-memory state — a form's typed-in text, a Redux store, an open modal's state — that a full page reload would otherwise wipe out",[28,808,810,812],{"className":809},[31],[33,811],{"disabled":35,"type":36}," It compiles the app faster, but the browser still performs a full page reload on every save regardless",[28,814,816,818],{"className":815},[31],[33,817],{"disabled":35,"type":36}," It works only for CSS files and has no effect on JavaScript module updates",[57,820,821,823,828],{},[60,822,62],{},[64,824,825,827],{},[67,826,69],{}," B — It swaps only the updated module(s) into the already-running application in the browser, preserving in-memory state — a form's typed-in text, a Redux store, an open modal's state — that a full page reload would otherwise wipe out",[64,829,830,832,833,836],{},[67,831,75],{}," HMR relies on the dev server pushing just the changed module's new code over a persistent connection (typically a WebSocket), and a small runtime in the page replaces that module in place, re-running only what's needed to apply the update, without tearing down the whole JS execution context. That's precisely why it's valuable during development of stateful UI: you can tweak a component's rendering logic and see the change instantly without losing whatever state you'd navigated into. Option A confuses a dev-only mechanism with deployment. Option C describes what a fast ",[565,834,835],{},"full reload"," setup does, which is a different (and less state-preserving) feature. Option D is wrong — HMR is commonly used for JS component updates too, not just CSS.",[14,838,839,854,892,905,961],{"language":326},[18,840,842,843,846,847,849,850,853],{"id":841},"q9-two-developers-run-npm-install-on-different-days-using-only-the-packagejson-snippet-below-with-no-package-lockjson-present-or-committed-to-the-repository","Q9. Two developers run ",[78,844,845],{},"npm install"," on different days, using only the ",[78,848,337],{}," snippet below — with no ",[78,851,852],{},"package-lock.json"," present or committed to the repository.",[112,855,856],{"language":326},[115,857,859],{"className":343,"code":858,"language":326,"meta":119,"style":119},"{\n  \"dependencies\": {\n    \"left-pad\": \"^1.3.0\"\n  }\n}\n",[78,860,861,865,873,883,888],{"__ignoreMap":119},[123,862,863],{"class":125,"line":126},[123,864,351],{"class":147},[123,866,867,870],{"class":125,"line":133},[123,868,869],{"class":251},"  \"dependencies\"",[123,871,872],{"class":147},": {\n",[123,874,875,878,880],{"class":125,"line":176},[123,876,877],{"class":251},"    \"left-pad\"",[123,879,359],{"class":147},[123,881,882],{"class":228},"\"^1.3.0\"\n",[123,884,885],{"class":125,"line":205},[123,886,887],{"class":147},"  }\n",[123,889,890],{"class":125,"line":211},[123,891,380],{"class":147},[64,893,894,895,155,897,900,901,904],{},"Why might they end up with different actual installed versions, and what does committing a lockfile (",[78,896,852],{},[78,898,899],{},"yarn.lock",", or ",[78,902,903],{},"pnpm-lock.yaml",") fix?",[23,906,908,916,930,940],{"className":907},[26],[28,909,911,552,913,915],{"className":910},[31],[33,912],{"disabled":35,"type":36},[78,914,845],{}," always installs the exact same version regardless of lockfiles, so this scenario is impossible",[28,917,919,921,922,925,926,929],{"className":918},[31],[33,920],{"disabled":35,"type":36}," Lockfiles only pin versions for ",[78,923,924],{},"devDependencies",", never for regular ",[78,927,928],{},"dependencies",", so this scenario would happen with or without one",[28,931,933,935,936,939],{"className":932},[31],[33,934],{"disabled":35,"type":36}," The ",[78,937,938],{},"^"," symbol actually means \"exact version only,\" so both installs are already guaranteed to be identical without any lockfile",[28,941,943,552,945,948,949,952,953,956,957,960],{"className":942},[31],[33,944],{"disabled":35,"type":36},[78,946,947],{},"^1.3.0"," permits any ",[78,950,951],{},"1.x.x"," release equal to or newer than ",[78,954,955],{},"1.3.0"," (excluding ",[78,958,959],{},"2.0.0","), so a new compatible version published between the two install dates — or a transitive dependency resolving its own range differently — can produce a different dependency tree on each machine; a committed lockfile pins the exact resolved version (and the full transitive tree) so every install reproduces identical versions",[57,962,963,965,978],{},[60,964,62],{},[64,966,967,969,970,948,972,952,974,956,976,960],{},[67,968,69],{}," D — ",[78,971,947],{},[78,973,951],{},[78,975,955],{},[78,977,959],{},[64,979,980,552,982,984,985,988,989,992,993,996,997,999,1000,1003],{},[67,981,75],{},[78,983,337],{}," alone only expresses ",[565,986,987],{},"acceptable ranges",", not exact versions — that's true by design, so authors can receive compatible patches automatically. The reproducibility problem is that \"acceptable range\" can resolve to a different concrete version depending on ",[565,990,991],{},"when"," you install and what else is in the dependency tree at that moment, including nested (transitive) dependencies with their own ranges. A lockfile freezes the entire resolved tree — exact versions and their exact sub-dependencies — so ",[78,994,995],{},"npm ci"," (or the equivalent) on any machine, at any later date, installs byte-for-byte the same tree. Option A is simply false in the absence of a lockfile; option B misdescribes lockfile scope (they cover all dependency types); option C misstates what ",[78,998,938],{}," means (it is a ",[565,1001,1002],{},"range",", not an exact pin).",[14,1005,1006,1018,1063],{"language":16},[18,1007,1009,1010,1013,1014,1017],{"id":1008},"q10-a-library-bumps-its-published-version-from-241-straight-to-300-with-no-other-announcement-under-semantic-versioning-semver-conventions-what-should-consumers-assume","Q10. A library bumps its published version from ",[78,1011,1012],{},"2.4.1"," straight to ",[78,1015,1016],{},"3.0.0",", with no other announcement. Under semantic versioning (semver) conventions, what should consumers assume?",[23,1019,1021,1045,1051,1057],{"className":1020},[26],[28,1022,1024,1026,1027,1030,1031,1033,1034,1036,1037,1040,1041,1044],{"className":1023},[31],[33,1025],{"disabled":35,"type":36}," The release contains a backwards-incompatible (\"breaking\") change to the public API — code that worked against ",[78,1028,1029],{},"2.x"," may need modification to work against ",[78,1032,1016],{},"; by contrast, a ",[78,1035,1012],{}," → ",[78,1038,1039],{},"2.5.0"," bump would promise new backwards-compatible features, and → ",[78,1042,1043],{},"2.4.2"," would promise only backwards-compatible bug fixes",[28,1046,1048,1050],{"className":1047},[31],[33,1049],{"disabled":35,"type":36}," Nothing meaningfully changed except bug fixes, so it's safe to upgrade blindly",[28,1052,1054,1056],{"className":1053},[31],[33,1055],{"disabled":35,"type":36}," The major version number is purely cosmetic marketing and carries no contractual meaning under semver",[28,1058,1060,1062],{"className":1059},[31],[33,1061],{"disabled":35,"type":36}," It means the package now requires a completely different JavaScript runtime, such as switching from Node.js to Deno",[57,1064,1065,1067,1082],{},[60,1066,62],{},[64,1068,1069,1071,1072,1030,1074,1033,1076,1036,1078,1040,1080,1044],{},[67,1070,69],{}," A — The release contains a backwards-incompatible (\"breaking\") change to the public API — code that worked against ",[78,1073,1029],{},[78,1075,1016],{},[78,1077,1012],{},[78,1079,1039],{},[78,1081,1043],{},[64,1083,1084,1086,1087,1090,1091,1094,1095,1036,1097,1099,1100,1103],{},[67,1085,75],{}," Semver's ",[78,1088,1089],{},"MAJOR.MINOR.PATCH"," scheme is a contract: PATCH bumps promise backwards-compatible bug fixes only, MINOR bumps promise backwards-compatible new functionality, and MAJOR bumps are the ",[565,1092,1093],{},"only"," place a breaking change is allowed to happen under the convention — so a ",[78,1096,1029],{},[78,1098,1016],{}," jump is the explicit signal to consult a changelog\u002Fmigration guide before upgrading, not to upgrade blindly (ruling out option B). The version number is meaningful, not cosmetic (ruling out C), and a major bump says nothing by itself about runtime requirements (ruling out D) — that would be called out separately, e.g. in an ",[78,1101,1102],{},"engines"," field.",[14,1105,1106,1118,1194,1234],{"language":16},[18,1107,1109,1110,1113,1114,1117],{"id":1108},"q11-what-does-a-bundler-typically-do-with-the-dynamic-import-call-below-that-it-would-not-do-with-a-static-import-openmodal-from-modaljs-placed-at-the-top-of-the-file","Q11. What does a bundler typically do with the dynamic ",[78,1111,1112],{},"import()"," call below that it would not do with a static ",[78,1115,1116],{},"import { openModal } from '.\u002Fmodal.js'"," placed at the top of the file?",[112,1119,1120],{"language":16},[115,1121,1123],{"className":117,"code":1122,"language":16,"meta":119,"style":119},"button.addEventListener('click', async () => {\n  const { openModal } = await import('.\u002Fmodal.js');\n  openModal();\n});\n",[78,1124,1125,1151,1181,1189],{"__ignoreMap":119},[123,1126,1127,1130,1133,1135,1138,1140,1143,1146,1148],{"class":125,"line":126},[123,1128,1129],{"class":147},"button.",[123,1131,1132],{"class":143},"addEventListener",[123,1134,148],{"class":147},[123,1136,1137],{"class":228},"'click'",[123,1139,155],{"class":147},[123,1141,1142],{"class":136},"async",[123,1144,1145],{"class":147}," () ",[123,1147,673],{"class":136},[123,1149,1150],{"class":147}," {\n",[123,1152,1153,1156,1159,1162,1165,1167,1170,1173,1175,1178],{"class":125,"line":133},[123,1154,1155],{"class":136},"  const",[123,1157,1158],{"class":147}," { ",[123,1160,1161],{"class":251},"openModal",[123,1163,1164],{"class":147}," } ",[123,1166,702],{"class":136},[123,1168,1169],{"class":136}," await",[123,1171,1172],{"class":136}," import",[123,1174,148],{"class":147},[123,1176,1177],{"class":228},"'.\u002Fmodal.js'",[123,1179,1180],{"class":147},");\n",[123,1182,1183,1186],{"class":125,"line":176},[123,1184,1185],{"class":143},"  openModal",[123,1187,1188],{"class":147},"();\n",[123,1190,1191],{"class":125,"line":205},[123,1192,1193],{"class":147},"});\n",[23,1195,1197,1207,1216,1225],{"className":1196},[26],[28,1198,1200,1202,1203,1206],{"className":1199},[31],[33,1201],{"disabled":35,"type":36}," It ignores the dynamic import entirely and bundles ",[78,1204,1205],{},"modal.js"," into the main bundle exactly as if it had been statically imported",[28,1208,1210,1212,1213,1215],{"className":1209},[31],[33,1211],{"disabled":35,"type":36}," It runs the code inside ",[78,1214,1205],{}," on a separate operating-system thread automatically",[28,1217,1219,1221,1222,1224],{"className":1218},[31],[33,1220],{"disabled":35,"type":36}," It extracts ",[78,1223,1205],{}," (and its own dependencies) into a separate chunk file that's only fetched over the network when the click handler actually executes, instead of being downloaded as part of the initial page load — shrinking the initial bundle",[28,1226,1228,1230,1231,1233],{"className":1227},[31],[33,1229],{"disabled":35,"type":36}," It silently converts every export inside ",[78,1232,1205],{}," from ESM syntax into CommonJS syntax",[57,1235,1236,1238,1245],{},[60,1237,62],{},[64,1239,1240,1242,1243,1224],{},[67,1241,69],{}," C — It extracts ",[78,1244,1205],{},[64,1246,1247,1249,1250,1252],{},[67,1248,75],{}," A dynamic ",[78,1251,1112],{}," call returns a promise and is a recognized signal to essentially every modern bundler that the target module and its subgraph should become their own on-demand chunk, fetched lazily at runtime rather than being force-included in the entry bundle. This is the mechanism behind route-based and feature-based code splitting — code the user might never trigger (like a rarely opened modal) never has to be downloaded until it's needed. It doesn't run on a separate thread (B is a misconception conflating this with Web Workers), it's not ignored (A is simply the opposite of what code splitting is for), and it doesn't force a module-format conversion (D) — the output format is a build configuration choice, unrelated to whether the import is static or dynamic.",[14,1254,1255,1259,1294],{"language":16},[18,1256,1258],{"id":1257},"q12-a-teams-ci-pipeline-runs-both-eslint-and-prettier-a-developer-asks-isnt-that-redundant-dont-they-both-just-check-code-style-whats-the-accurate-distinction","Q12. A team's CI pipeline runs both ESLint and Prettier. A developer asks: \"isn't that redundant — don't they both just check code style?\" What's the accurate distinction?",[23,1260,1262,1268,1282,1288],{"className":1261},[26],[28,1263,1265,1267],{"className":1264},[31],[33,1266],{"disabled":35,"type":36}," Prettier is the one that catches actual bugs, while ESLint only reformats whitespace",[28,1269,1271,1273,1274,1277,1278,1281],{"className":1270},[31],[33,1272],{"disabled":35,"type":36}," ESLint performs static analysis to catch potential bugs and enforce code-quality rules (e.g. unused variables, unreachable code, misuse of ",[78,1275,1276],{},"==","), while Prettier is purely an opinionated code formatter that rewrites whitespace, quote style, and line breaks without understanding code semantics; they're complementary tools, and teams commonly disable ESLint's own formatting-related rules (e.g. via ",[78,1279,1280],{},"eslint-config-prettier",") so the two don't fight over the same lines",[28,1283,1285,1287],{"className":1284},[31],[33,1286],{"disabled":35,"type":36}," Yes, it's redundant — either tool alone already provides everything the other one does",[28,1289,1291,1293],{"className":1290},[31],[33,1292],{"disabled":35,"type":36}," Only one of the two tools is actually allowed to run inside a CI pipeline at a time",[57,1295,1296,1298,1307],{},[60,1297,62],{},[64,1299,1300,1302,1303,1277,1305,1281],{},[67,1301,69],{}," B — ESLint performs static analysis to catch potential bugs and enforce code-quality rules (e.g. unused variables, unreachable code, misuse of ",[78,1304,1276],{},[78,1306,1280],{},[64,1308,1309,552,1311,1313,1314,1317,1318,1321,1322,1325,1326,1329],{},[67,1310,75],{},[67,1312,767],{}," — ESLint parses code into an AST and applies rules that reason about ",[565,1315,1316],{},"meaning"," — \"this variable is never read,\" \"this promise is never awaited,\" \"this ",[78,1319,1320],{},"switch"," case falls through unintentionally\" — the kind of issue that can indicate an actual bug. Prettier has no opinion on any of that; it only reprints code in a single canonical style so diffs and reviews aren't cluttered by formatting bikeshedding. Running both isn't redundant, it's standard practice — but running ESLint's ",[565,1323,1324],{},"formatting"," rules alongside Prettier's formatting ",[565,1327,1328],{},"would"," be redundant (and can conflict), which is why teams disable that overlapping subset specifically.",[14,1331,1332,1336,1363],{"language":16},[18,1333,1335],{"id":1334},"q13-a-teams-ci-pipeline-for-a-js-project-runs-in-order-install-dependencies-lint-unit-tests-build-a-new-hire-asks-why-the-build-step-often-the-slowest-runs-last-instead-of-first-whats-the-reasoning","Q13. A team's CI pipeline for a JS project runs, in order: install dependencies → lint → unit tests → build. A new hire asks why the build step — often the slowest — runs last instead of first. What's the reasoning?",[23,1337,1339,1345,1351,1357],{"className":1338},[26],[28,1340,1342,1344],{"className":1341},[31],[33,1343],{"disabled":35,"type":36}," The build must run last because bundlers are only able to process code that has already passed its unit tests",[28,1346,1348,1350],{"className":1347},[31],[33,1349],{"disabled":35,"type":36}," Lint and test are required to run after the build because they need the already-compiled output to work against",[28,1352,1354,1356],{"className":1353},[31],[33,1355],{"disabled":35,"type":36}," The step order is arbitrary and has no measurable effect on how quickly the pipeline reports a failure",[28,1358,1360,1362],{"className":1359},[31],[33,1361],{"disabled":35,"type":36}," Running the fastest, cheapest checks first — lint typically finishes in seconds — means the pipeline fails fast on trivial issues before spending time on slower steps; if lint fails, there's no reason to wait through a multi-minute build (or a slower test suite) just to discover a problem that a quick static check already caught",[57,1364,1365,1367,1372],{},[60,1366,62],{},[64,1368,1369,1371],{},[67,1370,69],{}," D — Running the fastest, cheapest checks first — lint typically finishes in seconds — means the pipeline fails fast on trivial issues before spending time on slower steps; if lint fails, there's no reason to wait through a multi-minute build (or a slower test suite) just to discover a problem that a quick static check already caught",[64,1373,1374,1376,1377,1380],{},[67,1375,75],{}," CI ordering is usually optimized for \"fail fast\": cheap, high-signal checks run first so a broken commit is rejected in seconds rather than after minutes of unnecessary work. Lint is typically the fastest (pure static analysis, no execution), tests are next (they execute code but are usually scoped and parallelizable), and a full production build is often the slowest step because it involves bundling, minification, and sometimes type-checking a whole project. Neither lint nor tests structurally depend on build output in a typical JS setup (ruling out B), and the build doesn't require passing tests to ",[565,1378,1379],{},"run"," — teams just choose not to waste time building a commit that's already known to be broken (ruling out A). Ordering absolutely affects feedback latency, so C is false too.",[14,1382,1383,1391,1421,1424,1461],{"language":16},[18,1384,1386,1387,1390],{"id":1385},"q14-a-frontend-team-changes-the-vite_api_url-environment-variable-on-their-server-after-already-deploying-a-built-vite-app-expecting-the-running-app-to-pick-up-the-new-url-on-the-next-page-load-without-a-rebuild","Q14. A frontend team changes the ",[78,1388,1389],{},"VITE_API_URL"," environment variable on their server after already deploying a built Vite app, expecting the running app to pick up the new URL on the next page load without a rebuild.",[112,1392,1393],{"language":16},[115,1394,1396],{"className":117,"code":1395,"language":16,"meta":119,"style":119},"console.log(import.meta.env.VITE_API_URL);\n",[78,1397,1398],{"__ignoreMap":119},[123,1399,1400,1402,1404,1406,1408,1411,1414,1417,1419],{"class":125,"line":126},[123,1401,238],{"class":147},[123,1403,241],{"class":143},[123,1405,148],{"class":147},[123,1407,84],{"class":136},[123,1409,1410],{"class":147},".",[123,1412,1413],{"class":251},"meta",[123,1415,1416],{"class":147},".env.",[123,1418,1389],{"class":251},[123,1420,1180],{"class":147},[64,1422,1423],{},"Why doesn't this work?",[23,1425,1427,1440,1446,1455],{"className":1426},[26],[28,1428,1430,552,1432,1435,1436,1439],{"className":1429},[31],[33,1431],{"disabled":35,"type":36},[78,1433,1434],{},"import.meta.env.VITE_API_URL"," is resolved at build time — Vite statically replaces that expression with the literal value present in the environment when ",[78,1437,1438],{},"vite build"," ran, baking it directly into the generated static JS files; there's no runtime process left in the browser to re-read a server environment variable, so the already-deployed static files must be rebuilt (and redeployed) for a new value to take effect",[28,1441,1443,1445],{"className":1442},[31],[33,1444],{"disabled":35,"type":36}," Environment variables are always read live from the server on every page load in any frontend framework, so this should already be working",[28,1447,1449,552,1451,1454],{"className":1448},[31],[33,1450],{"disabled":35,"type":36},[78,1452,1453],{},"import.meta.env"," never reads from environment variables at all — it only reads from a static config file that has nothing to do with the server environment",[28,1456,1458,1460],{"className":1457},[31],[33,1459],{"disabled":35,"type":36}," The value only updates the next time the browser itself is restarted, but otherwise updates automatically on every request",[57,1462,1463,1465,1474],{},[60,1464,62],{},[64,1466,1467,1469,1470,1435,1472,1439],{},[67,1468,69],{}," A — ",[78,1471,1434],{},[78,1473,1438],{},[64,1475,1476,552,1478,1480,1481,1484,1485,1487,1488,1491],{},[67,1477,75],{},[67,1479,555],{}," — This is a common point of confusion carried over from backend habits, where ",[78,1482,1483],{},"process.env.X"," really is read live at runtime by a running Node process. In a bundled frontend app, ",[78,1486,1434],{}," (or Create React App's ",[78,1489,1490],{},"process.env.REACT_APP_X",") is a compile-time substitution: the bundler literally replaces that expression with a hardcoded string in the emitted JS during the build step, because there is no server-side process running in the user's browser to consult a live environment variable. Changing the server's env var after the fact changes nothing about files that were already generated and shipped — a fresh build is required. Options B, C, and D each describe behavior that doesn't apply to a statically bundled frontend.",[14,1493,1494,1498,1529],{"language":16},[18,1495,1497],{"id":1496},"q15-a-developer-replaces-a-large-date-handling-library-with-a-smaller-alternative-expecting-the-production-bundle-to-shrink-as-a-result-but-never-actually-checks-whats-the-best-practice-next-step-before-assuming-the-optimization-worked","Q15. A developer replaces a large date-handling library with a smaller alternative, expecting the production bundle to shrink as a result — but never actually checks. What's the best-practice next step before assuming the optimization worked?",[23,1499,1501,1507,1513,1523],{"className":1500},[26],[28,1502,1504,1506],{"className":1503},[31],[33,1505],{"disabled":35,"type":36}," Trust the change without verification, since swapping to a \"smaller\" library logically implies a smaller bundle",[28,1508,1510,1512],{"className":1509},[31],[33,1511],{"disabled":35,"type":36}," Only check the bundle size in a staging environment, and never verify it locally during development",[28,1514,1516,1518,1519,1522],{"className":1515},[31],[33,1517],{"disabled":35,"type":36}," Inspect the actual build output — e.g. with a bundle analyzer (webpack-bundle-analyzer, or Vite's ",[78,1520,1521],{},"rollup-plugin-visualizer",") or by diffing the output file sizes before and after — since the real bundle size depends on how well the bundler tree-shakes both libraries, whether other code still imports the old library transitively, and whether duplicate copies get pulled in through other dependencies; assumptions about size are frequently wrong until actually measured",[28,1524,1526,1528],{"className":1525},[31],[33,1527],{"disabled":35,"type":36}," Assume bundle size no longer matters at all once gzip or Brotli compression is applied by the server",[57,1530,1531,1533,1540],{},[60,1532,62],{},[64,1534,1535,1537,1538,1522],{},[67,1536,69],{}," C — Inspect the actual build output — e.g. with a bundle analyzer (webpack-bundle-analyzer, or Vite's ",[78,1539,1521],{},[64,1541,1542,552,1544,1547],{},[67,1543,75],{},[67,1545,1546],{},"Performance"," — Swapping libraries feels like an obvious win, but the actual result depends on build-tool behavior you can't fully predict from source code alone: maybe another dependency still transitively pulls in the old library (so it never actually left the bundle), maybe the \"smaller\" library tree-shakes worse in practice, or maybe a duplicate version sneaks in through a nested dependency's own lockfile. A bundle analyzer visualizes exactly what ended up in the output and how large each module actually is, turning an assumption into a measurement. Compression (option D) reduces bytes over the wire but doesn't change parse\u002Fexecution cost, so it doesn't make bundle size irrelevant, and skipping local checks (option B) just delays discovering a mistake.",[14,1549,1550,1579,1643,1693],{"language":16},[18,1551,1553,1554,1557,1558,1561,1562,1565,1566,1569,1570,1572,1573,1575,1576,1578],{"id":1552},"q16-appjs-imports-analyticsjs-purely-for-its-side-effect-and-never-calls-track-assuming-the-analytics-packages-packagejson-does-not-set-sideeffects-false-what-happens-during-tree-shaking","Q16. ",[78,1555,1556],{},"app.js"," imports ",[78,1559,1560],{},"analytics.js"," purely for its side effect and never calls ",[78,1563,1564],{},"track",". Assuming the ",[78,1567,1568],{},"analytics"," package's ",[78,1571,337],{}," does ",[565,1574,567],{}," set ",[78,1577,333],{},", what happens during tree-shaking?",[112,1580,1581],{"language":16},[115,1582,1584],{"className":117,"code":1583,"language":16,"meta":119,"style":119},"\u002F\u002F analytics.js\nconsole.log('Analytics module loaded');\nexport function track(event) { \u002F* ... *\u002F }\n\n\u002F\u002F app.js\nimport '.\u002Fanalytics.js';\n",[78,1585,1586,1591,1604,1626,1630,1634],{"__ignoreMap":119},[123,1587,1588],{"class":125,"line":126},[123,1589,1590],{"class":129},"\u002F\u002F analytics.js\n",[123,1592,1593,1595,1597,1599,1602],{"class":125,"line":133},[123,1594,238],{"class":147},[123,1596,241],{"class":143},[123,1598,148],{"class":147},[123,1600,1601],{"class":228},"'Analytics module loaded'",[123,1603,1180],{"class":147},[123,1605,1606,1608,1610,1613,1615,1618,1620,1623],{"class":125,"line":176},[123,1607,137],{"class":136},[123,1609,140],{"class":136},[123,1611,1612],{"class":143}," track",[123,1614,148],{"class":147},[123,1616,1617],{"class":151},"event",[123,1619,161],{"class":147},[123,1621,1622],{"class":129},"\u002F* ... *\u002F",[123,1624,1625],{"class":147}," }\n",[123,1627,1628],{"class":125,"line":205},[123,1629,208],{"emptyLinePlaceholder":35},[123,1631,1632],{"class":125,"line":211},[123,1633,214],{"class":129},[123,1635,1636,1638,1641],{"class":125,"line":217},[123,1637,84],{"class":136},[123,1639,1640],{"class":228}," '.\u002Fanalytics.js'",[123,1642,232],{"class":147},[23,1644,1646,1658,1675,1681],{"className":1645},[26],[28,1647,1649,1651,1652,1654,1655,1657],{"className":1648},[31],[33,1650],{"disabled":35,"type":36}," The bundler removes the entire ",[78,1653,1560],{}," module, since ",[78,1656,1564],{}," is never referenced anywhere",[28,1659,1661,1663,1664,1666,1667,1670,1671,1674],{"className":1660},[31],[33,1662],{"disabled":35,"type":36}," The bundler must keep the whole module — including the unused ",[78,1665,1564],{}," function — because it can't prove the top-level ",[78,1668,1669],{},"console.log"," call is free of observable side effects, and running it is required for correctness; tree-shaking only removes code the bundler can prove is both unused ",[565,1672,1673],{},"and"," side-effect-free to skip",[28,1676,1678,1680],{"className":1677},[31],[33,1679],{"disabled":35,"type":36}," The build fails with an error, because top-level side effects are disallowed in ES modules",[28,1682,1684,1686,1687,1689,1690,1692],{"className":1683},[31],[33,1685],{"disabled":35,"type":36}," Only the ",[78,1688,1669],{}," line is stripped from the output, while ",[78,1691,1564],{}," is kept regardless",[57,1694,1695,1697,1708],{},[60,1696,62],{},[64,1698,1699,1701,1702,1666,1704,1670,1706,1674],{},[67,1700,69],{}," B — The bundler must keep the whole module — including the unused ",[78,1703,1564],{},[78,1705,1669],{},[565,1707,1673],{},[64,1709,1710,552,1712,1714,1715,1718,1719,1722,1723,1725,1726,1728,1729,1731],{},[67,1711,75],{},[67,1713,555],{}," — Tree-shaking's soundness guarantee requires proving a piece of code has ",[565,1716,1717],{},"no observable effect"," if removed. A statement like ",[78,1720,1721],{},"console.log(...)"," sitting directly at module scope executes the moment the module is evaluated, and removing it would change observable program behavior (the log line simply wouldn't appear) — so the bundler conservatively keeps the whole module, ",[78,1724,1564],{}," included, even though ",[78,1727,1564],{}," itself is never called. This is exactly the scenario ",[78,1730,333],{}," (see Q3) exists to override: it lets the package author explicitly promise no module needs to run \"just for its side effects,\" unlocking the removal the bundler otherwise can't safely perform on its own. ES modules impose no such restriction (ruling out C), and bundlers don't selectively remove single statements from a kept module while leaving unrelated exports (ruling out D).",[14,1733,1734,1744,1784],{"language":16},[18,1735,1737,1738,1740,1741,1743],{"id":1736},"q17-a-project-ends-up-with-both-a-package-lockjson-and-a-pnpm-lockyaml-committed-after-a-teammate-ran-a-different-package-manager-locally-by-mistake-whats-the-practical-problem","Q17. A project ends up with both a ",[78,1739,852],{}," and a ",[78,1742,903],{}," committed, after a teammate ran a different package manager locally by mistake. What's the practical problem?",[23,1745,1747,1758,1764,1770],{"className":1746},[26],[28,1748,1750,552,1752,1754,1755,1757],{"className":1749},[31],[33,1751],{"disabled":35,"type":36},[78,1753,903],{}," always silently takes priority over ",[78,1756,852],{},", in every package manager, so nothing actually breaks",[28,1759,1761,1763],{"className":1760},[31],[33,1762],{"disabled":35,"type":36}," Lockfiles are optional metadata that npm, yarn, and pnpm all ignore by default during install, so committing more than one changes nothing",[28,1765,1767,1769],{"className":1766},[31],[33,1768],{"disabled":35,"type":36}," No problem exists — every major package manager automatically merges and reconciles any lockfile format it finds",[28,1771,1773,1775,1776,1779,1780,1783],{"className":1772},[31],[33,1774],{"disabled":35,"type":36}," Each package manager reads and trusts only its own lockfile format, so mixing formats causes inconsistent dependency resolution between teammates and CI depending on which tool happens to run, defeating the reproducibility guarantee lockfiles exist to provide; teams typically enforce a single package manager (e.g. via a ",[78,1777,1778],{},"packageManager"," field or a CI check) and ",[78,1781,1782],{},".gitignore"," the rest",[57,1785,1786,1788,1797],{},[60,1787,62],{},[64,1789,1790,1792,1793,1779,1795,1783],{},[67,1791,69],{}," D — Each package manager reads and trusts only its own lockfile format, so mixing formats causes inconsistent dependency resolution between teammates and CI depending on which tool happens to run, defeating the reproducibility guarantee lockfiles exist to provide; teams typically enforce a single package manager (e.g. via a ",[78,1794,1778],{},[78,1796,1782],{},[64,1798,1799,1801,1802,1804,1805,1807,1808,1810,1811,1813,1814,1817],{},[67,1800,75],{}," npm only consults ",[78,1803,852],{},", pnpm only consults ",[78,1806,903],{},", and yarn only consults ",[78,1809,899],{}," — none of them read or reconcile a rival tool's lockfile. If both files sit in the repo, whichever teammate (or CI job) happens to run ",[78,1812,845],{}," gets npm's resolution, while whoever runs ",[78,1815,1816],{},"pnpm install"," gets pnpm's — potentially different dependency trees, entirely defeating the point of having a lockfile at all. There's no automatic merging or precedence between formats (ruling out A and C), and lockfiles are very much respected by default, not ignored (ruling out B) — that's the entire reason this mismatch causes a real problem instead of a harmless no-op.",[14,1819,1820,1824,1851],{"language":16},[18,1821,1823],{"id":1822},"q18-vite-uses-esbuild-to-pre-bundle-dependencies-and-serve-native-esm-during-development-but-switches-to-rollup-for-the-production-build-given-that-esbuild-is-dramatically-faster-than-rollup-why-not-just-use-esbuild-for-production-too","Q18. Vite uses esbuild to pre-bundle dependencies and serve native ESM during development, but switches to Rollup for the production build. Given that esbuild is dramatically faster than Rollup, why not just use esbuild for production too?",[23,1825,1827,1833,1839,1845],{"className":1826},[26],[28,1828,1830,1832],{"className":1829},[31],[33,1831],{"disabled":35,"type":36}," esbuild's plugin ecosystem and fine-grained output control (advanced code-splitting strategies, broader plugin compatibility, more mature tree-shaking edge-case handling) have historically lagged Rollup's, so Vite trades esbuild's raw speed for Rollup's more battle-tested, flexible production output; using native ESM plus esbuild's fast transforms in dev is fine there because dev-server responsiveness matters more than squeezing out the optimal final bundle shape",[28,1834,1836,1838],{"className":1835},[31],[33,1837],{"disabled":35,"type":36}," esbuild is a CSS-only tool and cannot process JavaScript at all",[28,1840,1842,1844],{"className":1841},[31],[33,1843],{"disabled":35,"type":36}," Rollup is required because esbuild is fundamentally incapable of running inside a Node.js process",[28,1846,1848,1850],{"className":1847},[31],[33,1849],{"disabled":35,"type":36}," The two tools always produce byte-for-byte identical output, so the choice between them is arbitrary either way",[57,1852,1853,1855,1860],{},[60,1854,62],{},[64,1856,1857,1859],{},[67,1858,69],{}," A — esbuild's plugin ecosystem and fine-grained output control (advanced code-splitting strategies, broader plugin compatibility, more mature tree-shaking edge-case handling) have historically lagged Rollup's, so Vite trades esbuild's raw speed for Rollup's more battle-tested, flexible production output; using native ESM plus esbuild's fast transforms in dev is fine there because dev-server responsiveness matters more than squeezing out the optimal final bundle shape",[64,1861,1862,552,1864,1866,1867,1869,1870,1873],{},[67,1863,75],{},[67,1865,767],{}," — This is a genuine, deliberate design trade-off in Vite's architecture: development mode optimizes for near-instant server start and updates (esbuild transforms individual files on the fly, and the browser handles module resolution natively via ESM ",[78,1868,84],{},"), while a production build optimizes for the ",[565,1871,1872],{},"shape"," and correctness of the final shipped bundle, where Rollup's more mature plugin API and configurable output (chunking strategy, more thorough dead-code elimination in edge cases) matter more than raw build speed. esbuild absolutely processes JavaScript, not just CSS (ruling out B), and runs fine under Node (ruling out C) — Vite itself uses it there. The two tools do not produce identical output (ruling out D); if they did, there'd be no reason for Vite to use two different bundlers in the first place.",[14,1875,1876,1888,1918,1939,1985],{"language":16},[18,1877,1879,1880,1883,1884,1887],{"id":1878},"q19-importing-the-whole-lodash-package-published-as-commonjs-exposed-as-one-default-exported-object-typically-leaves-the-entire-library-in-the-production-bundle-while-importing-from-lodash-es-and-destructuring-lets-unused-functions-be-tree-shaken-away-why","Q19. Importing the whole ",[78,1881,1882],{},"lodash"," package (published as CommonJS, exposed as one default-exported object) typically leaves the entire library in the production bundle, while importing from ",[78,1885,1886],{},"lodash-es"," and destructuring lets unused functions be tree-shaken away. Why?",[112,1889,1890],{"language":16},[115,1891,1893],{"className":117,"code":1892,"language":16,"meta":119,"style":119},"import _ from 'lodash';\nconsole.log(_.debounce);\n",[78,1894,1895,1909],{"__ignoreMap":119},[123,1896,1897,1899,1902,1904,1907],{"class":125,"line":126},[123,1898,84],{"class":136},[123,1900,1901],{"class":147}," _ ",[123,1903,225],{"class":136},[123,1905,1906],{"class":228}," 'lodash'",[123,1908,232],{"class":147},[123,1910,1911,1913,1915],{"class":125,"line":133},[123,1912,238],{"class":147},[123,1914,241],{"class":143},[123,1916,1917],{"class":147},"(_.debounce);\n",[112,1919,1920],{"language":16},[115,1921,1923],{"className":117,"code":1922,"language":16,"meta":119,"style":119},"import { debounce } from 'lodash-es';\n",[78,1924,1925],{"__ignoreMap":119},[123,1926,1927,1929,1932,1934,1937],{"class":125,"line":126},[123,1928,84],{"class":136},[123,1930,1931],{"class":147}," { debounce } ",[123,1933,225],{"class":136},[123,1935,1936],{"class":228}," 'lodash-es'",[123,1938,232],{"class":147},[23,1940,1942,1952,1958,1979],{"className":1941},[26],[28,1943,1945,552,1947,1949,1950],{"className":1944},[31],[33,1946],{"disabled":35,"type":36},[78,1948,1886],{}," is simply a smaller library that ships fewer functions than ",[78,1951,1882],{},[28,1953,1955,1957],{"className":1954},[31],[33,1956],{"disabled":35,"type":36}," Bundlers cannot process CommonJS packages at all, so the first snippet would actually fail to build",[28,1959,1961,1963,1964,1967,1968,1971,1972,1974,1975,1978],{"className":1960},[31],[33,1962],{"disabled":35,"type":36}," CommonJS's ",[78,1965,1966],{},"module.exports = { ... }"," produces a single, dynamically-constructed export value that a bundler can't statically split apart, so ",[78,1969,1970],{},"import _ from 'lodash'"," pulls in that whole object as one indivisible unit; ",[78,1973,1886],{}," ships genuine ESM named exports per function, so the bundler's static analysis can see exactly which named export (",[78,1976,1977],{},"debounce",") is actually referenced and drop the rest",[28,1980,1982,1984],{"className":1981},[31],[33,1983],{"disabled":35,"type":36}," The difference only matters for local development builds and has no effect once a production build is generated",[57,1986,1987,1989,2002],{},[60,1988,62],{},[64,1990,1991,1993,1994,1967,1996,1971,1998,1974,2000,1978],{},[67,1992,69],{}," C — CommonJS's ",[78,1995,1966],{},[78,1997,1970],{},[78,1999,1886],{},[78,2001,1977],{},[64,2003,2004,552,2006,2008,2009,2011,2012,2015,2016,2018,2019,2022,2023,2026,2027,320,2029,2031],{},[67,2005,75],{},[67,2007,1546],{}," — This is the same underlying mechanism as Q2 and Q16, applied to a real-world library people actually hit in production. ",[78,2010,1882],{},"'s CommonJS build exports one big object literal at runtime — from the bundler's static perspective, that's an opaque value, not a set of individually analyzable bindings, so accessing ",[78,2013,2014],{},"_.debounce"," gives no static guarantee the other ~300 functions are unused. ",[78,2017,1886],{}," restructures the exact same functionality as individual ESM named exports, which ",[565,2020,2021],{},"are"," statically analyzable, so ",[78,2024,2025],{},"import { debounce } from 'lodash-es'"," lets the bundler prove every other export is dead code and drop it. ",[78,2028,1882],{},[78,2030,1886],{}," contain the same functions (ruling out A); bundlers handle CommonJS routinely, just without tree-shaking granularity (ruling out B); and this affects production bundle size specifically, since that's when tree-shaking is applied (ruling out D).",[14,2033,2034,2042,2075],{"language":16},[18,2035,2037,2038,2041],{"id":2036},"q20-after-switching-to-a-production-build-a-team-notices-their-bundle-size-barely-shrank-despite-the-app-only-using-a-handful-of-functions-from-a-large-utility-library-based-on-everything-above-which-of-the-following-is-the-least-likely-actual-cause","Q20. After switching to a production build, a team notices their bundle size barely shrank despite the app only using a handful of functions from a large utility library. Based on everything above, which of the following is the ",[67,2039,2040],{},"LEAST likely"," actual cause?",[23,2043,2045,2051,2063,2069],{"className":2044},[26],[28,2046,2048,2050],{"className":2047},[31],[33,2049],{"disabled":35,"type":36}," The library is published only as CommonJS, so its exports can't be statically split apart and tree-shaken by the bundler",[28,2052,2054,2056,2057,2059,2060,2062],{"className":2053},[31],[33,2055],{"disabled":35,"type":36}," The library's ",[78,2058,337],{}," is missing ",[78,2061,333],{}," (or declares it incorrectly), so the bundler conservatively keeps modules it can't prove are free of side effects",[28,2064,2066,2068],{"className":2065},[31],[33,2067],{"disabled":35,"type":36}," Nobody on the team actually inspected the build output with a bundle analyzer, so an earlier attempted fix may not have taken effect, or an entirely different dependency is the real source of the bloat",[28,2070,2072,2074],{"className":2071},[31],[33,2073],{"disabled":35,"type":36}," The bundler's minifier failed to rename any local variables during minification, inflating the file size",[57,2076,2077,2079,2084],{},[60,2078,62],{},[64,2080,2081,2083],{},[67,2082,69],{}," D — The bundler's minifier failed to rename any local variables during minification, inflating the file size",[64,2085,2086,2088,2089,2092,2093,2096],{},[67,2087,75],{}," Variable-renaming is a minification detail that shaves bytes off ",[565,2090,2091],{},"already-included"," code — it has essentially nothing to do with why unused exports from a library would fail to be removed from the bundle in the first place, which is squarely a tree-shaking question, not a minification one (see Q7's distinction between the two). By contrast, options A, B, and C are all genuine, common root causes of \"tree-shaking didn't work\": a CommonJS-only library defeats static analysis outright (Q2, Q19); a missing or incorrect ",[78,2094,2095],{},"sideEffects"," flag forces the bundler to keep modules it can't prove are safe to drop (Q3, Q16); and skipping verification with a real bundle analyzer (Q15) means the team is guessing rather than diagnosing, which is often itself the actual blocker to fixing the real cause.",[2098,2099,2100],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}",{"title":119,"searchDepth":133,"depth":133,"links":2102},[2103,2104,2106,2108,2109,2111,2112,2113,2114,2116,2118,2120,2121,2122,2124,2125,2127,2129,2130,2132],{"id":20,"depth":176,"text":21},{"id":94,"depth":176,"text":2105},"Q2. Why can a bundler safely remove multiply from the production bundle below, but couldn't perform the same removal if mathUtils.js used CommonJS (module.exports \u002F require) instead?",{"id":329,"depth":176,"text":2107},"Q3. What does setting \"sideEffects\": false in a library's package.json tell a bundler like webpack, and what risk does it introduce if the claim is wrong?",{"id":435,"depth":176,"text":436},{"id":487,"depth":176,"text":2110},"Q5. A production bundle ends with the line shown below, and the corresponding .map file is deployed alongside it on the public web server.",{"id":581,"depth":176,"text":582},{"id":642,"depth":176,"text":643},{"id":790,"depth":176,"text":791},{"id":841,"depth":176,"text":2115},"Q9. Two developers run npm install on different days, using only the package.json snippet below — with no package-lock.json present or committed to the repository.",{"id":1008,"depth":176,"text":2117},"Q10. A library bumps its published version from 2.4.1 straight to 3.0.0, with no other announcement. Under semantic versioning (semver) conventions, what should consumers assume?",{"id":1108,"depth":176,"text":2119},"Q11. What does a bundler typically do with the dynamic import() call below that it would not do with a static import { openModal } from '.\u002Fmodal.js' placed at the top of the file?",{"id":1257,"depth":176,"text":1258},{"id":1334,"depth":176,"text":1335},{"id":1385,"depth":176,"text":2123},"Q14. A frontend team changes the VITE_API_URL environment variable on their server after already deploying a built Vite app, expecting the running app to pick up the new URL on the next page load without a rebuild.",{"id":1496,"depth":176,"text":1497},{"id":1552,"depth":176,"text":2126},"Q16. app.js imports analytics.js purely for its side effect and never calls track. Assuming the analytics package's package.json does not set \"sideEffects\": false, what happens during tree-shaking?",{"id":1736,"depth":176,"text":2128},"Q17. A project ends up with both a package-lock.json and a pnpm-lock.yaml committed, after a teammate ran a different package manager locally by mistake. What's the practical problem?",{"id":1822,"depth":176,"text":1823},{"id":1878,"depth":176,"text":2131},"Q19. Importing the whole lodash package (published as CommonJS, exposed as one default-exported object) typically leaves the entire library in the production bundle, while importing from lodash-es and destructuring lets unused functions be tree-shaken away. Why?",{"id":2036,"depth":176,"text":2133},"Q20. After switching to a production build, a team notices their bundle size barely shrank despite the app only using a handful of functions from a large utility library. Based on everything above, which of the following is the LEAST likely actual cause?","md",{},"\u002Fjs\u002F27-tooling-and-build-systems",{"title":5,"description":119},"js\u002F27-tooling-and-build-systems","GKZ93eJ8EGk32A-cYoUodPOmwRE51IDt5_3SurByzmw",1787335397337]