[{"data":1,"prerenderedAt":2153},["ShallowReactive",2],{"page-\u002Fjs\u002F27-tooling-and-build-systems":3},{"id":4,"title":5,"body":6,"description":2146,"extension":2147,"meta":2148,"navigation":64,"path":2149,"seo":2150,"stem":2151,"__hash__":2152},"content\u002Fjs\u002F27-tooling-and-build-systems.md","JavaScript 27 — Tooling & Build Systems: npm, ESLint, Vite & Bundler Internals",{"type":7,"value":8,"toc":2136},"minimark",[9,14,19,332,336,775,779,1133,1137,1404,1408,1566,1570,1728,1732,1859,1863,1867,1948,2132],[10,11,13],"h1",{"id":12},"_27-tooling-build-systems-npm-eslint-vite-bundler-internals","27 — Tooling & Build Systems: npm, ESLint, Vite & Bundler Internals",[15,16,18],"h2",{"id":17},"npmpnpm-dependency-management","npm\u002Fpnpm: Dependency Management",[20,21,23],"code-wrapper",{"language":22},"bash",[24,25,29],"pre",{"className":26,"code":27,"language":22,"meta":28,"style":28},"language-bash shiki shiki-themes github-light github-dark","# ── npm vs pnpm vs yarn ──\n# npm: default, flat node_modules (duplicates shared deps)\n# pnpm: symlinked node_modules (saves disk, strict — no undeclared access)\n# yarn: alternate (Plug'n'Play in v2+ — no node_modules)\n\n# ── Install (saves to dependencies) ──\nnpm install express           # install + add to package.json dependencies\nnpm install -D vitest         # install as devDependency (-D)\nnpm install -g typescript     # install globally (-g)\n\n# ── Install from git ──\nnpm install github:user\u002Frepo           # from GitHub\nnpm install github:user\u002Frepo#branch    # specific branch\nnpm install git+https:\u002F\u002Fgithub.com\u002Fuser\u002Frepo.git\n\n# ── Install exact version (no ^ or ~) ──\nnpm install express@4.18.2    # exact version\nnpm install express@^4.18.0   # caret: >=4.18.0 \u003C5.0.0 (minor + patch)\nnpm install express@~4.18.0   # tilde: >=4.18.0 \u003C4.19.0 (patch only)\n\n# ── package.json scripts ──\n# \"scripts\": {\n#   \"dev\": \"vite\",\n#   \"build\": \"vite build\",\n#   \"test\": \"vitest\",\n#   \"lint\": \"eslint .\",\n#   \"format\": \"prettier --write .\"\n# }\nnpm run dev        # runs the \"dev\" script\nnpm test           # shortcut for npm run test\nnpx vite           # run a local binary without installing globally\n\n# ── lock files (npm-shrinkwrap.json, package-lock.json, pnpm-lock.yaml) ──\n# Always commit the lock file — ensures reproducible installs across machines.\n# npm ci: clean install (uses lock file, removes node_modules, faster than npm install)\n","",[30,31,32,41,47,53,59,66,72,89,106,122,127,133,146,159,169,174,180,193,206,219,224,230,236,242,248,254,260,266,272,286,297,309,314,320,326],"code",{"__ignoreMap":28},[33,34,37],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sdCPZ","# ── npm vs pnpm vs yarn ──\n",[33,42,44],{"class":35,"line":43},2,[33,45,46],{"class":39},"# npm: default, flat node_modules (duplicates shared deps)\n",[33,48,50],{"class":35,"line":49},3,[33,51,52],{"class":39},"# pnpm: symlinked node_modules (saves disk, strict — no undeclared access)\n",[33,54,56],{"class":35,"line":55},4,[33,57,58],{"class":39},"# yarn: alternate (Plug'n'Play in v2+ — no node_modules)\n",[33,60,62],{"class":35,"line":61},5,[33,63,65],{"emptyLinePlaceholder":64},true,"\n",[33,67,69],{"class":35,"line":68},6,[33,70,71],{"class":39},"# ── Install (saves to dependencies) ──\n",[33,73,75,79,83,86],{"class":35,"line":74},7,[33,76,78],{"class":77},"sIsaT","npm",[33,80,82],{"class":81},"sJ6F3"," install",[33,84,85],{"class":81}," express",[33,87,88],{"class":39},"           # install + add to package.json dependencies\n",[33,90,92,94,96,100,103],{"class":35,"line":91},8,[33,93,78],{"class":77},[33,95,82],{"class":81},[33,97,99],{"class":98},"snvgF"," -D",[33,101,102],{"class":81}," vitest",[33,104,105],{"class":39},"         # install as devDependency (-D)\n",[33,107,109,111,113,116,119],{"class":35,"line":108},9,[33,110,78],{"class":77},[33,112,82],{"class":81},[33,114,115],{"class":98}," -g",[33,117,118],{"class":81}," typescript",[33,120,121],{"class":39},"     # install globally (-g)\n",[33,123,125],{"class":35,"line":124},10,[33,126,65],{"emptyLinePlaceholder":64},[33,128,130],{"class":35,"line":129},11,[33,131,132],{"class":39},"# ── Install from git ──\n",[33,134,136,138,140,143],{"class":35,"line":135},12,[33,137,78],{"class":77},[33,139,82],{"class":81},[33,141,142],{"class":81}," github:user\u002Frepo",[33,144,145],{"class":39},"           # from GitHub\n",[33,147,149,151,153,156],{"class":35,"line":148},13,[33,150,78],{"class":77},[33,152,82],{"class":81},[33,154,155],{"class":81}," github:user\u002Frepo#branch",[33,157,158],{"class":39},"    # specific branch\n",[33,160,162,164,166],{"class":35,"line":161},14,[33,163,78],{"class":77},[33,165,82],{"class":81},[33,167,168],{"class":81}," git+https:\u002F\u002Fgithub.com\u002Fuser\u002Frepo.git\n",[33,170,172],{"class":35,"line":171},15,[33,173,65],{"emptyLinePlaceholder":64},[33,175,177],{"class":35,"line":176},16,[33,178,179],{"class":39},"# ── Install exact version (no ^ or ~) ──\n",[33,181,183,185,187,190],{"class":35,"line":182},17,[33,184,78],{"class":77},[33,186,82],{"class":81},[33,188,189],{"class":81}," express@4.18.2",[33,191,192],{"class":39},"    # exact version\n",[33,194,196,198,200,203],{"class":35,"line":195},18,[33,197,78],{"class":77},[33,199,82],{"class":81},[33,201,202],{"class":81}," express@^4.18.0",[33,204,205],{"class":39},"   # caret: >=4.18.0 \u003C5.0.0 (minor + patch)\n",[33,207,209,211,213,216],{"class":35,"line":208},19,[33,210,78],{"class":77},[33,212,82],{"class":81},[33,214,215],{"class":81}," express@~4.18.0",[33,217,218],{"class":39},"   # tilde: >=4.18.0 \u003C4.19.0 (patch only)\n",[33,220,222],{"class":35,"line":221},20,[33,223,65],{"emptyLinePlaceholder":64},[33,225,227],{"class":35,"line":226},21,[33,228,229],{"class":39},"# ── package.json scripts ──\n",[33,231,233],{"class":35,"line":232},22,[33,234,235],{"class":39},"# \"scripts\": {\n",[33,237,239],{"class":35,"line":238},23,[33,240,241],{"class":39},"#   \"dev\": \"vite\",\n",[33,243,245],{"class":35,"line":244},24,[33,246,247],{"class":39},"#   \"build\": \"vite build\",\n",[33,249,251],{"class":35,"line":250},25,[33,252,253],{"class":39},"#   \"test\": \"vitest\",\n",[33,255,257],{"class":35,"line":256},26,[33,258,259],{"class":39},"#   \"lint\": \"eslint .\",\n",[33,261,263],{"class":35,"line":262},27,[33,264,265],{"class":39},"#   \"format\": \"prettier --write .\"\n",[33,267,269],{"class":35,"line":268},28,[33,270,271],{"class":39},"# }\n",[33,273,275,277,280,283],{"class":35,"line":274},29,[33,276,78],{"class":77},[33,278,279],{"class":81}," run",[33,281,282],{"class":81}," dev",[33,284,285],{"class":39},"        # runs the \"dev\" script\n",[33,287,289,291,294],{"class":35,"line":288},30,[33,290,78],{"class":77},[33,292,293],{"class":81}," test",[33,295,296],{"class":39},"           # shortcut for npm run test\n",[33,298,300,303,306],{"class":35,"line":299},31,[33,301,302],{"class":77},"npx",[33,304,305],{"class":81}," vite",[33,307,308],{"class":39},"           # run a local binary without installing globally\n",[33,310,312],{"class":35,"line":311},32,[33,313,65],{"emptyLinePlaceholder":64},[33,315,317],{"class":35,"line":316},33,[33,318,319],{"class":39},"# ── lock files (npm-shrinkwrap.json, package-lock.json, pnpm-lock.yaml) ──\n",[33,321,323],{"class":35,"line":322},34,[33,324,325],{"class":39},"# Always commit the lock file — ensures reproducible installs across machines.\n",[33,327,329],{"class":35,"line":328},35,[33,330,331],{"class":39},"# npm ci: clean install (uses lock file, removes node_modules, faster than npm install)\n",[15,333,335],{"id":334},"eslint-configuration-and-rules","ESLint: Configuration and Rules",[20,337,339],{"language":338},"javascript",[24,340,343],{"className":341,"code":342,"language":338,"meta":28,"style":28},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F ── eslint.config.js (flat config — ESLint 9+) ──\nimport js from \"@eslint\u002Fjs\";\nimport globals from \"globals\";\n\nexport default [\n    js.configs.recommended,  \u002F\u002F base recommended rules\n    {\n        files: [\"**\u002F*.js\"],\n        languageOptions: {\n            globals: { ...globals.browser, ...globals.node },  \u002F\u002F browser + Node globals\n            ecmaVersion: 2024,\n            sourceType: \"module\",  \u002F\u002F ESM\n        },\n        rules: {\n            \"no-unused-vars\": [\"warn\", { argsIgnorePattern: \"^_\" }],  \u002F\u002F warn, ignore _-prefixed\n            \"no-console\": [\"warn\", { allow: [\"warn\", \"error\"] }],  \u002F\u002F warn on console.log\n            \"eqeqeq\": [\"error\", \"always\", { null: \"ignore\" }],  \u002F\u002F === only (except == null)\n            \"no-undef\": \"error\",  \u002F\u002F error on undeclared variables\n            \"prefer-const\": \"error\",  \u002F\u002F error if let can be const\n            \"no-var\": \"error\",  \u002F\u002F error on var (use let\u002Fconst)\n            \"arrow-spacing\": \"error\",  \u002F\u002F enforce spaces in arrow functions\n            \"no-duplicate-imports\": \"error\",  \u002F\u002F combine imports\n            \"no-return-await\": \"off\",  \u002F\u002F allow return await (for finally blocks)\n        },\n    },\n    {\n        files: [\"**\u002F*.test.js\"],  \u002F\u002F relaxed rules for test files\n        rules: {\n            \"no-console\": \"off\",  \u002F\u002F allow console.log in tests\n        },\n    },\n    {\n        ignores: [\"dist\u002F**\", \"node_modules\u002F**\", \"coverage\u002F**\"],  \u002F\u002F exclude\n    },\n];\n\n\u002F\u002F ── Key ESLint rules for production ──\n\u002F\u002F eqeqeq: enforce === (prevent == coercion bugs)\n\u002F\u002F no-unused-vars: catch unused variables (dead code)\n\u002F\u002F prefer-const: catch let that should be const\n\u002F\u002F no-var: prevent var (use let\u002Fconst for block scoping)\n\u002F\u002F no-throw-literal: must throw Error objects (not strings)\n\u002F\u002F no-return-await: return await vs return Promise (minor perf, but better stack traces)\n",[30,344,345,350,369,383,387,398,406,411,422,427,446,457,471,476,481,504,530,555,570,584,598,612,626,641,645,650,654,667,671,684,688,692,696,719,723,728,733,739,745,751,757,763,769],{"__ignoreMap":28},[33,346,347],{"class":35,"line":36},[33,348,349],{"class":39},"\u002F\u002F ── eslint.config.js (flat config — ESLint 9+) ──\n",[33,351,352,356,360,363,366],{"class":35,"line":43},[33,353,355],{"class":354},"svdQ7","import",[33,357,359],{"class":358},"ssxIu"," js ",[33,361,362],{"class":354},"from",[33,364,365],{"class":81}," \"@eslint\u002Fjs\"",[33,367,368],{"class":358},";\n",[33,370,371,373,376,378,381],{"class":35,"line":49},[33,372,355],{"class":354},[33,374,375],{"class":358}," globals ",[33,377,362],{"class":354},[33,379,380],{"class":81}," \"globals\"",[33,382,368],{"class":358},[33,384,385],{"class":35,"line":55},[33,386,65],{"emptyLinePlaceholder":64},[33,388,389,392,395],{"class":35,"line":61},[33,390,391],{"class":354},"export",[33,393,394],{"class":354}," default",[33,396,397],{"class":358}," [\n",[33,399,400,403],{"class":35,"line":68},[33,401,402],{"class":358},"    js.configs.recommended,  ",[33,404,405],{"class":39},"\u002F\u002F base recommended rules\n",[33,407,408],{"class":35,"line":74},[33,409,410],{"class":358},"    {\n",[33,412,413,416,419],{"class":35,"line":91},[33,414,415],{"class":358},"        files: [",[33,417,418],{"class":81},"\"**\u002F*.js\"",[33,420,421],{"class":358},"],\n",[33,423,424],{"class":35,"line":108},[33,425,426],{"class":358},"        languageOptions: {\n",[33,428,429,432,435,438,440,443],{"class":35,"line":124},[33,430,431],{"class":358},"            globals: { ",[33,433,434],{"class":354},"...",[33,436,437],{"class":358},"globals.browser, ",[33,439,434],{"class":354},[33,441,442],{"class":358},"globals.node },  ",[33,444,445],{"class":39},"\u002F\u002F browser + Node globals\n",[33,447,448,451,454],{"class":35,"line":129},[33,449,450],{"class":358},"            ecmaVersion: ",[33,452,453],{"class":98},"2024",[33,455,456],{"class":358},",\n",[33,458,459,462,465,468],{"class":35,"line":135},[33,460,461],{"class":358},"            sourceType: ",[33,463,464],{"class":81},"\"module\"",[33,466,467],{"class":358},",  ",[33,469,470],{"class":39},"\u002F\u002F ESM\n",[33,472,473],{"class":35,"line":148},[33,474,475],{"class":358},"        },\n",[33,477,478],{"class":35,"line":161},[33,479,480],{"class":358},"        rules: {\n",[33,482,483,486,489,492,495,498,501],{"class":35,"line":171},[33,484,485],{"class":81},"            \"no-unused-vars\"",[33,487,488],{"class":358},": [",[33,490,491],{"class":81},"\"warn\"",[33,493,494],{"class":358},", { argsIgnorePattern: ",[33,496,497],{"class":81},"\"^_\"",[33,499,500],{"class":358}," }],  ",[33,502,503],{"class":39},"\u002F\u002F warn, ignore _-prefixed\n",[33,505,506,509,511,513,516,518,521,524,527],{"class":35,"line":176},[33,507,508],{"class":81},"            \"no-console\"",[33,510,488],{"class":358},[33,512,491],{"class":81},[33,514,515],{"class":358},", { allow: [",[33,517,491],{"class":81},[33,519,520],{"class":358},", ",[33,522,523],{"class":81},"\"error\"",[33,525,526],{"class":358},"] }],  ",[33,528,529],{"class":39},"\u002F\u002F warn on console.log\n",[33,531,532,535,537,539,541,544,547,550,552],{"class":35,"line":182},[33,533,534],{"class":81},"            \"eqeqeq\"",[33,536,488],{"class":358},[33,538,523],{"class":81},[33,540,520],{"class":358},[33,542,543],{"class":81},"\"always\"",[33,545,546],{"class":358},", { null: ",[33,548,549],{"class":81},"\"ignore\"",[33,551,500],{"class":358},[33,553,554],{"class":39},"\u002F\u002F === only (except == null)\n",[33,556,557,560,563,565,567],{"class":35,"line":195},[33,558,559],{"class":81},"            \"no-undef\"",[33,561,562],{"class":358},": ",[33,564,523],{"class":81},[33,566,467],{"class":358},[33,568,569],{"class":39},"\u002F\u002F error on undeclared variables\n",[33,571,572,575,577,579,581],{"class":35,"line":208},[33,573,574],{"class":81},"            \"prefer-const\"",[33,576,562],{"class":358},[33,578,523],{"class":81},[33,580,467],{"class":358},[33,582,583],{"class":39},"\u002F\u002F error if let can be const\n",[33,585,586,589,591,593,595],{"class":35,"line":221},[33,587,588],{"class":81},"            \"no-var\"",[33,590,562],{"class":358},[33,592,523],{"class":81},[33,594,467],{"class":358},[33,596,597],{"class":39},"\u002F\u002F error on var (use let\u002Fconst)\n",[33,599,600,603,605,607,609],{"class":35,"line":226},[33,601,602],{"class":81},"            \"arrow-spacing\"",[33,604,562],{"class":358},[33,606,523],{"class":81},[33,608,467],{"class":358},[33,610,611],{"class":39},"\u002F\u002F enforce spaces in arrow functions\n",[33,613,614,617,619,621,623],{"class":35,"line":232},[33,615,616],{"class":81},"            \"no-duplicate-imports\"",[33,618,562],{"class":358},[33,620,523],{"class":81},[33,622,467],{"class":358},[33,624,625],{"class":39},"\u002F\u002F combine imports\n",[33,627,628,631,633,636,638],{"class":35,"line":238},[33,629,630],{"class":81},"            \"no-return-await\"",[33,632,562],{"class":358},[33,634,635],{"class":81},"\"off\"",[33,637,467],{"class":358},[33,639,640],{"class":39},"\u002F\u002F allow return await (for finally blocks)\n",[33,642,643],{"class":35,"line":244},[33,644,475],{"class":358},[33,646,647],{"class":35,"line":250},[33,648,649],{"class":358},"    },\n",[33,651,652],{"class":35,"line":256},[33,653,410],{"class":358},[33,655,656,658,661,664],{"class":35,"line":262},[33,657,415],{"class":358},[33,659,660],{"class":81},"\"**\u002F*.test.js\"",[33,662,663],{"class":358},"],  ",[33,665,666],{"class":39},"\u002F\u002F relaxed rules for test files\n",[33,668,669],{"class":35,"line":268},[33,670,480],{"class":358},[33,672,673,675,677,679,681],{"class":35,"line":274},[33,674,508],{"class":81},[33,676,562],{"class":358},[33,678,635],{"class":81},[33,680,467],{"class":358},[33,682,683],{"class":39},"\u002F\u002F allow console.log in tests\n",[33,685,686],{"class":35,"line":288},[33,687,475],{"class":358},[33,689,690],{"class":35,"line":299},[33,691,649],{"class":358},[33,693,694],{"class":35,"line":311},[33,695,410],{"class":358},[33,697,698,701,704,706,709,711,714,716],{"class":35,"line":316},[33,699,700],{"class":358},"        ignores: [",[33,702,703],{"class":81},"\"dist\u002F**\"",[33,705,520],{"class":358},[33,707,708],{"class":81},"\"node_modules\u002F**\"",[33,710,520],{"class":358},[33,712,713],{"class":81},"\"coverage\u002F**\"",[33,715,663],{"class":358},[33,717,718],{"class":39},"\u002F\u002F exclude\n",[33,720,721],{"class":35,"line":322},[33,722,649],{"class":358},[33,724,725],{"class":35,"line":328},[33,726,727],{"class":358},"];\n",[33,729,731],{"class":35,"line":730},36,[33,732,65],{"emptyLinePlaceholder":64},[33,734,736],{"class":35,"line":735},37,[33,737,738],{"class":39},"\u002F\u002F ── Key ESLint rules for production ──\n",[33,740,742],{"class":35,"line":741},38,[33,743,744],{"class":39},"\u002F\u002F eqeqeq: enforce === (prevent == coercion bugs)\n",[33,746,748],{"class":35,"line":747},39,[33,749,750],{"class":39},"\u002F\u002F no-unused-vars: catch unused variables (dead code)\n",[33,752,754],{"class":35,"line":753},40,[33,755,756],{"class":39},"\u002F\u002F prefer-const: catch let that should be const\n",[33,758,760],{"class":35,"line":759},41,[33,761,762],{"class":39},"\u002F\u002F no-var: prevent var (use let\u002Fconst for block scoping)\n",[33,764,766],{"class":35,"line":765},42,[33,767,768],{"class":39},"\u002F\u002F no-throw-literal: must throw Error objects (not strings)\n",[33,770,772],{"class":35,"line":771},43,[33,773,774],{"class":39},"\u002F\u002F no-return-await: return await vs return Promise (minor perf, but better stack traces)\n",[15,776,778],{"id":777},"vite-dev-server-and-build-internals","Vite: Dev Server and Build Internals",[20,780,781],{"language":338},[24,782,784],{"className":341,"code":783,"language":338,"meta":28,"style":28},"\u002F\u002F ── Vite architecture: esbuild for dev, Rollup for production ──\n\u002F\u002F\n\u002F\u002F DEV MODE (vite dev):\n\u002F\u002F   - Native ESM: serves modules directly to the browser (no bundling)\n\u002F\u002F   - esbuild: transpiles TypeScript\u002FJSX on the fly (very fast — Go-based)\n\u002F\u002F   - HMR (Hot Module Replacement): updates changed modules without full reload\n\u002F\u002F   - Dependencies are pre-bundled with esbuild (node_modules → single optimized chunk)\n\u002F\u002F\n\u002F\u002F PRODUCTION MODE (vite build):\n\u002F\u002F   - Rollup: bundles the app into optimized chunks (tree-shaking, code splitting)\n\u002F\u002F   - Minification: esbuild or terser (esbuild is faster, terser is smaller)\n\u002F\u002F   - CSS: extracted and minified\n\u002F\u002F   - Assets: images, fonts inlined or emitted as files\n\n\u002F\u002F ── vite.config.js ──\nimport { defineConfig } from \"vite\";\nimport react from \"@vitejs\u002Fplugin-react\";\n\nexport default defineConfig({\n    plugins: [react()],  \u002F\u002F React support (JSX, Fast Refresh)\n    resolve: {\n        alias: {\n            \"@\": \"\u002Fsrc\",  \u002F\u002F import from \"@\u002Fcomponents\u002F...\" → \u002Fsrc\u002Fcomponents\u002F...\n        },\n    },\n    build: {\n        target: \"es2022\",  \u002F\u002F output target (browsers that support ES2022)\n        outDir: \"dist\",\n        minify: \"esbuild\",  \u002F\u002F \"esbuild\" (fast) or \"terser\" (smaller) or false\n        sourcemap: true,     \u002F\u002F emit source maps\n        rollupOptions: {\n            output: {\n                manualChunks: {  \u002F\u002F manual code splitting\n                    \"react-vendor\": [\"react\", \"react-dom\"],\n                    \"utils\": [\"lodash\", \"dayjs\"],\n                },\n            },\n        },\n    },\n    server: {\n        port: 3000,\n        proxy: {  \u002F\u002F dev proxy (avoid CORS during development)\n            \"\u002Fapi\": { target: \"http:\u002F\u002Flocalhost:8080\", changeOrigin: true },\n        },\n    },\n});\n",[30,785,786,791,796,801,806,811,816,821,825,830,835,840,845,850,854,859,873,887,891,903,917,922,927,942,946,950,955,968,978,991,1005,1010,1015,1023,1040,1057,1062,1067,1071,1075,1080,1090,1098,1117,1122,1127],{"__ignoreMap":28},[33,787,788],{"class":35,"line":36},[33,789,790],{"class":39},"\u002F\u002F ── Vite architecture: esbuild for dev, Rollup for production ──\n",[33,792,793],{"class":35,"line":43},[33,794,795],{"class":39},"\u002F\u002F\n",[33,797,798],{"class":35,"line":49},[33,799,800],{"class":39},"\u002F\u002F DEV MODE (vite dev):\n",[33,802,803],{"class":35,"line":55},[33,804,805],{"class":39},"\u002F\u002F   - Native ESM: serves modules directly to the browser (no bundling)\n",[33,807,808],{"class":35,"line":61},[33,809,810],{"class":39},"\u002F\u002F   - esbuild: transpiles TypeScript\u002FJSX on the fly (very fast — Go-based)\n",[33,812,813],{"class":35,"line":68},[33,814,815],{"class":39},"\u002F\u002F   - HMR (Hot Module Replacement): updates changed modules without full reload\n",[33,817,818],{"class":35,"line":74},[33,819,820],{"class":39},"\u002F\u002F   - Dependencies are pre-bundled with esbuild (node_modules → single optimized chunk)\n",[33,822,823],{"class":35,"line":91},[33,824,795],{"class":39},[33,826,827],{"class":35,"line":108},[33,828,829],{"class":39},"\u002F\u002F PRODUCTION MODE (vite build):\n",[33,831,832],{"class":35,"line":124},[33,833,834],{"class":39},"\u002F\u002F   - Rollup: bundles the app into optimized chunks (tree-shaking, code splitting)\n",[33,836,837],{"class":35,"line":129},[33,838,839],{"class":39},"\u002F\u002F   - Minification: esbuild or terser (esbuild is faster, terser is smaller)\n",[33,841,842],{"class":35,"line":135},[33,843,844],{"class":39},"\u002F\u002F   - CSS: extracted and minified\n",[33,846,847],{"class":35,"line":148},[33,848,849],{"class":39},"\u002F\u002F   - Assets: images, fonts inlined or emitted as files\n",[33,851,852],{"class":35,"line":161},[33,853,65],{"emptyLinePlaceholder":64},[33,855,856],{"class":35,"line":171},[33,857,858],{"class":39},"\u002F\u002F ── vite.config.js ──\n",[33,860,861,863,866,868,871],{"class":35,"line":176},[33,862,355],{"class":354},[33,864,865],{"class":358}," { defineConfig } ",[33,867,362],{"class":354},[33,869,870],{"class":81}," \"vite\"",[33,872,368],{"class":358},[33,874,875,877,880,882,885],{"class":35,"line":182},[33,876,355],{"class":354},[33,878,879],{"class":358}," react ",[33,881,362],{"class":354},[33,883,884],{"class":81}," \"@vitejs\u002Fplugin-react\"",[33,886,368],{"class":358},[33,888,889],{"class":35,"line":195},[33,890,65],{"emptyLinePlaceholder":64},[33,892,893,895,897,900],{"class":35,"line":208},[33,894,391],{"class":354},[33,896,394],{"class":354},[33,898,899],{"class":77}," defineConfig",[33,901,902],{"class":358},"({\n",[33,904,905,908,911,914],{"class":35,"line":221},[33,906,907],{"class":358},"    plugins: [",[33,909,910],{"class":77},"react",[33,912,913],{"class":358},"()],  ",[33,915,916],{"class":39},"\u002F\u002F React support (JSX, Fast Refresh)\n",[33,918,919],{"class":35,"line":226},[33,920,921],{"class":358},"    resolve: {\n",[33,923,924],{"class":35,"line":232},[33,925,926],{"class":358},"        alias: {\n",[33,928,929,932,934,937,939],{"class":35,"line":238},[33,930,931],{"class":81},"            \"@\"",[33,933,562],{"class":358},[33,935,936],{"class":81},"\"\u002Fsrc\"",[33,938,467],{"class":358},[33,940,941],{"class":39},"\u002F\u002F import from \"@\u002Fcomponents\u002F...\" → \u002Fsrc\u002Fcomponents\u002F...\n",[33,943,944],{"class":35,"line":244},[33,945,475],{"class":358},[33,947,948],{"class":35,"line":250},[33,949,649],{"class":358},[33,951,952],{"class":35,"line":256},[33,953,954],{"class":358},"    build: {\n",[33,956,957,960,963,965],{"class":35,"line":262},[33,958,959],{"class":358},"        target: ",[33,961,962],{"class":81},"\"es2022\"",[33,964,467],{"class":358},[33,966,967],{"class":39},"\u002F\u002F output target (browsers that support ES2022)\n",[33,969,970,973,976],{"class":35,"line":268},[33,971,972],{"class":358},"        outDir: ",[33,974,975],{"class":81},"\"dist\"",[33,977,456],{"class":358},[33,979,980,983,986,988],{"class":35,"line":274},[33,981,982],{"class":358},"        minify: ",[33,984,985],{"class":81},"\"esbuild\"",[33,987,467],{"class":358},[33,989,990],{"class":39},"\u002F\u002F \"esbuild\" (fast) or \"terser\" (smaller) or false\n",[33,992,993,996,999,1002],{"class":35,"line":288},[33,994,995],{"class":358},"        sourcemap: ",[33,997,998],{"class":98},"true",[33,1000,1001],{"class":358},",     ",[33,1003,1004],{"class":39},"\u002F\u002F emit source maps\n",[33,1006,1007],{"class":35,"line":299},[33,1008,1009],{"class":358},"        rollupOptions: {\n",[33,1011,1012],{"class":35,"line":311},[33,1013,1014],{"class":358},"            output: {\n",[33,1016,1017,1020],{"class":35,"line":316},[33,1018,1019],{"class":358},"                manualChunks: {  ",[33,1021,1022],{"class":39},"\u002F\u002F manual code splitting\n",[33,1024,1025,1028,1030,1033,1035,1038],{"class":35,"line":322},[33,1026,1027],{"class":81},"                    \"react-vendor\"",[33,1029,488],{"class":358},[33,1031,1032],{"class":81},"\"react\"",[33,1034,520],{"class":358},[33,1036,1037],{"class":81},"\"react-dom\"",[33,1039,421],{"class":358},[33,1041,1042,1045,1047,1050,1052,1055],{"class":35,"line":328},[33,1043,1044],{"class":81},"                    \"utils\"",[33,1046,488],{"class":358},[33,1048,1049],{"class":81},"\"lodash\"",[33,1051,520],{"class":358},[33,1053,1054],{"class":81},"\"dayjs\"",[33,1056,421],{"class":358},[33,1058,1059],{"class":35,"line":730},[33,1060,1061],{"class":358},"                },\n",[33,1063,1064],{"class":35,"line":735},[33,1065,1066],{"class":358},"            },\n",[33,1068,1069],{"class":35,"line":741},[33,1070,475],{"class":358},[33,1072,1073],{"class":35,"line":747},[33,1074,649],{"class":358},[33,1076,1077],{"class":35,"line":753},[33,1078,1079],{"class":358},"    server: {\n",[33,1081,1082,1085,1088],{"class":35,"line":759},[33,1083,1084],{"class":358},"        port: ",[33,1086,1087],{"class":98},"3000",[33,1089,456],{"class":358},[33,1091,1092,1095],{"class":35,"line":765},[33,1093,1094],{"class":358},"        proxy: {  ",[33,1096,1097],{"class":39},"\u002F\u002F dev proxy (avoid CORS during development)\n",[33,1099,1100,1103,1106,1109,1112,1114],{"class":35,"line":771},[33,1101,1102],{"class":81},"            \"\u002Fapi\"",[33,1104,1105],{"class":358},": { target: ",[33,1107,1108],{"class":81},"\"http:\u002F\u002Flocalhost:8080\"",[33,1110,1111],{"class":358},", changeOrigin: ",[33,1113,998],{"class":98},[33,1115,1116],{"class":358}," },\n",[33,1118,1120],{"class":35,"line":1119},44,[33,1121,475],{"class":358},[33,1123,1125],{"class":35,"line":1124},45,[33,1126,649],{"class":358},[33,1128,1130],{"class":35,"line":1129},46,[33,1131,1132],{"class":358},"});\n",[15,1134,1136],{"id":1135},"tree-shaking-and-code-splitting","Tree-Shaking and Code Splitting",[20,1138,1139],{"language":338},[24,1140,1142],{"className":341,"code":1141,"language":338,"meta":28,"style":28},"\u002F\u002F ── Tree-shaking: bundler removes unused exports (dead code elimination) ──\n\u002F\u002F Only works with ESM (static import\u002Fexport — analyzable at build time).\n\u002F\u002F CommonJS (require) can't be tree-shaken (require is dynamic — can't analyze statically).\n\n\u002F\u002F ── ESM (tree-shakeable) ──\n\u002F\u002F math.js:\nexport const add = (a, b) => a + b;\nexport const subtract = (a, b) => a - b;  \u002F\u002F unused by app → tree-shaken (removed)\n\u002F\u002F app.js:\nimport { add } from \".\u002Fmath.js\";  \u002F\u002F only `add` is bundled (subtract is removed)\n\n\u002F\u002F ── Side effects in modules can prevent tree-shaking ──\n\u002F\u002F If a module has side effects (top-level code that modifies global state),\n\u002F\u002F the bundler can't safely remove it even if its exports are unused.\n\u002F\u002F package.json: \"sideEffects\": false  → tell the bundler this package has no side effects\n\u002F\u002F \"sideEffects\": [\".\u002Fpolyfill.js\"]  → except this file (has side effects)\n\n\u002F\u002F ── Code splitting: load code on demand (reduce initial bundle) ──\n\u002F\u002F Static import: loaded immediately (part of the initial bundle)\nimport { critical } from \".\u002Fcritical.js\";\n\n\u002F\u002F Dynamic import: loaded on demand (separate chunk — lazy loaded)\nconst lazyModule = await import(\".\u002Fheavy-feature.js\");\n\u002F\u002F Vite\u002FRollup creates a separate chunk for heavy-feature.js (loaded when import() runs)\n\n\u002F\u002F ── Manual chunks (vendor splitting) ──\n\u002F\u002F vite.config.js: rollupOptions.output.manualChunks\n\u002F\u002F Splits large vendor libs (react, lodash) into separate chunks (cached independently)\n\n\u002F\u002F ── Prefetch and preload hints ──\n\u002F\u002F \u003Clink rel=\"modulepreload\" href=\"\u002Fchunk.js\">  → load early (high priority, for critical chunks)\n\u002F\u002F \u003Clink rel=\"prefetch\" href=\"\u002Flazy.js\">        → load when idle (low priority, for future navigation)\n",[30,1143,1144,1149,1154,1159,1163,1168,1173,1213,1247,1252,1270,1274,1279,1284,1289,1294,1299,1303,1308,1313,1327,1331,1336,1361,1366,1370,1375,1380,1385,1389,1394,1399],{"__ignoreMap":28},[33,1145,1146],{"class":35,"line":36},[33,1147,1148],{"class":39},"\u002F\u002F ── Tree-shaking: bundler removes unused exports (dead code elimination) ──\n",[33,1150,1151],{"class":35,"line":43},[33,1152,1153],{"class":39},"\u002F\u002F Only works with ESM (static import\u002Fexport — analyzable at build time).\n",[33,1155,1156],{"class":35,"line":49},[33,1157,1158],{"class":39},"\u002F\u002F CommonJS (require) can't be tree-shaken (require is dynamic — can't analyze statically).\n",[33,1160,1161],{"class":35,"line":55},[33,1162,65],{"emptyLinePlaceholder":64},[33,1164,1165],{"class":35,"line":61},[33,1166,1167],{"class":39},"\u002F\u002F ── ESM (tree-shakeable) ──\n",[33,1169,1170],{"class":35,"line":68},[33,1171,1172],{"class":39},"\u002F\u002F math.js:\n",[33,1174,1175,1177,1180,1183,1186,1189,1193,1195,1198,1201,1204,1207,1210],{"class":35,"line":74},[33,1176,391],{"class":354},[33,1178,1179],{"class":354}," const",[33,1181,1182],{"class":77}," add",[33,1184,1185],{"class":354}," =",[33,1187,1188],{"class":358}," (",[33,1190,1192],{"class":1191},"sCrzJ","a",[33,1194,520],{"class":358},[33,1196,1197],{"class":1191},"b",[33,1199,1200],{"class":358},") ",[33,1202,1203],{"class":354},"=>",[33,1205,1206],{"class":358}," a ",[33,1208,1209],{"class":354},"+",[33,1211,1212],{"class":358}," b;\n",[33,1214,1215,1217,1219,1222,1224,1226,1228,1230,1232,1234,1236,1238,1241,1244],{"class":35,"line":91},[33,1216,391],{"class":354},[33,1218,1179],{"class":354},[33,1220,1221],{"class":77}," subtract",[33,1223,1185],{"class":354},[33,1225,1188],{"class":358},[33,1227,1192],{"class":1191},[33,1229,520],{"class":358},[33,1231,1197],{"class":1191},[33,1233,1200],{"class":358},[33,1235,1203],{"class":354},[33,1237,1206],{"class":358},[33,1239,1240],{"class":354},"-",[33,1242,1243],{"class":358}," b;  ",[33,1245,1246],{"class":39},"\u002F\u002F unused by app → tree-shaken (removed)\n",[33,1248,1249],{"class":35,"line":108},[33,1250,1251],{"class":39},"\u002F\u002F app.js:\n",[33,1253,1254,1256,1259,1261,1264,1267],{"class":35,"line":124},[33,1255,355],{"class":354},[33,1257,1258],{"class":358}," { add } ",[33,1260,362],{"class":354},[33,1262,1263],{"class":81}," \".\u002Fmath.js\"",[33,1265,1266],{"class":358},";  ",[33,1268,1269],{"class":39},"\u002F\u002F only `add` is bundled (subtract is removed)\n",[33,1271,1272],{"class":35,"line":129},[33,1273,65],{"emptyLinePlaceholder":64},[33,1275,1276],{"class":35,"line":135},[33,1277,1278],{"class":39},"\u002F\u002F ── Side effects in modules can prevent tree-shaking ──\n",[33,1280,1281],{"class":35,"line":148},[33,1282,1283],{"class":39},"\u002F\u002F If a module has side effects (top-level code that modifies global state),\n",[33,1285,1286],{"class":35,"line":161},[33,1287,1288],{"class":39},"\u002F\u002F the bundler can't safely remove it even if its exports are unused.\n",[33,1290,1291],{"class":35,"line":171},[33,1292,1293],{"class":39},"\u002F\u002F package.json: \"sideEffects\": false  → tell the bundler this package has no side effects\n",[33,1295,1296],{"class":35,"line":176},[33,1297,1298],{"class":39},"\u002F\u002F \"sideEffects\": [\".\u002Fpolyfill.js\"]  → except this file (has side effects)\n",[33,1300,1301],{"class":35,"line":182},[33,1302,65],{"emptyLinePlaceholder":64},[33,1304,1305],{"class":35,"line":195},[33,1306,1307],{"class":39},"\u002F\u002F ── Code splitting: load code on demand (reduce initial bundle) ──\n",[33,1309,1310],{"class":35,"line":208},[33,1311,1312],{"class":39},"\u002F\u002F Static import: loaded immediately (part of the initial bundle)\n",[33,1314,1315,1317,1320,1322,1325],{"class":35,"line":221},[33,1316,355],{"class":354},[33,1318,1319],{"class":358}," { critical } ",[33,1321,362],{"class":354},[33,1323,1324],{"class":81}," \".\u002Fcritical.js\"",[33,1326,368],{"class":358},[33,1328,1329],{"class":35,"line":226},[33,1330,65],{"emptyLinePlaceholder":64},[33,1332,1333],{"class":35,"line":232},[33,1334,1335],{"class":39},"\u002F\u002F Dynamic import: loaded on demand (separate chunk — lazy loaded)\n",[33,1337,1338,1341,1344,1346,1349,1352,1355,1358],{"class":35,"line":238},[33,1339,1340],{"class":354},"const",[33,1342,1343],{"class":98}," lazyModule",[33,1345,1185],{"class":354},[33,1347,1348],{"class":354}," await",[33,1350,1351],{"class":354}," import",[33,1353,1354],{"class":358},"(",[33,1356,1357],{"class":81},"\".\u002Fheavy-feature.js\"",[33,1359,1360],{"class":358},");\n",[33,1362,1363],{"class":35,"line":244},[33,1364,1365],{"class":39},"\u002F\u002F Vite\u002FRollup creates a separate chunk for heavy-feature.js (loaded when import() runs)\n",[33,1367,1368],{"class":35,"line":250},[33,1369,65],{"emptyLinePlaceholder":64},[33,1371,1372],{"class":35,"line":256},[33,1373,1374],{"class":39},"\u002F\u002F ── Manual chunks (vendor splitting) ──\n",[33,1376,1377],{"class":35,"line":262},[33,1378,1379],{"class":39},"\u002F\u002F vite.config.js: rollupOptions.output.manualChunks\n",[33,1381,1382],{"class":35,"line":268},[33,1383,1384],{"class":39},"\u002F\u002F Splits large vendor libs (react, lodash) into separate chunks (cached independently)\n",[33,1386,1387],{"class":35,"line":274},[33,1388,65],{"emptyLinePlaceholder":64},[33,1390,1391],{"class":35,"line":288},[33,1392,1393],{"class":39},"\u002F\u002F ── Prefetch and preload hints ──\n",[33,1395,1396],{"class":35,"line":299},[33,1397,1398],{"class":39},"\u002F\u002F \u003Clink rel=\"modulepreload\" href=\"\u002Fchunk.js\">  → load early (high priority, for critical chunks)\n",[33,1400,1401],{"class":35,"line":311},[33,1402,1403],{"class":39},"\u002F\u002F \u003Clink rel=\"prefetch\" href=\"\u002Flazy.js\">        → load when idle (low priority, for future navigation)\n",[15,1405,1407],{"id":1406},"source-maps","Source Maps",[20,1409,1410],{"language":338},[24,1411,1413],{"className":341,"code":1412,"language":338,"meta":28,"style":28},"\u002F\u002F ── Source maps: map minified code back to the original source ──\n\u002F\u002F Essential for debugging production code (stack traces, breakpoints).\n\n\u002F\u002F ── Source map types ──\n\u002F\u002F inline: embedded in the JS file (\u002F\u002F# sourceMappingURL=data:...)\n\u002F\u002F external: separate .js.map file (\u002F\u002F# sourceMappingURL=app.js.map)\n\u002F\u002F hidden: generated but no sourceMappingURL comment (for error reporting tools)\n\n\u002F\u002F ── Vite source map config ──\n\u002F\u002F vite.config.js:\n\u002F\u002F build: { sourcemap: true }       → external .map files\n\u002F\u002F build: { sourcemap: \"inline\" }   → inline in the JS\n\u002F\u002F build: { sourcemap: \"hidden\" }   → no comment (for Sentry\u002Fetc.)\n\n\u002F\u002F ── Source map structure (simplified) ──\n\u002F\u002F {\n\u002F\u002F   \"version\": 3,\n\u002F\u002F   \"sources\": [\"src\u002Fapp.js\", \"src\u002Futils.js\"],  \u002F\u002F original source files\n\u002F\u002F   \"names\": [\"add\", \"subtract\", \"result\"],     \u002F\u002F original variable names\n\u002F\u002F   \"mappings\": \"AAAA,CAAC...\",                  \u002F\u002F VLQ-encoded position mappings\n\u002F\u002F   \"file\": \"app.min.js\",                        \u002F\u002F generated file\n\u002F\u002F   \"sourcesContent\": [\"const add = ...\"]        \u002F\u002F original source content (optional)\n\u002F\u002F }\n\u002F\u002F Mappings encode: generated position → original position (file, line, column, name)\n\n\u002F\u002F ── Stack trace with source maps ──\n\u002F\u002F Without source maps: \"Error at a.min.js:1:234\" (minified — useless)\n\u002F\u002F With source maps: \"Error at add (src\u002Fmath.js:3:12)\" (original — debuggable)\n",[30,1414,1415,1420,1425,1429,1434,1439,1444,1449,1453,1458,1463,1468,1473,1478,1482,1487,1492,1497,1505,1513,1521,1529,1537,1542,1547,1551,1556,1561],{"__ignoreMap":28},[33,1416,1417],{"class":35,"line":36},[33,1418,1419],{"class":39},"\u002F\u002F ── Source maps: map minified code back to the original source ──\n",[33,1421,1422],{"class":35,"line":43},[33,1423,1424],{"class":39},"\u002F\u002F Essential for debugging production code (stack traces, breakpoints).\n",[33,1426,1427],{"class":35,"line":49},[33,1428,65],{"emptyLinePlaceholder":64},[33,1430,1431],{"class":35,"line":55},[33,1432,1433],{"class":39},"\u002F\u002F ── Source map types ──\n",[33,1435,1436],{"class":35,"line":61},[33,1437,1438],{"class":39},"\u002F\u002F inline: embedded in the JS file (\u002F\u002F# sourceMappingURL=data:...)\n",[33,1440,1441],{"class":35,"line":68},[33,1442,1443],{"class":39},"\u002F\u002F external: separate .js.map file (\u002F\u002F# sourceMappingURL=app.js.map)\n",[33,1445,1446],{"class":35,"line":74},[33,1447,1448],{"class":39},"\u002F\u002F hidden: generated but no sourceMappingURL comment (for error reporting tools)\n",[33,1450,1451],{"class":35,"line":91},[33,1452,65],{"emptyLinePlaceholder":64},[33,1454,1455],{"class":35,"line":108},[33,1456,1457],{"class":39},"\u002F\u002F ── Vite source map config ──\n",[33,1459,1460],{"class":35,"line":124},[33,1461,1462],{"class":39},"\u002F\u002F vite.config.js:\n",[33,1464,1465],{"class":35,"line":129},[33,1466,1467],{"class":39},"\u002F\u002F build: { sourcemap: true }       → external .map files\n",[33,1469,1470],{"class":35,"line":135},[33,1471,1472],{"class":39},"\u002F\u002F build: { sourcemap: \"inline\" }   → inline in the JS\n",[33,1474,1475],{"class":35,"line":148},[33,1476,1477],{"class":39},"\u002F\u002F build: { sourcemap: \"hidden\" }   → no comment (for Sentry\u002Fetc.)\n",[33,1479,1480],{"class":35,"line":161},[33,1481,65],{"emptyLinePlaceholder":64},[33,1483,1484],{"class":35,"line":171},[33,1485,1486],{"class":39},"\u002F\u002F ── Source map structure (simplified) ──\n",[33,1488,1489],{"class":35,"line":176},[33,1490,1491],{"class":39},"\u002F\u002F {\n",[33,1493,1494],{"class":35,"line":182},[33,1495,1496],{"class":39},"\u002F\u002F   \"version\": 3,\n",[33,1498,1499,1502],{"class":35,"line":195},[33,1500,1501],{"class":39},"\u002F\u002F   \"sources\": [\"src\u002Fapp.js\", \"src\u002Futils.js\"],",[33,1503,1504],{"class":39},"  \u002F\u002F original source files\n",[33,1506,1507,1510],{"class":35,"line":208},[33,1508,1509],{"class":39},"\u002F\u002F   \"names\": [\"add\", \"subtract\", \"result\"],",[33,1511,1512],{"class":39},"     \u002F\u002F original variable names\n",[33,1514,1515,1518],{"class":35,"line":221},[33,1516,1517],{"class":39},"\u002F\u002F   \"mappings\": \"AAAA,CAAC...\",",[33,1519,1520],{"class":39},"                  \u002F\u002F VLQ-encoded position mappings\n",[33,1522,1523,1526],{"class":35,"line":226},[33,1524,1525],{"class":39},"\u002F\u002F   \"file\": \"app.min.js\",",[33,1527,1528],{"class":39},"                        \u002F\u002F generated file\n",[33,1530,1531,1534],{"class":35,"line":232},[33,1532,1533],{"class":39},"\u002F\u002F   \"sourcesContent\": [\"const add = ...\"]",[33,1535,1536],{"class":39},"        \u002F\u002F original source content (optional)\n",[33,1538,1539],{"class":35,"line":238},[33,1540,1541],{"class":39},"\u002F\u002F }\n",[33,1543,1544],{"class":35,"line":244},[33,1545,1546],{"class":39},"\u002F\u002F Mappings encode: generated position → original position (file, line, column, name)\n",[33,1548,1549],{"class":35,"line":250},[33,1550,65],{"emptyLinePlaceholder":64},[33,1552,1553],{"class":35,"line":256},[33,1554,1555],{"class":39},"\u002F\u002F ── Stack trace with source maps ──\n",[33,1557,1558],{"class":35,"line":262},[33,1559,1560],{"class":39},"\u002F\u002F Without source maps: \"Error at a.min.js:1:234\" (minified — useless)\n",[33,1562,1563],{"class":35,"line":268},[33,1564,1565],{"class":39},"\u002F\u002F With source maps: \"Error at add (src\u002Fmath.js:3:12)\" (original — debuggable)\n",[15,1567,1569],{"id":1568},"tips-tricks","💡 Tips & Tricks",[20,1571,1572],{"language":22},[24,1573,1575],{"className":26,"code":1574,"language":22,"meta":28,"style":28},"# ── npm audit: check for known vulnerabilities ──\nnpm audit              # list vulnerabilities\nnpm audit fix          # auto-fix (updates vulnerable deps)\nnpm audit fix --force  # breaking fixes (major version bumps)\n\n# ── nvm\u002Ffnm: manage Node versions ──\nnvm install 20         # install Node 20\nnvm use 20             # switch to Node 20\nnvm alias default 20   # set default\n# .nvmrc file: \"20\" → nvm use automatically reads it\n\n# ── npx: run a package's binary without installing globally ──\nnpx create-vite my-app  # run create-vite without global install\nnpx prettier --write .  # run the local prettier (from node_modules\u002F.bin)\n\n# ── npm scripts with cross-env (cross-platform env vars) ──\n# \"scripts\": { \"dev\": \"cross-env NODE_ENV=development vite\" }\n# Without cross-env: NODE_ENV=dev vite (Unix only — doesn't work on Windows)\n",[30,1576,1577,1582,1592,1604,1618,1622,1627,1640,1652,1666,1671,1675,1680,1693,1709,1713,1718,1723],{"__ignoreMap":28},[33,1578,1579],{"class":35,"line":36},[33,1580,1581],{"class":39},"# ── npm audit: check for known vulnerabilities ──\n",[33,1583,1584,1586,1589],{"class":35,"line":43},[33,1585,78],{"class":77},[33,1587,1588],{"class":81}," audit",[33,1590,1591],{"class":39},"              # list vulnerabilities\n",[33,1593,1594,1596,1598,1601],{"class":35,"line":49},[33,1595,78],{"class":77},[33,1597,1588],{"class":81},[33,1599,1600],{"class":81}," fix",[33,1602,1603],{"class":39},"          # auto-fix (updates vulnerable deps)\n",[33,1605,1606,1608,1610,1612,1615],{"class":35,"line":55},[33,1607,78],{"class":77},[33,1609,1588],{"class":81},[33,1611,1600],{"class":81},[33,1613,1614],{"class":98}," --force",[33,1616,1617],{"class":39},"  # breaking fixes (major version bumps)\n",[33,1619,1620],{"class":35,"line":61},[33,1621,65],{"emptyLinePlaceholder":64},[33,1623,1624],{"class":35,"line":68},[33,1625,1626],{"class":39},"# ── nvm\u002Ffnm: manage Node versions ──\n",[33,1628,1629,1632,1634,1637],{"class":35,"line":74},[33,1630,1631],{"class":77},"nvm",[33,1633,82],{"class":81},[33,1635,1636],{"class":98}," 20",[33,1638,1639],{"class":39},"         # install Node 20\n",[33,1641,1642,1644,1647,1649],{"class":35,"line":91},[33,1643,1631],{"class":77},[33,1645,1646],{"class":81}," use",[33,1648,1636],{"class":98},[33,1650,1651],{"class":39},"             # switch to Node 20\n",[33,1653,1654,1656,1659,1661,1663],{"class":35,"line":108},[33,1655,1631],{"class":77},[33,1657,1658],{"class":81}," alias",[33,1660,394],{"class":81},[33,1662,1636],{"class":98},[33,1664,1665],{"class":39},"   # set default\n",[33,1667,1668],{"class":35,"line":124},[33,1669,1670],{"class":39},"# .nvmrc file: \"20\" → nvm use automatically reads it\n",[33,1672,1673],{"class":35,"line":129},[33,1674,65],{"emptyLinePlaceholder":64},[33,1676,1677],{"class":35,"line":135},[33,1678,1679],{"class":39},"# ── npx: run a package's binary without installing globally ──\n",[33,1681,1682,1684,1687,1690],{"class":35,"line":148},[33,1683,302],{"class":77},[33,1685,1686],{"class":81}," create-vite",[33,1688,1689],{"class":81}," my-app",[33,1691,1692],{"class":39},"  # run create-vite without global install\n",[33,1694,1695,1697,1700,1703,1706],{"class":35,"line":161},[33,1696,302],{"class":77},[33,1698,1699],{"class":81}," prettier",[33,1701,1702],{"class":98}," --write",[33,1704,1705],{"class":81}," .",[33,1707,1708],{"class":39},"  # run the local prettier (from node_modules\u002F.bin)\n",[33,1710,1711],{"class":35,"line":171},[33,1712,65],{"emptyLinePlaceholder":64},[33,1714,1715],{"class":35,"line":176},[33,1716,1717],{"class":39},"# ── npm scripts with cross-env (cross-platform env vars) ──\n",[33,1719,1720],{"class":35,"line":182},[33,1721,1722],{"class":39},"# \"scripts\": { \"dev\": \"cross-env NODE_ENV=development vite\" }\n",[33,1724,1725],{"class":35,"line":195},[33,1726,1727],{"class":39},"# Without cross-env: NODE_ENV=dev vite (Unix only — doesn't work on Windows)\n",[15,1729,1731],{"id":1730},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[20,1733,1734],{"language":338},[24,1735,1737],{"className":341,"code":1736,"language":338,"meta":28,"style":28},"\u002F\u002F ── CommonJS can't be tree-shaken (require is dynamic) ──\n\u002F\u002F require(\".\u002Fmodule\") → bundler can't know which exports are used at build time.\n\u002F\u002F Use ESM (import\u002Fexport) for tree-shaking.\n\n\u002F\u002F ── `import * as namespace` prevents tree-shaking ──\n\u002F\u002F import * as utils from \".\u002Futils.js\";  → bundler must include ALL exports (can't shake)\n\u002F\u002F import { used } from \".\u002Futils.js\";   → only `used` is bundled (shakeable)\n\n\u002F\u002F ── Side effects prevent tree-shaking ──\n\u002F\u002F If a module modifies global state (polyfills, prototypes), it can't be removed.\n\u002F\u002F Declare side effects in package.json: \"sideEffects\": [\".\u002Fpolyfill.js\"]\n\n\u002F\u002F ── `npm install` updates the lock file; `npm ci` uses it strictly ──\n\u002F\u002F npm install: may change versions (resolves to latest within range)\n\u002F\u002F npm ci: strictly uses the lock file (reproducible — use in CI)\n\n\u002F\u002F ── Dev dependencies are not installed in production ──\n\u002F\u002F npm install --production → only dependencies (no devDependencies)\n\u002F\u002F Don't import devDependencies in production code (eslint, vitest, etc.)\n\n\u002F\u002F ── `^` and `~` in package.json ──\n\u002F\u002F ^1.2.3: >=1.2.3 \u003C2.0.0 (caret — allows minor and patch updates)\n\u002F\u002F ~1.2.3: >=1.2.3 \u003C1.3.0 (tilde — allows patch updates only)\n\u002F\u002F 1.2.3: exact version (no updates)\n\u002F\u002F Use ^ for libraries (flexible), pin exact versions for critical deps.\n",[30,1738,1739,1744,1749,1754,1758,1763,1768,1773,1777,1782,1787,1792,1796,1801,1806,1811,1815,1820,1825,1830,1834,1839,1844,1849,1854],{"__ignoreMap":28},[33,1740,1741],{"class":35,"line":36},[33,1742,1743],{"class":39},"\u002F\u002F ── CommonJS can't be tree-shaken (require is dynamic) ──\n",[33,1745,1746],{"class":35,"line":43},[33,1747,1748],{"class":39},"\u002F\u002F require(\".\u002Fmodule\") → bundler can't know which exports are used at build time.\n",[33,1750,1751],{"class":35,"line":49},[33,1752,1753],{"class":39},"\u002F\u002F Use ESM (import\u002Fexport) for tree-shaking.\n",[33,1755,1756],{"class":35,"line":55},[33,1757,65],{"emptyLinePlaceholder":64},[33,1759,1760],{"class":35,"line":61},[33,1761,1762],{"class":39},"\u002F\u002F ── `import * as namespace` prevents tree-shaking ──\n",[33,1764,1765],{"class":35,"line":68},[33,1766,1767],{"class":39},"\u002F\u002F import * as utils from \".\u002Futils.js\";  → bundler must include ALL exports (can't shake)\n",[33,1769,1770],{"class":35,"line":74},[33,1771,1772],{"class":39},"\u002F\u002F import { used } from \".\u002Futils.js\";   → only `used` is bundled (shakeable)\n",[33,1774,1775],{"class":35,"line":91},[33,1776,65],{"emptyLinePlaceholder":64},[33,1778,1779],{"class":35,"line":108},[33,1780,1781],{"class":39},"\u002F\u002F ── Side effects prevent tree-shaking ──\n",[33,1783,1784],{"class":35,"line":124},[33,1785,1786],{"class":39},"\u002F\u002F If a module modifies global state (polyfills, prototypes), it can't be removed.\n",[33,1788,1789],{"class":35,"line":129},[33,1790,1791],{"class":39},"\u002F\u002F Declare side effects in package.json: \"sideEffects\": [\".\u002Fpolyfill.js\"]\n",[33,1793,1794],{"class":35,"line":135},[33,1795,65],{"emptyLinePlaceholder":64},[33,1797,1798],{"class":35,"line":148},[33,1799,1800],{"class":39},"\u002F\u002F ── `npm install` updates the lock file; `npm ci` uses it strictly ──\n",[33,1802,1803],{"class":35,"line":161},[33,1804,1805],{"class":39},"\u002F\u002F npm install: may change versions (resolves to latest within range)\n",[33,1807,1808],{"class":35,"line":171},[33,1809,1810],{"class":39},"\u002F\u002F npm ci: strictly uses the lock file (reproducible — use in CI)\n",[33,1812,1813],{"class":35,"line":176},[33,1814,65],{"emptyLinePlaceholder":64},[33,1816,1817],{"class":35,"line":182},[33,1818,1819],{"class":39},"\u002F\u002F ── Dev dependencies are not installed in production ──\n",[33,1821,1822],{"class":35,"line":195},[33,1823,1824],{"class":39},"\u002F\u002F npm install --production → only dependencies (no devDependencies)\n",[33,1826,1827],{"class":35,"line":208},[33,1828,1829],{"class":39},"\u002F\u002F Don't import devDependencies in production code (eslint, vitest, etc.)\n",[33,1831,1832],{"class":35,"line":221},[33,1833,65],{"emptyLinePlaceholder":64},[33,1835,1836],{"class":35,"line":226},[33,1837,1838],{"class":39},"\u002F\u002F ── `^` and `~` in package.json ──\n",[33,1840,1841],{"class":35,"line":232},[33,1842,1843],{"class":39},"\u002F\u002F ^1.2.3: >=1.2.3 \u003C2.0.0 (caret — allows minor and patch updates)\n",[33,1845,1846],{"class":35,"line":238},[33,1847,1848],{"class":39},"\u002F\u002F ~1.2.3: >=1.2.3 \u003C1.3.0 (tilde — allows patch updates only)\n",[33,1850,1851],{"class":35,"line":244},[33,1852,1853],{"class":39},"\u002F\u002F 1.2.3: exact version (no updates)\n",[33,1855,1856],{"class":35,"line":250},[33,1857,1858],{"class":39},"\u002F\u002F Use ^ for libraries (flexible), pin exact versions for critical deps.\n",[15,1860,1862],{"id":1861},"quick-quiz","🧠 Quick Quiz",[1864,1865,1866],"p",{},"Why might tree-shaking fail to remove an unused export?",[20,1868,1869],{"language":338},[24,1870,1872],{"className":341,"code":1871,"language":338,"meta":28,"style":28},"\u002F\u002F utils.js\nexport const used = () => \"hello\";\nexport const unused = () => {\n    console.log(\"side effect on import\");\n    return \"unused\";\n};\n",[30,1873,1874,1879,1900,1918,1933,1943],{"__ignoreMap":28},[33,1875,1876],{"class":35,"line":36},[33,1877,1878],{"class":39},"\u002F\u002F utils.js\n",[33,1880,1881,1883,1885,1888,1890,1893,1895,1898],{"class":35,"line":43},[33,1882,391],{"class":354},[33,1884,1179],{"class":354},[33,1886,1887],{"class":77}," used",[33,1889,1185],{"class":354},[33,1891,1892],{"class":358}," () ",[33,1894,1203],{"class":354},[33,1896,1897],{"class":81}," \"hello\"",[33,1899,368],{"class":358},[33,1901,1902,1904,1906,1909,1911,1913,1915],{"class":35,"line":49},[33,1903,391],{"class":354},[33,1905,1179],{"class":354},[33,1907,1908],{"class":77}," unused",[33,1910,1185],{"class":354},[33,1912,1892],{"class":358},[33,1914,1203],{"class":354},[33,1916,1917],{"class":358}," {\n",[33,1919,1920,1923,1926,1928,1931],{"class":35,"line":55},[33,1921,1922],{"class":358},"    console.",[33,1924,1925],{"class":77},"log",[33,1927,1354],{"class":358},[33,1929,1930],{"class":81},"\"side effect on import\"",[33,1932,1360],{"class":358},[33,1934,1935,1938,1941],{"class":35,"line":61},[33,1936,1937],{"class":354},"    return",[33,1939,1940],{"class":81}," \"unused\"",[33,1942,368],{"class":358},[33,1944,1945],{"class":35,"line":68},[33,1946,1947],{"class":358},"};\n",[1949,1950,1951,1955,1971,1986,1992,2055,2065,2079,2122],"details",{},[1952,1953,1954],"summary",{},"Answer",[1864,1956,1957,1958,1961,1962,1966,1967,1970],{},"If ",[30,1959,1960],{},"unused"," has ",[1963,1964,1965],"strong",{},"side effects"," (like ",[30,1968,1969],{},"console.log"," at the top level, or modifying global state), the bundler can't safely remove it — the side effect might be needed for correctness.",[1864,1972,1973,1974,1976,1977,1979,1980,1982,1983,1985],{},"In this case, ",[30,1975,1960],{}," is a function — the ",[30,1978,1969],{}," is inside the function body, so it only runs when ",[30,1981,1960],{}," is called. If ",[30,1984,1960],{}," is never called, it CAN be tree-shaken (the side effect never executes).",[1864,1987,1988,1991],{},[1963,1989,1990],{},"But"," if the module has top-level side effects:",[24,1993,1995],{"className":341,"code":1994,"language":338,"meta":28,"style":28},"\u002F\u002F utils.js\nconsole.log(\"module loaded\");  \u002F\u002F top-level side effect → runs on import\nexport const used = () => \"hello\";\nexport const unused = () => \"unused\";\n",[30,1996,1997,2001,2019,2037],{"__ignoreMap":28},[33,1998,1999],{"class":35,"line":36},[33,2000,1878],{"class":39},[33,2002,2003,2006,2008,2010,2013,2016],{"class":35,"line":43},[33,2004,2005],{"class":358},"console.",[33,2007,1925],{"class":77},[33,2009,1354],{"class":358},[33,2011,2012],{"class":81},"\"module loaded\"",[33,2014,2015],{"class":358},");  ",[33,2017,2018],{"class":39},"\u002F\u002F top-level side effect → runs on import\n",[33,2020,2021,2023,2025,2027,2029,2031,2033,2035],{"class":35,"line":49},[33,2022,391],{"class":354},[33,2024,1179],{"class":354},[33,2026,1887],{"class":77},[33,2028,1185],{"class":354},[33,2030,1892],{"class":358},[33,2032,1203],{"class":354},[33,2034,1897],{"class":81},[33,2036,368],{"class":358},[33,2038,2039,2041,2043,2045,2047,2049,2051,2053],{"class":35,"line":55},[33,2040,391],{"class":354},[33,2042,1179],{"class":354},[33,2044,1908],{"class":77},[33,2046,1185],{"class":354},[33,2048,1892],{"class":358},[33,2050,1203],{"class":354},[33,2052,1940],{"class":81},[33,2054,368],{"class":358},[1864,2056,2057,2058,2060,2061,2064],{},"The bundler can't remove ",[30,2059,1969],{}," (it runs on import) — so the entire module must be included, even if only ",[30,2062,2063],{},"used"," is imported.",[1864,2066,2067,2070,2071,2074,2075,2078],{},[1963,2068,2069],{},"Fix",": declare ",[30,2072,2073],{},"\"sideEffects\": false"," in ",[30,2076,2077],{},"package.json"," (if truly no side effects), or list specific files with side effects:",[24,2080,2084],{"className":2081,"code":2082,"language":2083,"meta":28,"style":28},"language-json shiki shiki-themes github-light github-dark","{ \"sideEffects\": false }  \u002F\u002F bundler can freely tree-shake all exports\n{ \"sideEffects\": [\".\u002Fpolyfill.js\"] }  \u002F\u002F except this file\n","json",[30,2085,2086,2105],{"__ignoreMap":28},[33,2087,2088,2091,2094,2096,2099,2102],{"class":35,"line":36},[33,2089,2090],{"class":358},"{ ",[33,2092,2093],{"class":98},"\"sideEffects\"",[33,2095,562],{"class":358},[33,2097,2098],{"class":98},"false",[33,2100,2101],{"class":358}," }  ",[33,2103,2104],{"class":39},"\u002F\u002F bundler can freely tree-shake all exports\n",[33,2106,2107,2109,2111,2113,2116,2119],{"class":35,"line":43},[33,2108,2090],{"class":358},[33,2110,2093],{"class":98},[33,2112,488],{"class":358},[33,2114,2115],{"class":81},"\".\u002Fpolyfill.js\"",[33,2117,2118],{"class":358},"] }  ",[33,2120,2121],{"class":39},"\u002F\u002F except this file\n",[1864,2123,2124,2127,2128,2131],{},[1963,2125,2126],{},"The lesson",": tree-shaking requires (1) ESM (static imports), (2) no side effects (or declared side effects), and (3) no namespace imports (",[30,2129,2130],{},"import * as","). Side effects at the module top level prevent the bundler from removing unused exports.",[2133,2134,2135],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}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);}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}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}",{"title":28,"searchDepth":43,"depth":43,"links":2137},[2138,2139,2140,2141,2142,2143,2144,2145],{"id":17,"depth":43,"text":18},{"id":334,"depth":43,"text":335},{"id":777,"depth":43,"text":778},{"id":1135,"depth":43,"text":1136},{"id":1406,"depth":43,"text":1407},{"id":1568,"depth":43,"text":1569},{"id":1730,"depth":43,"text":1731},{"id":1861,"depth":43,"text":1862},"Deep-dive into JavaScript tooling: npm\u002Fpnpm package management, ESLint configuration and custom rules, Vite build internals (esbuild dev + Rollup prod), tree-shaking, and source maps. Code-first reference for senior engineers.","md",{},"\u002Fjs\u002F27-tooling-and-build-systems",{"title":5,"description":2146},"js\u002F27-tooling-and-build-systems","K0ZVWU9WTdUHzji-kCvNigcHaCeAvUuF1wdXn7511a8",1789924649560]