[{"data":1,"prerenderedAt":1421},["ShallowReactive",2],{"content:\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fanalyzing-vite-bundles-with-rollup-plugin-visualizer":3,"surroundings:\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fanalyzing-vite-bundles-with-rollup-plugin-visualizer":1413},{"id":4,"title":5,"body":6,"description":1393,"extension":1394,"meta":1395,"navigation":1407,"path":1408,"seo":1409,"stem":1411,"__hash__":1412},"content\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fanalyzing-vite-bundles-with-rollup-plugin-visualizer\u002Findex.md","Analyzing Vite Bundles with rollup-plugin-visualizer",{"type":7,"value":8,"toc":1378},"minimark",[9,14,34,37,197,202,237,241,247,253,259,265,352,356,361,522,567,570,574,600,715,719,722,786,789,793,800,1207,1210,1214,1217,1221,1236,1240,1299,1303,1315,1327,1336,1340,1363,1368,1371,1374],[10,11,13],"h1",{"id":12},"how-to-analyze-vite-bundles-with-rollup-plugin-visualizer","How to Analyze Vite Bundles with rollup-plugin-visualizer",[15,16,17,18,23,24,28,29,33],"p",{},"This guide covers the main analysis tool for ",[19,20,22],"a",{"href":21},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002F","Vite & Rollup Build Optimization",", part of ",[19,25,27],{"href":26},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript Bundle Optimization & Code Splitting",". Before changing chunking or replacing a dependency, you need to see what is in each chunk, how large it is in the units that matter, and why it is there. ",[30,31,32],"code",{},"rollup-plugin-visualizer"," produces that picture from the Rollup build that Vite runs in production.",[15,35,36],{},"Reading the output correctly matters as much as generating it. The plugin reports several sizes — rendered (after tree-shaking, before minification in some setups), gzip and brotli — and offers several views. Teams that only look at the biggest rectangle in the treemap often optimise the wrong thing: a library that is large in total but only on a lazy route, while a smaller library on the critical path does more damage to LCP and INP.",[15,38,39],{},[40,41,47,48,47,55,47,59,47,62,47,80,47,88,47,94,47,102,47,109,47,113,47,118,47,122,47,125,47,129,47,133,47,137,47,143,47,147,47,150,47,153,47,156,47,160,47,163,47,166,47,170,47,173,47,176,47,185,47,189,47,193,47],"svg",{"viewBox":42,"width":43,"role":44,"ariaLabel":45,"style":46},"0 0 760 166","100%","img","Workflow from generating the visualiser report to deciding on a bundle change.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[49,50],"rect",{"className":51,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],"svg-canvas","0","#ffffff",[56,57,58],"title",{},"From build to decision",[60,61,45],"desc",{},[63,64,65],"defs",{},[66,67,74],"marker",{"id":68,"viewBox":69,"refX":70,"refY":71,"markerWidth":72,"markerHeight":72,"orient":73},"fa0371b7e7","0 0 10 10","9","5","7","auto-start-reverse",[75,76],"path",{"d":77,"fill":78,"style":79},"M0 0 L10 5 L0 10 z","currentColor","fill-opacity:0.7",[49,81],{"x":82,"y":82,"width":83,"height":84,"rx":85,"fill":86,"stroke":78,"style":87},"1","758","164","10","none","stroke-opacity:0.18",[89,90,58],"text",{"x":91,"y":92,"fill":78,"style":93},"28.0","34.0","font-size:16px;font-weight:700",[49,95],{"x":91,"y":96,"width":97,"height":98,"rx":99,"fill":100,"stroke":100,"style":101},"56.0","108.8","88.0","6","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[89,103,108],{"x":104,"y":105,"fill":78,"style":106,"textAnchor":107},"82.4","78.0","font-size:13px;font-weight:700","middle","Build with",[89,110,112],{"x":104,"y":111,"fill":78,"style":106,"textAnchor":107},"95.0","plugin",[89,114,117],{"x":104,"y":115,"fill":78,"style":116,"textAnchor":107},"113.0","font-size:12px","stats.html + raw",[89,119,121],{"x":104,"y":120,"fill":78,"style":116,"textAnchor":107},"129.0","data",[49,123],{"x":124,"y":96,"width":97,"height":98,"rx":99,"fill":100,"stroke":100,"style":101},"176.8",[89,126,128],{"x":127,"y":105,"fill":78,"style":106,"textAnchor":107},"231.2","Pick the chunk",[89,130,132],{"x":127,"y":131,"fill":78,"style":116,"textAnchor":107},"96.0","what the route",[89,134,136],{"x":127,"y":135,"fill":78,"style":116,"textAnchor":107},"112.0","loads",[49,138],{"x":139,"y":96,"width":97,"height":98,"rx":99,"fill":140,"stroke":141,"style":142},"325.6","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[89,144,146],{"x":145,"y":105,"fill":78,"style":106,"textAnchor":107},"380.0","Find largest",[89,148,149],{"x":145,"y":111,"fill":78,"style":106,"textAnchor":107},"modules",[89,151,152],{"x":145,"y":115,"fill":78,"style":116,"textAnchor":107},"by gzip size",[49,154],{"x":155,"y":96,"width":97,"height":98,"rx":99,"fill":100,"stroke":100,"style":101},"474.4",[89,157,159],{"x":158,"y":105,"fill":78,"style":106,"textAnchor":107},"528.8","Ask why",[89,161,162],{"x":158,"y":131,"fill":78,"style":116,"textAnchor":107},"importer chain",[49,164],{"x":165,"y":96,"width":97,"height":98,"rx":99,"fill":100,"stroke":100,"style":101},"623.2",[89,167,169],{"x":168,"y":105,"fill":78,"style":106,"textAnchor":107},"677.6","Change",[89,171,172],{"x":168,"y":131,"fill":78,"style":116,"textAnchor":107},"lazy, replace,",[89,174,175],{"x":168,"y":135,"fill":78,"style":116,"textAnchor":107},"dedupe",[177,178],"line",{"x1":179,"y1":180,"x2":181,"y2":180,"stroke":78,"strokeWidth":182,"style":183,"markerEnd":184},"136.8","100.0","174.8","1.5","stroke-opacity:0.6","url(#fa0371b7e7)",[177,186],{"x1":187,"y1":180,"x2":188,"y2":180,"stroke":78,"strokeWidth":182,"style":183,"markerEnd":184},"285.6","323.6",[177,190],{"x1":191,"y1":180,"x2":192,"y2":180,"stroke":78,"strokeWidth":182,"style":183,"markerEnd":184},"434.4","472.4",[177,194],{"x1":195,"y1":180,"x2":196,"y2":180,"stroke":78,"strokeWidth":182,"style":183,"markerEnd":184},"583.2","621.2",[198,199,201],"h2",{"id":200},"rapid-diagnosis","Rapid Diagnosis",[203,204,205,213,219,225,231],"ul",{},[206,207,208,212],"li",{},[209,210,211],"strong",{},"Generate the report on a production build."," The plugin only reflects what Rollup bundles; the dev server shows nothing useful.",[206,214,215,218],{},[209,216,217],{},"Start from the route, not the biggest box."," Identify which chunks your landing route loads (Network panel or the Vite manifest), then inspect those.",[206,220,221,224],{},[209,222,223],{},"Use gzip or brotli size for transfer, rendered size for parse cost."," Both matter; they tell different stories.",[206,226,227,230],{},[209,228,229],{},"Look for duplicates."," The same package name appearing under several chunks or at several versions.",[206,232,233,236],{},[209,234,235],{},"Look for surprises."," Locale files, development builds of libraries, test utilities, or full icon sets in production chunks.",[198,238,240],{"id":239},"root-cause-analysis-what-analysis-usually-reveals","Root Cause Analysis: What Analysis Usually Reveals",[15,242,243,246],{},[209,244,245],{},"1. Libraries imported for one function."," A date or utility library included wholesale because of a namespace import or a non-tree-shakeable build.",[15,248,249,252],{},[209,250,251],{},"2. Large dependencies on the critical path."," A rich-text editor or chart library statically imported by a component rendered on the landing route.",[15,254,255,258],{},[209,256,257],{},"3. Duplicate versions."," Two major versions of a library pulled in by different dependencies, both shipped.",[15,260,261,264],{},[209,262,263],{},"4. Assets inlined as JavaScript."," SVG icon sets, JSON data or images converted to base64 inside JS chunks, inflating parse cost.",[15,266,267],{},[40,268,47,271,47,274,47,277,47,279,47,282,47,284,47,291,47,298,47,303,47,307,47,311,47,315,47,319,47,324,47,328,47,332,47,336,47,340,47,344,47,348,47],{"viewBox":269,"width":43,"role":44,"ariaLabel":270,"style":46},"0 0 760 225","Bar chart of the largest modules in a landing route's JavaScript chunk as revealed by the visualiser.",[49,272],{"className":273,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],[56,275,276],{},"Top modules in a landing-route chunk (brotli)",[60,278,270],{},[49,280],{"x":82,"y":82,"width":83,"height":281,"rx":85,"fill":86,"stroke":78,"style":87},"223",[89,283,276],{"x":91,"y":92,"fill":78,"style":93},[89,285,290],{"x":286,"y":287,"fill":78,"style":288,"textAnchor":289},"155.0","70.0","font-size:13px","end","moment + all locales",[49,292],{"x":293,"y":96,"width":294,"height":295,"rx":296,"fill":140,"stroke":141,"style":297},"167.0","501.0","19","3","fill-opacity:0.7;stroke-opacity:0.9",[89,299,302],{"x":300,"y":287,"fill":78,"style":301},"674.0","font-size:12px;font-weight:600","72KB",[89,304,306],{"x":286,"y":305,"fill":78,"style":288,"textAnchor":289},"101.0","lodash (full build)",[49,308],{"x":293,"y":309,"width":310,"height":295,"rx":296,"fill":140,"stroke":141,"style":297},"87.0","174.0",[89,312,314],{"x":313,"y":305,"fill":78,"style":301},"346.9","25KB",[89,316,318],{"x":286,"y":317,"fill":78,"style":288,"textAnchor":289},"132.0","react-dom",[49,320],{"x":293,"y":321,"width":322,"height":295,"rx":296,"fill":78,"stroke":78,"style":323},"118.0","292.3","fill-opacity:0.7;stroke-opacity:0.4",[89,325,327],{"x":326,"y":317,"fill":78,"style":301},"465.2","42KB",[89,329,331],{"x":286,"y":330,"fill":78,"style":288,"textAnchor":289},"163.0","icons (full set as JSX)",[49,333],{"x":293,"y":334,"width":335,"height":295,"rx":296,"fill":140,"stroke":141,"style":297},"149.0","264.4",[89,337,339],{"x":338,"y":330,"fill":78,"style":301},"437.4","38KB",[89,341,343],{"x":286,"y":342,"fill":78,"style":288,"textAnchor":289},"194.0","App components",[49,345],{"x":293,"y":346,"width":347,"height":295,"rx":296,"fill":78,"stroke":78,"style":323},"180.0","215.7",[89,349,351],{"x":350,"y":342,"fill":78,"style":301},"388.7","31KB",[198,353,355],{"id":354},"step-by-step-workflow","Step-by-Step Workflow",[357,358,360],"h3",{"id":359},"_1-configure-the-plugin-for-useful-output","1. Configure the plugin for useful output",[362,363,368],"pre",{"className":364,"code":365,"language":366,"meta":367,"style":367},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F vite.config.js\nimport { visualizer } from 'rollup-plugin-visualizer';\nexport default {\n  plugins: [\n    visualizer({\n      filename: 'dist\u002Fstats.html',\n      template: 'treemap',          \u002F\u002F also: 'sunburst', 'network', 'raw-data', 'list'\n      gzipSize: true,\n      brotliSize: true,\n      emitFile: false,\n    }),\n  ],\n};\n\u002F\u002F trade-off: computing gzip and brotli sizes slows large builds noticeably.\n\u002F\u002F Enable the plugin only in an \"analyze\" build mode rather than on every build.\n","javascript","",[30,369,370,378,399,412,418,428,440,455,467,477,488,494,502,510,516],{"__ignoreMap":367},[371,372,374],"span",{"class":177,"line":373},1,[371,375,377],{"class":376},"sjfSM","\u002F\u002F vite.config.js\n",[371,379,381,385,389,392,396],{"class":177,"line":380},2,[371,382,384],{"class":383},"sPARh","import",[371,386,388],{"class":387},"saISM"," { visualizer } ",[371,390,391],{"class":383},"from",[371,393,395],{"class":394},"sZ8jY"," 'rollup-plugin-visualizer'",[371,397,398],{"class":387},";\n",[371,400,402,405,408],{"class":177,"line":401},3,[371,403,404],{"class":383},"export",[371,406,407],{"class":383}," default",[371,409,411],{"class":410},"sQw3B"," {\n",[371,413,415],{"class":177,"line":414},4,[371,416,417],{"class":387},"  plugins: [\n",[371,419,421,425],{"class":177,"line":420},5,[371,422,424],{"class":423},"smZ65","    visualizer",[371,426,427],{"class":387},"({\n",[371,429,431,434,437],{"class":177,"line":430},6,[371,432,433],{"class":387},"      filename: ",[371,435,436],{"class":394},"'dist\u002Fstats.html'",[371,438,439],{"class":387},",\n",[371,441,443,446,449,452],{"class":177,"line":442},7,[371,444,445],{"class":387},"      template: ",[371,447,448],{"class":394},"'treemap'",[371,450,451],{"class":387},",          ",[371,453,454],{"class":376},"\u002F\u002F also: 'sunburst', 'network', 'raw-data', 'list'\n",[371,456,458,461,465],{"class":177,"line":457},8,[371,459,460],{"class":387},"      gzipSize: ",[371,462,464],{"class":463},"sPXB4","true",[371,466,439],{"class":387},[371,468,470,473,475],{"class":177,"line":469},9,[371,471,472],{"class":387},"      brotliSize: ",[371,474,464],{"class":463},[371,476,439],{"class":387},[371,478,480,483,486],{"class":177,"line":479},10,[371,481,482],{"class":387},"      emitFile: ",[371,484,485],{"class":463},"false",[371,487,439],{"class":387},[371,489,491],{"class":177,"line":490},11,[371,492,493],{"class":387},"    }),\n",[371,495,497,500],{"class":177,"line":496},12,[371,498,499],{"class":387},"  ]",[371,501,439],{"class":410},[371,503,505,508],{"class":177,"line":504},13,[371,506,507],{"class":410},"}",[371,509,398],{"class":387},[371,511,513],{"class":177,"line":512},14,[371,514,515],{"class":376},"\u002F\u002F trade-off: computing gzip and brotli sizes slows large builds noticeably.\n",[371,517,519],{"class":177,"line":518},15,[371,520,521],{"class":376},"\u002F\u002F Enable the plugin only in an \"analyze\" build mode rather than on every build.\n",[362,523,527],{"className":524,"code":525,"language":526,"meta":367,"style":367},"language-bash shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","ANALYZE=1 npx vite build && open dist\u002Fstats.html\n# trade-off: opening the report locally is fine; publishing stats.html with your\n# site exposes your dependency list and file paths. Keep it out of the deploy.\n","bash",[30,528,529,557,562],{"__ignoreMap":367},[371,530,531,534,537,539,542,545,548,551,554],{"class":177,"line":373},[371,532,533],{"class":387},"ANALYZE",[371,535,536],{"class":383},"=",[371,538,82],{"class":394},[371,540,541],{"class":410}," npx",[371,543,544],{"class":394}," vite",[371,546,547],{"class":394}," build",[371,549,550],{"class":387}," && ",[371,552,553],{"class":410},"open",[371,555,556],{"class":394}," dist\u002Fstats.html\n",[371,558,559],{"class":177,"line":380},[371,560,561],{"class":376},"# trade-off: opening the report locally is fine; publishing stats.html with your\n",[371,563,564],{"class":177,"line":401},[371,565,566],{"class":376},"# site exposes your dependency list and file paths. Keep it out of the deploy.\n",[15,568,569],{},"Expected outcome: an interactive report you can filter by chunk and module.",[357,571,573],{"id":572},"_2-use-the-right-view-for-the-question","2. Use the right view for the question",[203,575,576,582,588,594],{},[206,577,578,581],{},[209,579,580],{},"Treemap"," — what is big in each chunk.",[206,583,584,587],{},[209,585,586],{},"Sunburst"," — how a package's size is distributed across its internal files (useful for libraries with many submodules).",[206,589,590,593],{},[209,591,592],{},"Network"," — which modules import which, to answer \"why is this here?\".",[206,595,596,599],{},[209,597,598],{},"Raw data \u002F list"," — machine-readable output for CI comparisons.",[15,601,602],{},[40,603,47,606,47,609,47,612,47,614,47,617,47,619,47,624,47,631,47,635,47,639,47,642,47,646,47,650,47,654,47,656,47,659,47,661,47,664,47,667,47,671,47,673,47,676,47,678,47,681,47,684,47,688,47,690,47,693,47,695,47,698,47,701,47,705,47,707,47,710,47,712,47],{"viewBox":604,"width":43,"role":44,"ariaLabel":605,"style":46},"0 0 760 228","Mapping of rollup-plugin-visualizer templates to the analysis question each is best for.",[49,607],{"className":608,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],[56,610,611],{},"Which visualiser view answers which question",[60,613,605],{},[49,615],{"x":82,"y":82,"width":83,"height":616,"rx":85,"fill":86,"stroke":78,"style":87},"226",[89,618,611],{"x":91,"y":92,"fill":78,"style":93},[49,620],{"x":91,"y":96,"width":621,"height":622,"rx":53,"fill":78,"stroke":78,"style":623},"100.2","30.0","fill-opacity:0.06;stroke-opacity:0.4",[89,625,630],{"x":626,"y":627,"fill":78,"style":628,"textAnchor":629},"38.0","75.5","font-size:12.5px;font-weight:700","start","View",[49,632],{"x":633,"y":96,"width":634,"height":622,"rx":53,"fill":78,"stroke":78,"style":623},"128.2","301.9",[89,636,638],{"x":637,"y":627,"fill":78,"style":628,"textAnchor":107},"279.2","Best question",[49,640],{"x":641,"y":96,"width":634,"height":622,"rx":53,"fill":78,"stroke":78,"style":623},"430.1",[89,643,645],{"x":644,"y":627,"fill":78,"style":628,"textAnchor":107},"581.1","Watch out for",[49,647],{"x":91,"y":648,"width":621,"height":622,"rx":53,"fill":86,"stroke":78,"style":649},"86.0","stroke-opacity:0.35",[89,651,653],{"x":626,"y":652,"fill":78,"style":628,"textAnchor":629},"105.5","treemap",[49,655],{"x":633,"y":648,"width":634,"height":622,"rx":53,"fill":86,"stroke":78,"style":649},[89,657,658],{"x":637,"y":652,"fill":78,"style":116,"textAnchor":107},"What is large in this chunk?",[49,660],{"x":641,"y":648,"width":634,"height":622,"rx":53,"fill":78,"stroke":78,"style":623},[89,662,663],{"x":644,"y":652,"fill":78,"style":116,"textAnchor":107},"area hides small duplicated pieces",[49,665],{"x":91,"y":666,"width":621,"height":622,"rx":53,"fill":86,"stroke":78,"style":649},"116.0",[89,668,670],{"x":626,"y":669,"fill":78,"style":628,"textAnchor":629},"135.5","sunburst",[49,672],{"x":633,"y":666,"width":634,"height":622,"rx":53,"fill":86,"stroke":78,"style":649},[89,674,675],{"x":637,"y":669,"fill":78,"style":116,"textAnchor":107},"Which part of a package is large?",[49,677],{"x":641,"y":666,"width":634,"height":622,"rx":53,"fill":78,"stroke":78,"style":623},[89,679,680],{"x":644,"y":669,"fill":78,"style":116,"textAnchor":107},"hard to compare chunks",[49,682],{"x":91,"y":683,"width":621,"height":622,"rx":53,"fill":86,"stroke":78,"style":649},"146.0",[89,685,687],{"x":626,"y":686,"fill":78,"style":628,"textAnchor":629},"165.5","network",[49,689],{"x":633,"y":683,"width":634,"height":622,"rx":53,"fill":86,"stroke":78,"style":649},[89,691,692],{"x":637,"y":686,"fill":78,"style":116,"textAnchor":107},"Why is this module included?",[49,694],{"x":641,"y":683,"width":634,"height":622,"rx":53,"fill":140,"stroke":141,"style":142},[89,696,697],{"x":644,"y":686,"fill":78,"style":116,"textAnchor":107},"busy on big graphs; filter first",[49,699],{"x":91,"y":700,"width":621,"height":622,"rx":53,"fill":86,"stroke":78,"style":649},"176.0",[89,702,704],{"x":626,"y":703,"fill":78,"style":628,"textAnchor":629},"195.5","raw-data \u002F list",[49,706],{"x":633,"y":700,"width":634,"height":622,"rx":53,"fill":86,"stroke":78,"style":649},[89,708,709],{"x":637,"y":703,"fill":78,"style":116,"textAnchor":107},"Did size change in this PR?",[49,711],{"x":641,"y":700,"width":634,"height":622,"rx":53,"fill":100,"stroke":100,"style":101},[89,713,714],{"x":644,"y":703,"fill":78,"style":116,"textAnchor":107},"diff-friendly for CI",[357,716,718],{"id":717},"_3-trace-why-a-module-is-included","3. Trace why a module is included",[15,720,721],{},"In the network view, select the surprising module and follow its importers back to your code. The first import from your own source is where to intervene — replace a namespace import, change a barrel import to a direct path, or turn a static import into a dynamic one.",[362,723,725],{"className":364,"code":724,"language":366,"meta":367,"style":367},"\u002F\u002F Before: pulls the whole icon set into the landing chunk.\nimport * as Icons from '@acme\u002Ficons';\n\u002F\u002F After: import only what the component renders.\nimport { SearchIcon } from '@acme\u002Ficons\u002Fsearch';\n\u002F\u002F trade-off: deep imports couple you to a package's internal file layout,\n\u002F\u002F which can change in minor versions. Prefer packages that publish\n\u002F\u002F per-icon entry points or sideEffects-free ESM that tree-shakes reliably.\n",[30,726,727,732,752,757,771,776,781],{"__ignoreMap":367},[371,728,729],{"class":177,"line":373},[371,730,731],{"class":376},"\u002F\u002F Before: pulls the whole icon set into the landing chunk.\n",[371,733,734,736,739,742,745,747,750],{"class":177,"line":380},[371,735,384],{"class":383},[371,737,738],{"class":463}," *",[371,740,741],{"class":383}," as",[371,743,744],{"class":387}," Icons ",[371,746,391],{"class":383},[371,748,749],{"class":394}," '@acme\u002Ficons'",[371,751,398],{"class":387},[371,753,754],{"class":177,"line":401},[371,755,756],{"class":376},"\u002F\u002F After: import only what the component renders.\n",[371,758,759,761,764,766,769],{"class":177,"line":414},[371,760,384],{"class":383},[371,762,763],{"class":387}," { SearchIcon } ",[371,765,391],{"class":383},[371,767,768],{"class":394}," '@acme\u002Ficons\u002Fsearch'",[371,770,398],{"class":387},[371,772,773],{"class":177,"line":420},[371,774,775],{"class":376},"\u002F\u002F trade-off: deep imports couple you to a package's internal file layout,\n",[371,777,778],{"class":177,"line":430},[371,779,780],{"class":376},"\u002F\u002F which can change in minor versions. Prefer packages that publish\n",[371,782,783],{"class":177,"line":442},[371,784,785],{"class":376},"\u002F\u002F per-icon entry points or sideEffects-free ESM that tree-shakes reliably.\n",[15,787,788],{},"Expected outcome: the module disappears from the chunk, or moves to the lazy chunk where it belongs.",[357,790,792],{"id":791},"_4-compare-reports-between-builds-in-ci","4. Compare reports between builds in CI",[15,794,795,796,799],{},"Emit ",[30,797,798],{},"raw-data"," JSON on the main branch and on each pull request, and post a size diff per chunk as a PR comment. Large unexplained growth is caught before merge.",[362,801,803],{"className":364,"code":802,"language":366,"meta":367,"style":367},"\u002F\u002F scripts\u002Fdiff-stats.mjs — compare per-chunk brotli totals from two raw-data reports.\nimport base from '.\u002Fbase-stats.json' with { type: 'json' };\nimport head from '..\u002Fdist\u002Fstats.json' with { type: 'json' };\nfunction perChunk({ nodeMetas, nodeParts }) {\n  const out = {};\n  for (const meta of Object.values(nodeMetas)) {\n    for (const [chunk, partUid] of Object.entries(meta.moduleParts)) {\n      out[chunk] = (out[chunk] ?? 0) + (nodeParts[partUid]?.brotliLength ?? 0);\n    }\n  }\n  return out;\n}\nconst before = perChunk(base), after = perChunk(head);\nfor (const chunk of new Set([...Object.keys(before), ...Object.keys(after)])) {\n  const delta = (after[chunk] ?? 0) - (before[chunk] ?? 0);\n  if (Math.abs(delta) > 2048) console.log(`${chunk}: ${delta > 0 ? '+' : ''}${(delta \u002F 1024).toFixed(1)} KB brotli`);\n}\n\u002F\u002F trade-off: the raw-data schema is internal to the plugin and changes between\n\u002F\u002F major versions. Pin the plugin version, or use size-limit for stable CI output.\n",[30,804,805,810,834,854,877,891,917,951,983,988,993,1001,1006,1030,1074,1104,1190,1195,1201],{"__ignoreMap":367},[371,806,807],{"class":177,"line":373},[371,808,809],{"class":376},"\u002F\u002F scripts\u002Fdiff-stats.mjs — compare per-chunk brotli totals from two raw-data reports.\n",[371,811,812,814,817,819,822,825,828,831],{"class":177,"line":380},[371,813,384],{"class":383},[371,815,816],{"class":387}," base ",[371,818,391],{"class":383},[371,820,821],{"class":394}," '.\u002Fbase-stats.json'",[371,823,824],{"class":383}," with",[371,826,827],{"class":387}," { type: ",[371,829,830],{"class":394},"'json'",[371,832,833],{"class":387}," };\n",[371,835,836,838,841,843,846,848,850,852],{"class":177,"line":401},[371,837,384],{"class":383},[371,839,840],{"class":387}," head ",[371,842,391],{"class":383},[371,844,845],{"class":394}," '..\u002Fdist\u002Fstats.json'",[371,847,824],{"class":383},[371,849,827],{"class":387},[371,851,830],{"class":394},[371,853,833],{"class":387},[371,855,856,859,862,865,868,871,874],{"class":177,"line":414},[371,857,858],{"class":383},"function",[371,860,861],{"class":423}," perChunk",[371,863,864],{"class":387},"({ ",[371,866,867],{"class":410},"nodeMetas",[371,869,870],{"class":387},", ",[371,872,873],{"class":410},"nodeParts",[371,875,876],{"class":387}," }) {\n",[371,878,879,882,885,888],{"class":177,"line":420},[371,880,881],{"class":383},"  const",[371,883,884],{"class":463}," out",[371,886,887],{"class":383}," =",[371,889,890],{"class":387}," {};\n",[371,892,893,896,899,902,905,908,911,914],{"class":177,"line":430},[371,894,895],{"class":383},"  for",[371,897,898],{"class":387}," (",[371,900,901],{"class":383},"const",[371,903,904],{"class":463}," meta",[371,906,907],{"class":383}," of",[371,909,910],{"class":387}," Object.",[371,912,913],{"class":423},"values",[371,915,916],{"class":387},"(nodeMetas)) {\n",[371,918,919,922,924,926,929,932,934,937,940,943,945,948],{"class":177,"line":442},[371,920,921],{"class":383},"    for",[371,923,898],{"class":387},[371,925,901],{"class":383},[371,927,928],{"class":387}," [",[371,930,931],{"class":463},"chunk",[371,933,870],{"class":387},[371,935,936],{"class":463},"partUid",[371,938,939],{"class":387},"] ",[371,941,942],{"class":383},"of",[371,944,910],{"class":387},[371,946,947],{"class":423},"entries",[371,949,950],{"class":387},"(meta.moduleParts)) {\n",[371,952,953,956,958,961,964,967,970,973,976,978,980],{"class":177,"line":457},[371,954,955],{"class":387},"      out[chunk] ",[371,957,536],{"class":383},[371,959,960],{"class":387}," (out[chunk] ",[371,962,963],{"class":383},"??",[371,965,966],{"class":463}," 0",[371,968,969],{"class":387},") ",[371,971,972],{"class":383},"+",[371,974,975],{"class":387}," (nodeParts[partUid]?.brotliLength ",[371,977,963],{"class":383},[371,979,966],{"class":463},[371,981,982],{"class":387},");\n",[371,984,985],{"class":177,"line":469},[371,986,987],{"class":387},"    }\n",[371,989,990],{"class":177,"line":479},[371,991,992],{"class":387},"  }\n",[371,994,995,998],{"class":177,"line":490},[371,996,997],{"class":383},"  return",[371,999,1000],{"class":387}," out;\n",[371,1002,1003],{"class":177,"line":496},[371,1004,1005],{"class":387},"}\n",[371,1007,1008,1010,1013,1015,1017,1020,1023,1025,1027],{"class":177,"line":504},[371,1009,901],{"class":383},[371,1011,1012],{"class":463}," before",[371,1014,887],{"class":383},[371,1016,861],{"class":423},[371,1018,1019],{"class":387},"(base), ",[371,1021,1022],{"class":463},"after",[371,1024,887],{"class":383},[371,1026,861],{"class":423},[371,1028,1029],{"class":387},"(head);\n",[371,1031,1032,1035,1037,1039,1042,1044,1047,1050,1053,1056,1059,1062,1065,1067,1069,1071],{"class":177,"line":512},[371,1033,1034],{"class":383},"for",[371,1036,898],{"class":387},[371,1038,901],{"class":383},[371,1040,1041],{"class":463}," chunk",[371,1043,907],{"class":383},[371,1045,1046],{"class":383}," new",[371,1048,1049],{"class":423}," Set",[371,1051,1052],{"class":387},"([",[371,1054,1055],{"class":383},"...",[371,1057,1058],{"class":387},"Object.",[371,1060,1061],{"class":423},"keys",[371,1063,1064],{"class":387},"(before), ",[371,1066,1055],{"class":383},[371,1068,1058],{"class":387},[371,1070,1061],{"class":423},[371,1072,1073],{"class":387},"(after)])) {\n",[371,1075,1076,1078,1081,1083,1086,1088,1090,1092,1095,1098,1100,1102],{"class":177,"line":518},[371,1077,881],{"class":383},[371,1079,1080],{"class":463}," delta",[371,1082,887],{"class":383},[371,1084,1085],{"class":387}," (after[chunk] ",[371,1087,963],{"class":383},[371,1089,966],{"class":463},[371,1091,969],{"class":387},[371,1093,1094],{"class":383},"-",[371,1096,1097],{"class":387}," (before[chunk] ",[371,1099,963],{"class":383},[371,1101,966],{"class":463},[371,1103,982],{"class":387},[371,1105,1107,1110,1113,1116,1119,1122,1125,1128,1131,1134,1137,1139,1142,1145,1148,1150,1153,1156,1159,1162,1164,1166,1169,1172,1175,1178,1180,1182,1185,1188],{"class":177,"line":1106},16,[371,1108,1109],{"class":383},"  if",[371,1111,1112],{"class":387}," (Math.",[371,1114,1115],{"class":423},"abs",[371,1117,1118],{"class":387},"(delta) ",[371,1120,1121],{"class":383},">",[371,1123,1124],{"class":463}," 2048",[371,1126,1127],{"class":387},") console.",[371,1129,1130],{"class":423},"log",[371,1132,1133],{"class":387},"(",[371,1135,1136],{"class":394},"`${",[371,1138,931],{"class":387},[371,1140,1141],{"class":394},"}: ${",[371,1143,1144],{"class":387},"delta",[371,1146,1147],{"class":383}," >",[371,1149,966],{"class":463},[371,1151,1152],{"class":383}," ?",[371,1154,1155],{"class":394}," '+'",[371,1157,1158],{"class":383}," :",[371,1160,1161],{"class":394}," ''}${",[371,1163,1133],{"class":394},[371,1165,1144],{"class":387},[371,1167,1168],{"class":383}," \u002F",[371,1170,1171],{"class":463}," 1024",[371,1173,1174],{"class":394},").",[371,1176,1177],{"class":423},"toFixed",[371,1179,1133],{"class":394},[371,1181,82],{"class":463},[371,1183,1184],{"class":394},")",[371,1186,1187],{"class":394},"} KB brotli`",[371,1189,982],{"class":387},[371,1191,1193],{"class":177,"line":1192},17,[371,1194,1005],{"class":387},[371,1196,1198],{"class":177,"line":1197},18,[371,1199,1200],{"class":376},"\u002F\u002F trade-off: the raw-data schema is internal to the plugin and changes between\n",[371,1202,1204],{"class":177,"line":1203},19,[371,1205,1206],{"class":376},"\u002F\u002F major versions. Pin the plugin version, or use size-limit for stable CI output.\n",[15,1208,1209],{},"Expected outcome: reviewers see \"landing chunk +38KB brotli\" next to the code that caused it.",[198,1211,1213],{"id":1212},"verification","Verification",[15,1215,1216],{},"After each change, rebuild and confirm the module has left the critical-path chunk or shrunk, then measure the route in a throttled lab run: JavaScript transfer size, scripting time and TBT should all fall. Keep the before and after reports; they make the change easy to explain in code review and in a performance changelog.",[198,1218,1220],{"id":1219},"reading-sizes-correctly","Reading Sizes Correctly",[15,1222,1223,1224,1227,1228,1231,1232,1235],{},"The three sizes answer different questions. ",[209,1225,1226],{},"Rendered size"," is the module's code as it appears in the output chunk before compression; it is the best proxy for parse and compile time. ",[209,1229,1230],{},"Gzip"," and ",[209,1233,1234],{},"brotli"," sizes estimate bytes on the wire; brotli is usually what modern CDNs serve. A module that compresses exceptionally well — repetitive JSON, generated code — can look small in brotli and still cost significant parse time. Conversely, already-minified, high-entropy code compresses less. When the goal is LCP on slow networks, prioritise brotli size on the critical path; when the goal is INP and TBT on slow CPUs, prioritise rendered size.",[198,1237,1239],{"id":1238},"common-findings-and-their-fixes","Common Findings and Their Fixes",[203,1241,1242,1248,1269,1275,1285],{},[206,1243,1244,1247],{},[209,1245,1246],{},"Full locale sets"," (moment, date libraries, i18n bundles): switch to modular date libraries or load locales dynamically per user language.",[206,1249,1250,1253,1254,1257,1258,1261,1262,1231,1265,1268],{},[209,1251,1252],{},"Development builds in production",": a library resolved through a ",[30,1255,1256],{},"browser"," or ",[30,1259,1260],{},"development"," condition — check ",[30,1263,1264],{},"resolve.conditions",[30,1266,1267],{},"NODE_ENV"," defines.",[206,1270,1271,1274],{},[209,1272,1273],{},"Polyfills for features every target supports",": tighten Browserslist and the build target.",[206,1276,1277,1280,1281,1284],{},[209,1278,1279],{},"JSON or SVG inlined into JS",": load large data with ",[30,1282,1283],{},"fetch"," and import SVG as URLs rather than components, unless they are tiny.",[206,1286,1287,1290,1291,1294,1295,1298],{},[209,1288,1289],{},"Two copies of the framework",": usually a linked local package with its own ",[30,1292,1293],{},"node_modules","; use ",[30,1296,1297],{},"resolve.dedupe",".",[198,1300,1302],{"id":1301},"faq","FAQ",[1304,1305,1308,1312],"details",{"className":1306},[1307],"faq-item",[1309,1310,1311],"summary",{},"Why does the visualiser total differ from the files in dist?",[15,1313,1314],{},"The plugin measures module contributions within chunks, sometimes before final minification or without Rollup's runtime helpers, and its gzip estimates compress each module separately rather than the whole file. Treat its numbers as relative — which modules are large — and use the actual emitted files for absolute budgets.",[1304,1316,1318,1321],{"className":1317},[1307],[1309,1319,1320],{},"Is vite-bundle-visualizer different?",[15,1322,1323,1324,1326],{},"It is a thin CLI wrapper that runs your Vite build with ",[30,1325,32],{}," configured, so you do not need to edit your config. The output and views are the same.",[1304,1328,1330,1333],{"className":1329},[1307],[1309,1331,1332],{},"Can it analyse the SSR bundle?",[15,1334,1335],{},"Yes, if the plugin runs during the SSR build too. The server bundle's size rarely matters for Core Web Vitals, but analysing it can reveal code accidentally shared with the client or dependencies that should be externalised.",[198,1337,1339],{"id":1338},"related","Related",[203,1341,1342,1349,1356],{},[206,1343,1344,1348],{},[19,1345,1347],{"href":1346},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fconfiguring-manualchunks-in-vite\u002F","Configuring manualChunks in Vite"," — acting on what the treemap shows.",[206,1350,1351,1355],{},[19,1352,1354],{"href":1353},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fwebpack-bundle-analysis-techniques\u002Fhow-to-configure-webpack-bundle-analyzer-for-production\u002F","How to configure webpack-bundle-analyzer for production"," — the webpack counterpart.",[206,1357,1358,1362],{},[19,1359,1361],{"href":1360},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fwebpack-bundle-analysis-techniques\u002Ffinding-bundle-bloat-with-source-map-explorer\u002F","Finding bundle bloat with source-map-explorer"," — a bundler-agnostic view from source maps.",[1364,1365,1367],"script",{"type":1366},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Analyze Vite Bundles with rollup-plugin-visualizer\",\n  \"description\": \"How to set up rollup-plugin-visualizer for Vite, read its views correctly, and turn what you find into smaller, better-split bundles.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Configure the plugin for useful output\",\n      \"text\": \"Expected outcome: an interactive report you can filter by chunk and module.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Use the right view for the question\",\n      \"text\": \"Use the right view for the question\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Trace why a module is included\",\n      \"text\": \"In the network view, select the surprising module and follow its importers back to your code.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Compare reports between builds in CI\",\n      \"text\": \"Emit raw-data JSON on the main branch and on each pull request, and post a size diff per chunk as a PR comment.\"\n    }\n  ]\n}\n",[1364,1369,1370],{"type":1366},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Analyze Vite Bundles with rollup-plugin-visualizer\",\n  \"description\": \"How to set up rollup-plugin-visualizer for Vite, read its views correctly, and turn what you find into smaller, better-split bundles.\",\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\u002Fvite-and-rollup-build-optimization\u002Fanalyzing-vite-bundles-with-rollup-plugin-visualizer\u002F\"\n  }\n}\n",[1364,1372,1373],{"type":1366},"\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\": \"Vite & Rollup Build Optimization\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Analyzing Vite Bundles with rollup-plugin-visualizer\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fanalyzing-vite-bundles-with-rollup-plugin-visualizer\u002F\"\n    }\n  ]\n}\n",[1375,1376,1377],"style",{},"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 .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}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}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);}",{"title":367,"searchDepth":380,"depth":380,"links":1379},[1380,1381,1382,1388,1389,1390,1391,1392],{"id":200,"depth":380,"text":201},{"id":239,"depth":380,"text":240},{"id":354,"depth":380,"text":355,"children":1383},[1384,1385,1386,1387],{"id":359,"depth":401,"text":360},{"id":572,"depth":401,"text":573},{"id":717,"depth":401,"text":718},{"id":791,"depth":401,"text":792},{"id":1212,"depth":380,"text":1213},{"id":1219,"depth":380,"text":1220},{"id":1238,"depth":380,"text":1239},{"id":1301,"depth":380,"text":1302},{"id":1338,"depth":380,"text":1339},"How to set up rollup-plugin-visualizer for Vite, read its views correctly, and turn what you find into smaller, better-split bundles.","md",{"slug":1396,"type":1397,"breadcrumb":1398,"datePublished":1406,"dateModified":1406},"analyzing-vite-bundles-with-rollup-plugin-visualizer","article",[1399,1402,1403,1404],{"name":1400,"url":1401},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1405},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fanalyzing-vite-bundles-with-rollup-plugin-visualizer\u002F","2026-10-06",true,"\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fanalyzing-vite-bundles-with-rollup-plugin-visualizer",{"title":5,"description":1410},"Generate treemap, sunburst and network views of a Vite build, read rendered vs gzip sizes, find duplicate and misplaced modules, and track bundle changes in PRs.","javascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fanalyzing-vite-bundles-with-rollup-plugin-visualizer\u002Findex","7ZD4XhVeLD8RC20F6_y5AOpXQB1UsQVkYfkyU3Q-wKc",[1414,1417],{"title":22,"path":1415,"stem":1416,"children":-1},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization","javascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Findex",{"title":1418,"path":1419,"stem":1420,"children":-1},"Building Tree-Shakeable Libraries with Vite Library Mode","\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fbuilding-tree-shakeable-libraries-with-vite-library-mode","javascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fbuilding-tree-shakeable-libraries-with-vite-library-mode\u002Findex",1791308077634]