[{"data":1,"prerenderedAt":1075},["ShallowReactive",2],{"content:\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwhy-barrel-files-break-tree-shaking":3,"surroundings:\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwhy-barrel-files-break-tree-shaking":1066},{"id":4,"title":5,"body":6,"description":1046,"extension":1047,"meta":1048,"navigation":536,"path":1060,"seo":1061,"stem":1064,"__hash__":1065},"content\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwhy-barrel-files-break-tree-shaking\u002Findex.md","Why Barrel Files Break Tree Shaking",{"type":7,"value":8,"toc":1030},"minimark",[9,14,42,45,205,210,257,261,271,280,290,299,374,378,383,443,455,458,462,614,617,621,628,677,680,684,691,809,813,816,820,850,854,884,888,901,915,929,935,939,954,963,976,988,992,1015,1020,1023,1026],[10,11,13],"h1",{"id":12},"why-barrel-files-break-tree-shaking-and-how-to-fix-it","Why Barrel Files Break Tree Shaking — and How to Fix It",[15,16,17,18,23,24,28,29,33,34,37,38,41],"p",{},"This guide belongs to ",[19,20,22],"a",{"href":21},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002F","Tree Shaking and Dead Code Elimination"," within ",[19,25,27],{"href":26},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript Bundle Optimization & Code Splitting",". A barrel file is an ",[30,31,32],"code",{},"index.ts"," that re-exports everything from a folder: ",[30,35,36],{},"export * from '.\u002FButton'; export * from '.\u002FModal'; export * from '.\u002FDataGrid';",". It makes imports tidy — ",[30,39,40],{},"import { Button } from '@\u002Fcomponents'"," — and it is one of the most common reasons a page that uses one button ships the data grid too.",[15,43,44],{},"In theory, bundlers follow re-exports and drop unused modules. In practice, they can only drop a module if they can prove that evaluating it has no side effects. A single module in the barrel with top-level code — a CSS import, a polyfill, a registry call, a class with static initialisers — forces the bundler to keep it, and anything it imports. Barrels also slow builds and development servers, because every import of the barrel makes the tool resolve and parse every file behind it.",[15,46,47],{},[48,49,55,56,55,63,55,67,55,70,55,88,55,96,55,102,55,110,55,117,55,121,55,126,55,130,55,133,55,137,55,141,55,145,55,151,55,155,55,158,55,161,55,165,55,168,55,171,55,174,55,178,55,181,55,184,55,193,55,197,55,201,55],"svg",{"viewBox":50,"width":51,"role":52,"ariaLabel":53,"style":54},"0 0 760 166","100%","img","Flow from importing one component through a barrel file to the bundler having to evaluate every re-exported module.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[57,58],"rect",{"className":59,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],"svg-canvas","0","#ffffff",[64,65,66],"title",{},"How one barrel import pulls in the folder",[68,69,53],"desc",{},[71,72,73],"defs",{},[74,75,82],"marker",{"id":76,"viewBox":77,"refX":78,"refY":79,"markerWidth":80,"markerHeight":80,"orient":81},"fade94f737","0 0 10 10","9","5","7","auto-start-reverse",[83,84],"path",{"d":85,"fill":86,"style":87},"M0 0 L10 5 L0 10 z","currentColor","fill-opacity:0.7",[57,89],{"x":90,"y":90,"width":91,"height":92,"rx":93,"fill":94,"stroke":86,"style":95},"1","758","164","10","none","stroke-opacity:0.18",[97,98,66],"text",{"x":99,"y":100,"fill":86,"style":101},"28.0","34.0","font-size:16px;font-weight:700",[57,103],{"x":99,"y":104,"width":105,"height":106,"rx":107,"fill":108,"stroke":108,"style":109},"56.0","108.8","88.0","6","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[97,111,116],{"x":112,"y":113,"fill":86,"style":114,"textAnchor":115},"82.4","78.0","font-size:13px;font-weight:700","middle","import { Button",[97,118,120],{"x":112,"y":119,"fill":86,"style":114,"textAnchor":115},"95.0","}",[97,122,125],{"x":112,"y":123,"fill":86,"style":124,"textAnchor":115},"113.0","font-size:12px","from",[97,127,129],{"x":112,"y":128,"fill":86,"style":124,"textAnchor":115},"129.0","'@\u002Fcomponents'",[57,131],{"x":132,"y":104,"width":105,"height":106,"rx":107,"fill":108,"stroke":108,"style":109},"176.8",[97,134,136],{"x":135,"y":113,"fill":86,"style":114,"textAnchor":115},"231.2","Barrel index.ts",[97,138,140],{"x":135,"y":139,"fill":86,"style":124,"textAnchor":115},"96.0","export * from 30",[97,142,144],{"x":135,"y":143,"fill":86,"style":124,"textAnchor":115},"112.0","files",[57,146],{"x":147,"y":104,"width":105,"height":106,"rx":107,"fill":148,"stroke":149,"style":150},"325.6","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[97,152,154],{"x":153,"y":113,"fill":86,"style":114,"textAnchor":115},"380.0","Side effects?",[97,156,157],{"x":153,"y":139,"fill":86,"style":124,"textAnchor":115},"unknown or yes",[57,159],{"x":160,"y":104,"width":105,"height":106,"rx":107,"fill":108,"stroke":108,"style":109},"474.4",[97,162,164],{"x":163,"y":113,"fill":86,"style":114,"textAnchor":115},"528.8","Kept",[97,166,167],{"x":163,"y":139,"fill":86,"style":124,"textAnchor":115},"DataGrid, Chart,",[97,169,170],{"x":163,"y":143,"fill":86,"style":124,"textAnchor":115},"Editor",[57,172],{"x":173,"y":104,"width":105,"height":106,"rx":107,"fill":108,"stroke":108,"style":109},"623.2",[97,175,177],{"x":176,"y":113,"fill":86,"style":114,"textAnchor":115},"677.6","Shipped",[97,179,180],{"x":176,"y":139,"fill":86,"style":124,"textAnchor":115},"+180KB on every",[97,182,183],{"x":176,"y":143,"fill":86,"style":124,"textAnchor":115},"page",[185,186],"line",{"x1":187,"y1":188,"x2":189,"y2":188,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":192},"136.8","100.0","174.8","1.5","stroke-opacity:0.6","url(#fade94f737)",[185,194],{"x1":195,"y1":188,"x2":196,"y2":188,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":192},"285.6","323.6",[185,198],{"x1":199,"y1":188,"x2":200,"y2":188,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":192},"434.4","472.4",[185,202],{"x1":203,"y1":188,"x2":204,"y2":188,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":192},"583.2","621.2",[206,207,209],"h2",{"id":208},"rapid-diagnosis","Rapid Diagnosis",[211,212,213,221,235,251],"ul",{},[214,215,216,220],"li",{},[217,218,219],"strong",{},"Import one small export through the barrel in a test entry"," and check the bundle: if unrelated components appear, the barrel is leaking.",[214,222,223,234],{},[217,224,225,226,229,230,233],{},"Check ",[30,227,228],{},"sideEffects"," in ",[30,231,232],{},"package.json","."," If it is missing for your internal packages, bundlers assume every file has side effects.",[214,236,237,55,240,243,244,243,247,250],{},[217,238,239],{},"Search re-exported modules for top-level effects:",[30,241,242],{},"import '.\u002Fstyles.css'",", ",[30,245,246],{},"register(...)",[30,248,249],{},"window.x = ",", or immediately invoked functions.",[214,252,253,256],{},[217,254,255],{},"Measure build and dev-server time."," In large codebases, barrel imports noticeably slow module resolution; Next.js and Vite both document this.",[206,258,260],{"id":259},"root-cause-analysis","Root Cause Analysis",[15,262,263,266,267,270],{},[217,264,265],{},"1. Unknown side effects."," Without ",[30,268,269],{},"\"sideEffects\": false"," or a precise list, bundlers must keep every module reached through the barrel, in case importing it does something.",[15,272,273,276,277,279],{},[217,274,275],{},"2. Real side effects in one module."," Even with ",[30,278,228],{}," declared, a module that genuinely has top-level effects is kept — and if it imports heavy dependencies, so are they.",[15,281,282,289],{},[217,283,284,285,288],{},"3. ",[30,286,287],{},"export *"," from CommonJS."," Re-exporting a CommonJS module makes its exports dynamic; bundlers cannot shake it.",[15,291,292,55,295,298],{},[217,293,294],{},"4. Namespace re-exports.",[30,296,297],{},"export * as utils from '.\u002Futils'"," creates a namespace object; some bundlers keep the whole namespace if it is passed around.",[15,300,301],{},[48,302,55,305,55,308,55,311,55,313,55,316,55,318,55,325,55,332,55,337,55,341,55,345,55,349,55,353,55,358,55,362,55,366,55,370,55],{"viewBox":303,"width":51,"role":52,"ariaLabel":304,"style":54},"0 0 760 194","Bar chart of bytes shipped when importing a single Button component via a barrel versus a direct path, under different side-effect settings.",[57,306],{"className":307,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],[64,309,310],{},"Bundle cost of importing one Button",[68,312,304],{},[57,314],{"x":90,"y":90,"width":91,"height":315,"rx":93,"fill":94,"stroke":86,"style":95},"192",[97,317,310],{"x":99,"y":100,"fill":86,"style":101},[97,319,324],{"x":320,"y":321,"fill":86,"style":322,"textAnchor":323},"233.2","70.0","font-size:13px","end","Barrel, sideEffects unset",[57,326],{"x":327,"y":104,"width":328,"height":329,"rx":330,"fill":148,"stroke":149,"style":331},"245.2","422.8","19","3","fill-opacity:0.7;stroke-opacity:0.9",[97,333,336],{"x":334,"y":321,"fill":86,"style":335},"674.0","font-size:12px;font-weight:600","186KB",[97,338,340],{"x":320,"y":339,"fill":86,"style":322,"textAnchor":323},"101.0","Barrel, one module with CSS import",[57,342],{"x":327,"y":343,"width":344,"height":329,"rx":330,"fill":148,"stroke":149,"style":331},"87.0","145.5",[97,346,348],{"x":347,"y":339,"fill":86,"style":335},"396.7","64KB",[97,350,352],{"x":320,"y":351,"fill":86,"style":322,"textAnchor":323},"132.0","Barrel, sideEffects declared",[57,354],{"x":327,"y":355,"width":356,"height":329,"rx":330,"fill":108,"stroke":108,"style":357},"118.0","20.5","fill-opacity:0.55;stroke-opacity:0.9",[97,359,361],{"x":360,"y":351,"fill":86,"style":335},"271.7","9KB",[97,363,365],{"x":320,"y":364,"fill":86,"style":322,"textAnchor":323},"163.0","Direct path import",[57,367],{"x":327,"y":368,"width":369,"height":329,"rx":330,"fill":108,"stroke":108,"style":357},"149.0","18.2",[97,371,373],{"x":372,"y":364,"fill":86,"style":335},"269.4","8KB",[206,375,377],{"id":376},"step-by-step-resolution","Step-by-Step Resolution",[379,380,382],"h3",{"id":381},"_1-declare-side-effects-for-internal-packages","1. Declare side effects for internal packages",[384,385,390],"pre",{"className":386,"code":387,"language":388,"meta":389,"style":389},"language-json shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","{\n  \"name\": \"@acme\u002Fcomponents\",\n  \"sideEffects\": [\"**\u002F*.css\", \".\u002Fsrc\u002Fpolyfills.ts\"]\n}\n","json","",[30,391,392,400,417,437],{"__ignoreMap":389},[393,394,396],"span",{"class":185,"line":395},1,[393,397,399],{"class":398},"saISM","{\n",[393,401,403,407,410,414],{"class":185,"line":402},2,[393,404,406],{"class":405},"sZBmE","  \"name\"",[393,408,409],{"class":398},": ",[393,411,413],{"class":412},"sZ8jY","\"@acme\u002Fcomponents\"",[393,415,416],{"class":398},",\n",[393,418,420,423,426,429,431,434],{"class":185,"line":419},3,[393,421,422],{"class":405},"  \"sideEffects\"",[393,424,425],{"class":398},": [",[393,427,428],{"class":412},"\"**\u002F*.css\"",[393,430,243],{"class":398},[393,432,433],{"class":412},"\".\u002Fsrc\u002Fpolyfills.ts\"",[393,435,436],{"class":398},"]\n",[393,438,440],{"class":185,"line":439},4,[393,441,442],{"class":398},"}\n",[15,444,445,446,450,451,233],{},"Everything not listed is treated as pure, so unused re-exports are dropped. The trade-off is correctness: if a module you did not list ",[447,448,449],"em",{},"does"," rely on a side effect, it will disappear — the failure mode described in ",[19,452,454],{"href":453},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fsideeffects-false-broke-my-css-imports\u002F","sideEffects: false broke my CSS imports",[15,456,457],{},"Expected outcome: importing one component through the barrel ships roughly what a direct import ships.",[379,459,461],{"id":460},"_2-remove-top-level-effects-from-re-exported-modules","2. Remove top-level effects from re-exported modules",[384,463,467],{"className":464,"code":465,"language":466,"meta":389,"style":389},"language-typescript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F Before: importing the module registers the component globally.\nimport { registry } from '..\u002Fregistry';\nexport class DataGrid { \u002F* ... *\u002F }\nregistry.register('data-grid', DataGrid);\n\n\u002F\u002F After: export only; registration is an explicit call in app setup.\nexport class DataGrid { \u002F* ... *\u002F }\nexport const registerDataGrid = (r: Registry) => r.register('data-grid', DataGrid);\n\u002F\u002F trade-off: callers must now register explicitly. That is more code at the\n\u002F\u002F call site, but it is also clearer about what the app depends on.\n","typescript",[30,468,469,475,492,513,531,538,544,559,602,608],{"__ignoreMap":389},[393,470,471],{"class":185,"line":395},[393,472,474],{"class":473},"sjfSM","\u002F\u002F Before: importing the module registers the component globally.\n",[393,476,477,481,484,486,489],{"class":185,"line":402},[393,478,480],{"class":479},"sPARh","import",[393,482,483],{"class":398}," { registry } ",[393,485,125],{"class":479},[393,487,488],{"class":412}," '..\u002Fregistry'",[393,490,491],{"class":398},";\n",[393,493,494,497,500,504,507,510],{"class":185,"line":419},[393,495,496],{"class":479},"export",[393,498,499],{"class":479}," class",[393,501,503],{"class":502},"sQw3B"," DataGrid",[393,505,506],{"class":398}," { ",[393,508,509],{"class":473},"\u002F* ... *\u002F",[393,511,512],{"class":398}," }\n",[393,514,515,518,522,525,528],{"class":185,"line":439},[393,516,517],{"class":398},"registry.",[393,519,521],{"class":520},"smZ65","register",[393,523,524],{"class":398},"(",[393,526,527],{"class":412},"'data-grid'",[393,529,530],{"class":398},", DataGrid);\n",[393,532,534],{"class":185,"line":533},5,[393,535,537],{"emptyLinePlaceholder":536},true,"\n",[393,539,541],{"class":185,"line":540},6,[393,542,543],{"class":473},"\u002F\u002F After: export only; registration is an explicit call in app setup.\n",[393,545,547,549,551,553,555,557],{"class":185,"line":546},7,[393,548,496],{"class":479},[393,550,499],{"class":479},[393,552,503],{"class":502},[393,554,506],{"class":398},[393,556,509],{"class":473},[393,558,512],{"class":398},[393,560,562,564,567,570,573,576,579,582,585,588,591,594,596,598,600],{"class":185,"line":561},8,[393,563,496],{"class":479},[393,565,566],{"class":479}," const",[393,568,569],{"class":520}," registerDataGrid",[393,571,572],{"class":479}," =",[393,574,575],{"class":398}," (",[393,577,578],{"class":502},"r",[393,580,581],{"class":479},":",[393,583,584],{"class":502}," Registry",[393,586,587],{"class":398},") ",[393,589,590],{"class":479},"=>",[393,592,593],{"class":398}," r.",[393,595,521],{"class":520},[393,597,524],{"class":398},[393,599,527],{"class":412},[393,601,530],{"class":398},[393,603,605],{"class":185,"line":604},9,[393,606,607],{"class":473},"\u002F\u002F trade-off: callers must now register explicitly. That is more code at the\n",[393,609,611],{"class":185,"line":610},10,[393,612,613],{"class":473},"\u002F\u002F call site, but it is also clearer about what the app depends on.\n",[15,615,616],{},"Expected outcome: modules behind the barrel become genuinely removable.",[379,618,620],{"id":619},"_3-use-direct-imports-for-heavy-modules-or-let-the-framework-optimise-barrels","3. Use direct imports for heavy modules, or let the framework optimise barrels",[15,622,623,624,627],{},"For heavy components, import from their own paths. Next.js offers ",[30,625,626],{},"optimizePackageImports",", which rewrites barrel imports from listed packages into direct imports at build time.",[384,629,633],{"className":630,"code":631,"language":632,"meta":389,"style":389},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F next.config.js\nmodule.exports = { experimental: { optimizePackageImports: ['@acme\u002Fcomponents', 'lucide-react'] } };\n\u002F\u002F trade-off: the rewrite relies on the package's export structure; it works\n\u002F\u002F for well-behaved packages and may need disabling for ones with unusual exports.\n","javascript",[30,634,635,640,667,672],{"__ignoreMap":389},[393,636,637],{"class":185,"line":395},[393,638,639],{"class":473},"\u002F\u002F next.config.js\n",[393,641,642,646,648,651,653,656,659,661,664],{"class":185,"line":402},[393,643,645],{"class":644},"sPXB4","module",[393,647,233],{"class":398},[393,649,650],{"class":644},"exports",[393,652,572],{"class":479},[393,654,655],{"class":398}," { experimental: { optimizePackageImports: [",[393,657,658],{"class":412},"'@acme\u002Fcomponents'",[393,660,243],{"class":398},[393,662,663],{"class":412},"'lucide-react'",[393,665,666],{"class":398},"] } };\n",[393,668,669],{"class":185,"line":419},[393,670,671],{"class":473},"\u002F\u002F trade-off: the rewrite relies on the package's export structure; it works\n",[393,673,674],{"class":185,"line":439},[393,675,676],{"class":473},"\u002F\u002F for well-behaved packages and may need disabling for ones with unusual exports.\n",[15,678,679],{},"Expected outcome: imports stay ergonomic while the bundle contains only what is used.",[379,681,683],{"id":682},"_4-enforce-with-lint-rules","4. Enforce with lint rules",[15,685,686,687,690],{},"Prevent new barrels from reintroducing the problem in hot paths with ESLint rules such as ",[30,688,689],{},"no-restricted-imports"," for known heavy barrels, or plugins that flag barrel files entirely.",[15,692,693],{},[48,694,55,697,55,700,55,703,55,705,55,712,55,715,55,717,55,722,55,726,55,729,55,734,55,740,55,745,55,749,55,754,55,757,55,760,55,762,55,765,55,768,55,771,55,774,55,777,55,780,55,784,55,786,55,789,55,792,55,795,55,799,55,802,55,805,55],{"viewBox":695,"width":51,"role":52,"ariaLabel":696,"style":54},"0 0 760 325","Decision sequence for fixing a barrel file that pulls unused modules into the bundle.",[57,698],{"className":699,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],[64,701,702],{},"Fixing a leaky barrel",[68,704,696],{},[71,706,707],{},[74,708,710],{"id":709,"viewBox":77,"refX":78,"refY":79,"markerWidth":80,"markerHeight":80,"orient":81},"fabdab6ea3",[83,711],{"d":85,"fill":86,"style":87},[57,713],{"x":90,"y":90,"width":91,"height":714,"rx":93,"fill":94,"stroke":86,"style":95},"323",[97,716,702],{"x":99,"y":100,"fill":86,"style":101},[57,718],{"x":99,"y":104,"width":719,"height":720,"rx":107,"fill":86,"stroke":86,"style":721},"320.0","35.0","fill-opacity:0.06;stroke-opacity:0.4",[97,723,725],{"x":724,"y":113,"fill":86,"style":114,"textAnchor":115},"188.0","Package has no sideEffects field?",[57,727],{"x":728,"y":104,"width":719,"height":720,"rx":107,"fill":108,"stroke":108,"style":109},"412.0",[97,730,733],{"x":731,"y":113,"fill":86,"style":732,"textAnchor":115},"572.0","font-size:12.5px","Add sideEffects listing only CSS and true effects",[185,735],{"x1":736,"y1":737,"x2":738,"y2":737,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":739},"348.0","73.5","410.0","url(#fabdab6ea3)",[97,741,744],{"x":153,"y":742,"fill":108,"style":743,"textAnchor":115},"66.5","font-size:11.5px;font-weight:700","yes",[185,746],{"x1":724,"y1":747,"x2":724,"y2":748,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":739},"91.0","125.0",[97,750,753],{"x":751,"y":123,"fill":752,"style":743},"196.0","#51617a","no",[57,755],{"x":99,"y":756,"width":719,"height":720,"rx":107,"fill":86,"stroke":86,"style":721},"127.0",[97,758,759],{"x":724,"y":368,"fill":86,"style":114,"textAnchor":115},"A re-exported module has top-level effects?",[57,761],{"x":728,"y":756,"width":719,"height":720,"rx":107,"fill":108,"stroke":108,"style":109},[97,763,764],{"x":731,"y":368,"fill":86,"style":732,"textAnchor":115},"Move the effect into an explicit function",[185,766],{"x1":736,"y1":767,"x2":738,"y2":767,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":739},"144.5",[97,769,744],{"x":153,"y":770,"fill":108,"style":743,"textAnchor":115},"137.5",[185,772],{"x1":724,"y1":773,"x2":724,"y2":751,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":739},"162.0",[97,775,753],{"x":751,"y":776,"fill":752,"style":743},"184.0",[57,778],{"x":99,"y":779,"width":719,"height":720,"rx":107,"fill":86,"stroke":86,"style":721},"198.0",[97,781,783],{"x":724,"y":782,"fill":86,"style":114,"textAnchor":115},"220.0","Re-exports CommonJS modules?",[57,785],{"x":728,"y":779,"width":719,"height":720,"rx":107,"fill":108,"stroke":108,"style":109},[97,787,788],{"x":731,"y":782,"fill":86,"style":732,"textAnchor":115},"Convert to ESM or import directly",[185,790],{"x1":736,"y1":791,"x2":738,"y2":791,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":739},"215.5",[97,793,744],{"x":153,"y":794,"fill":108,"style":743,"textAnchor":115},"208.5",[185,796],{"x1":724,"y1":797,"x2":724,"y2":798,"stroke":86,"strokeWidth":190,"style":191,"markerEnd":739},"233.0","267.0",[97,800,753],{"x":751,"y":801,"fill":752,"style":743},"255.0",[57,803],{"x":99,"y":804,"width":719,"height":100,"rx":107,"fill":148,"stroke":149,"style":150},"269.0",[97,806,808],{"x":724,"y":807,"fill":86,"style":732,"textAnchor":115},"290.5","Barrel is fine — keep it for ergonomics",[206,810,812],{"id":811},"verification","Verification",[15,814,815],{},"Build a test entry importing a single small export from the barrel and confirm its bundle size matches a direct import. Re-run the route's bundle analysis: heavy components should appear only in chunks for routes that use them. Measure build time too — removing barrels from hot paths often speeds up development server startup and hot reload noticeably.",[206,817,819],{"id":818},"worked-example-an-icon-barrel","Worked Example: An Icon Barrel",[15,821,822,823,826,827,830,831,833,834,837,838,840,841,844,845,849],{},"A design system exported 1,400 icons through ",[30,824,825],{},"icons\u002Findex.ts",", each as a React component. Pages imported ",[30,828,829],{},"{ SearchIcon, CloseIcon }"," from it. The package had no ",[30,832,228],{}," field, and the icon components were generated with a wrapper that called ",[30,835,836],{},"createIcon()"," at module scope — which bundlers could not prove pure. Every page shipped all 1,400 icons: 310KB uncompressed. Adding ",[30,839,269],{}," and marking the factory calls with ",[30,842,843],{},"\u002F*#__PURE__*\u002F"," (the subject of ",[19,846,848],{"href":847},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fusing-pure-annotations-for-side-effect-free-calls\u002F","using PURE annotations for side-effect-free calls",") reduced it to the dozen icons actually used, about 4KB.",[206,851,853],{"id":852},"common-mistakes","Common Mistakes",[211,855,856,866,872,878],{},[214,857,858,865],{},[217,859,860,861,864],{},"Declaring ",[30,862,863],{},"sideEffects: false"," without auditing."," Global CSS imports and polyfills silently vanish.",[214,867,868,871],{},[217,869,870],{},"Nested barrels."," A barrel that re-exports other barrels multiplies the surface area for side effects; flatten them.",[214,873,874,877],{},[217,875,876],{},"Assuming dev-mode bundles reflect production."," Dev servers do not tree-shake; check production builds.",[214,879,880,883],{},[217,881,882],{},"Using barrels for server-only code in shared folders."," A barrel mixing client and server utilities can pull server-only modules into client bundles, or break the build entirely.",[206,885,887],{"id":886},"edge-cases-when-barrels-bite-even-with-sideeffects","Edge Cases: When Barrels Bite Even With sideEffects",[15,889,890,55,893,896,897,900],{},[217,891,892],{},"Re-exported default exports.",[30,894,895],{},"export { default as Button } from '.\u002FButton'"," is fine; ",[30,898,899],{},"export default from"," patterns and mixed CommonJS interop can produce wrapper objects that bundlers keep.",[15,902,903,906,907,910,911,914],{},[217,904,905],{},"Barrels that compute exports."," An index that builds its exports dynamically — iterating a folder with ",[30,908,909],{},"import.meta.glob",", or assembling an object of components — defeats static analysis entirely. Generated barrels should emit plain ",[30,912,913],{},"export … from"," lines.",[15,916,917,920,921,924,925,928],{},[217,918,919],{},"Type-only re-exports."," In TypeScript, re-exporting types alongside values is harmless after compilation, but ",[30,922,923],{},"isolatedModules"," setups may require ",[30,926,927],{},"export type"," to avoid emitting runtime imports for types. A stray runtime import of a types-only module can pull an otherwise unused file into the graph.",[15,930,931,934],{},[217,932,933],{},"Server and client boundaries."," In frameworks with server components, a barrel that re-exports both server-only and client components can force the client bundle to include server code paths or trigger build errors. Split barrels by environment.",[206,936,938],{"id":937},"faq","FAQ",[940,941,944,948],"details",{"className":942},[943],"faq-item",[945,946,947],"summary",{},"Should we ban barrel files entirely?",[15,949,950,951,953],{},"Not necessarily. Barrels of pure, small modules with ",[30,952,228],{}," declared tree-shake well and keep imports tidy. Problems arise with barrels over heavy or effectful modules, CommonJS re-exports, and very large barrels that slow tooling. Restrict barrels in those cases and keep them elsewhere.",[940,955,957,960],{"className":956},[943],[945,958,959],{},"Does Vite's dev server suffer from barrels?",[15,961,962],{},"Yes. Vite serves modules individually in development, so importing a barrel makes the browser request every module behind it. Large barrels can mean hundreds of requests on page load in dev, which is why Vite's documentation recommends avoiding them for large libraries.",[940,964,966,969],{"className":965},[943],[945,967,968],{},"Do TypeScript path aliases change anything?",[15,970,971,972,975],{},"No. Aliases like ",[30,973,974],{},"@\u002Fcomponents"," are resolved to paths before bundling; whether tree shaking works depends on what the resolved module contains, not how it was referenced.",[940,977,979,982],{"className":978},[943],[945,980,981],{},"How do I find which barrel is responsible?",[15,983,984,985,987],{},"In a bundle analyser's network or import-chain view, select an unexpected module and follow its importers upward. The first ",[30,986,32],{}," in the chain that your code imports is the barrel to fix.",[206,989,991],{"id":990},"related","Related",[211,993,994,1001,1008],{},[214,995,996,1000],{},[19,997,999],{"href":998},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwriting-tree-shakeable-library-exports\u002F","Writing tree-shakeable library exports"," — designing exports that shake from the start.",[214,1002,1003,1007],{},[19,1004,1006],{"href":1005},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Ffixing-tree-shaking-issues-with-lodash-and-moment\u002F","Fixing tree-shaking issues with lodash and moment"," — third-party libraries with the same problem.",[214,1009,1010,1014],{},[19,1011,1013],{"href":1012},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fbuilding-tree-shakeable-libraries-with-vite-library-mode\u002F","Building tree-shakeable libraries with Vite library mode"," — packaging internal libraries correctly.",[1016,1017,1019],"script",{"type":1018},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Why Barrel Files Break Tree Shaking — and How to Fix It\",\n  \"description\": \"How re-export barrels defeat dead-code elimination through side effects and module evaluation, and the import, config and lint fixes that restore it.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Declare side effects for internal packages\",\n      \"text\": \"Everything not listed is treated as pure, so unused re-exports are dropped.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Remove top-level effects from re-exported modules\",\n      \"text\": \"\u002F\u002F After: export only; registration is an explicit call in app setup.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Use direct imports for heavy modules, or let the framework optimise barrels\",\n      \"text\": \"For heavy components, import from their own paths.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Enforce with lint rules\",\n      \"text\": \"Prevent new barrels from reintroducing the problem in hot paths with ESLint rules such as no-restricted-imports for known heavy barrels, or plugins that flag barrel files entirely.\"\n    }\n  ]\n}\n",[1016,1021,1022],{"type":1018},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"Why Barrel Files Break Tree Shaking — and How to Fix It\",\n  \"description\": \"How re-export barrels defeat dead-code elimination through side effects and module evaluation, and the import, config and lint fixes that restore it.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwhy-barrel-files-break-tree-shaking\u002F\"\n  }\n}\n",[1016,1024,1025],{"type":1018},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"JavaScript Bundle Optimization & Code Splitting\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Tree Shaking and Dead Code Elimination\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Why Barrel Files Break Tree Shaking\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwhy-barrel-files-break-tree-shaking\u002F\"\n    }\n  ]\n}\n",[1027,1028,1029],"style",{},"html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}",{"title":389,"searchDepth":402,"depth":402,"links":1031},[1032,1033,1034,1040,1041,1042,1043,1044,1045],{"id":208,"depth":402,"text":209},{"id":259,"depth":402,"text":260},{"id":376,"depth":402,"text":377,"children":1035},[1036,1037,1038,1039],{"id":381,"depth":419,"text":382},{"id":460,"depth":419,"text":461},{"id":619,"depth":419,"text":620},{"id":682,"depth":419,"text":683},{"id":811,"depth":402,"text":812},{"id":818,"depth":402,"text":819},{"id":852,"depth":402,"text":853},{"id":886,"depth":402,"text":887},{"id":937,"depth":402,"text":938},{"id":990,"depth":402,"text":991},"How re-export barrels defeat dead-code elimination through side effects and module evaluation, and the import, config and lint fixes that restore it.","md",{"slug":1049,"type":1050,"breadcrumb":1051,"datePublished":1059,"dateModified":1059},"why-barrel-files-break-tree-shaking","article",[1052,1055,1056,1057],{"name":1053,"url":1054},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1058},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwhy-barrel-files-break-tree-shaking\u002F","2026-10-06","\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwhy-barrel-files-break-tree-shaking",{"title":1062,"description":1063},"Why Barrel Files Break Tree Shaking (and How to Fix It)","index.ts barrel files that re-export everything can pull whole modules into bundles and slow builds. Learn when barrels break tree shaking and how to fix them.","javascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwhy-barrel-files-break-tree-shaking\u002Findex","AWeEWXnjxhhyCOnAGVos0_oG-Gg3gA4VztQd1p3i_Ms",[1067,1071],{"title":1068,"path":1069,"stem":1070},"Using PURE Annotations for Side-Effect-Free Calls","\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fusing-pure-annotations-for-side-effect-free-calls","javascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fusing-pure-annotations-for-side-effect-free-calls\u002Findex",{"title":1072,"path":1073,"stem":1074},"Writing Tree-Shakeable Library Exports","\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwriting-tree-shakeable-library-exports","javascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fwriting-tree-shakeable-library-exports\u002Findex",1791308079790]