[{"data":1,"prerenderedAt":1102},["ShallowReactive",2],{"content:\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Ftargeting-baseline-browsers-with-esbuild-and-swc":3,"surroundings:\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Ftargeting-baseline-browsers-with-esbuild-and-swc":1093},{"id":4,"title":5,"body":6,"description":1073,"extension":1074,"meta":1075,"navigation":1087,"path":1088,"seo":1089,"stem":1091,"__hash__":1092},"content\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Ftargeting-baseline-browsers-with-esbuild-and-swc\u002Findex.md","Targeting Baseline Browsers with esbuild and SWC",{"type":7,"value":8,"toc":1057},"minimark",[9,14,29,32,145,150,228,232,242,251,257,263,335,339,344,435,507,510,514,523,565,568,572,583,747,750,880,884,890,894,897,901,939,943,958,962,973,977,993,1002,1015,1019,1042,1047,1050,1053],[10,11,13],"h1",{"id":12},"how-to-target-baseline-browsers-with-esbuild-and-swc","How to Target Baseline Browsers with esbuild and SWC",[15,16,17,18,23,24,28],"p",{},"This guide covers the syntax side of ",[19,20,22],"a",{"href":21},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002F","Polyfills & Differential Serving",", part of ",[19,25,27],{"href":26},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript Bundle Optimization & Code Splitting",". Most modern toolchains no longer use Babel for transpilation: Vite uses esbuild for production syntax lowering, Next.js uses SWC, and Rspack, Turbopack, Parcel and others use one of the two. Each has its own notion of a \"target\", and getting it right determines whether your classes, async functions, optional chaining and object spread ship as written or as longer, slower emulations.",[15,30,31],{},"\"Baseline\" — the web platform's shared definition of features available across all major engines — gives a principled target. Baseline \"widely available\" features have been supported in every major browser for at least 30 months. Targeting browsers that support those features means virtually no syntax lowering for code written in modern JavaScript, while still covering the overwhelming majority of real traffic.",[15,33,34],{},[35,36,42,43,42,50,42,54,42,57,42,66,42,72,42,81,42,87,42,92,42,97,42,100,42,103,42,106,42,109,42,112,42,115,42,120,42,124,42,126,42,130,42,132,42,135,42,137,42,140,42,142,42],"svg",{"viewBox":37,"width":38,"role":39,"ariaLabel":40,"style":41},"0 0 760 228","100%","img","Comparison of output characteristics for one source file compiled with an ES2015 target and with a modern Baseline target.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[44,45],"rect",{"className":46,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],"svg-canvas","0","#ffffff",[51,52,53],"title",{},"Same source, two targets",[55,56,40],"desc",{},[44,58],{"x":59,"y":59,"width":60,"height":61,"rx":62,"fill":63,"stroke":64,"style":65},"1","758","226","10","none","currentColor","stroke-opacity:0.18",[67,68,53],"text",{"x":69,"y":70,"fill":64,"style":71},"28.0","34.0","font-size:16px;font-weight:700",[44,73],{"x":69,"y":74,"width":75,"height":76,"rx":77,"fill":78,"stroke":79,"style":80},"56.0","340.0","150.0","6","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[67,82,86],{"x":83,"y":84,"fill":64,"style":85},"42.0","82.0","font-size:14px;font-weight:700","target: es2015",[67,88,91],{"x":83,"y":89,"fill":64,"style":90},"108.0","font-size:12.5px;font-weight:700","•",[67,93,96],{"x":74,"y":89,"fill":64,"style":94,"textAnchor":95},"font-size:12.5px","start","async\u002Fawait → generator state machines",[67,98,91],{"x":83,"y":99,"fill":64,"style":90},"132.0",[67,101,102],{"x":74,"y":99,"fill":64,"style":94,"textAnchor":95},"Class fields → constructor assignments + helpers",[67,104,91],{"x":83,"y":105,"fill":64,"style":90},"156.0",[67,107,108],{"x":74,"y":105,"fill":64,"style":94,"textAnchor":95},"?. and ?? → ternary chains",[67,110,91],{"x":83,"y":111,"fill":64,"style":90},"180.0",[67,113,114],{"x":74,"y":111,"fill":64,"style":94,"textAnchor":95},"~18% larger, slower to parse",[44,116],{"x":117,"y":74,"width":75,"height":76,"rx":77,"fill":118,"stroke":118,"style":119},"392.0","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[67,121,123],{"x":122,"y":84,"fill":64,"style":85},"406.0","target: Baseline browsers",[67,125,91],{"x":122,"y":89,"fill":64,"style":90},[67,127,129],{"x":128,"y":89,"fill":64,"style":94,"textAnchor":95},"420.0","Syntax emitted as written",[67,131,91],{"x":122,"y":99,"fill":64,"style":90},[67,133,134],{"x":128,"y":99,"fill":64,"style":94,"textAnchor":95},"No helper functions injected",[67,136,91],{"x":122,"y":105,"fill":64,"style":90},[67,138,139],{"x":128,"y":105,"fill":64,"style":94,"textAnchor":95},"Shorter code, faster parse",[67,141,91],{"x":122,"y":111,"fill":64,"style":90},[67,143,144],{"x":128,"y":111,"fill":64,"style":94,"textAnchor":95},"Native engine optimisations apply",[146,147,149],"h2",{"id":148},"rapid-diagnosis","Rapid Diagnosis",[151,152,153,189,212,218],"ul",{},[154,155,156,160,161,165,166,169,170,173,174,177,178,181,182,169,185,188],"li",{},[157,158,159],"strong",{},"Check the current target."," Vite: ",[162,163,164],"code",{},"build.target","; Next.js: ",[162,167,168],{},"browserslist"," in ",[162,171,172],{},"package.json"," (read by SWC); esbuild: ",[162,175,176],{},"--target","; SWC standalone: ",[162,179,180],{},"jsc.target"," or ",[162,183,184],{},"env.targets",[162,186,187],{},".swcrc",".",[154,190,191,42,194,197,198,197,201,204,205,197,208,211],{},[157,192,193],{},"Grep the output for lowering artefacts:",[162,195,196],{},"__async",", ",[162,199,200],{},"__publicField",[162,202,203],{},"__spreadValues"," (esbuild helpers) or ",[162,206,207],{},"_async_to_generator",[162,209,210],{},"_define_property"," (SWC helpers).",[154,213,214,217],{},[157,215,216],{},"Compare with your analytics."," Confirm the browsers in the target cover your traffic — and that you are not targeting far below what your traffic needs.",[154,219,220,223,224,227],{},[157,221,222],{},"Check dependencies."," Code in ",[162,225,226],{},"node_modules"," may not be transpiled at all; your target then affects only your own code.",[146,229,231],{"id":230},"root-cause-analysis","Root Cause Analysis",[15,233,234,237,238,241],{},[157,235,236],{},"1. Conservative defaults copied forward."," Projects created when ",[162,239,240],{},"es2015"," was the safe choice keep it indefinitely.",[15,243,244,42,247,250],{},[157,245,246],{},"2. Targets expressed as ES versions instead of browsers.",[162,248,249],{},"es2017"," sounds modern, but forces lowering of everything newer (object spread, optional chaining, class fields), which all current browsers support.",[15,252,253,256],{},[157,254,255],{},"3. Mismatch with Browserslist."," esbuild ignores Browserslist; SWC reads it only when its own targets are unset. CSS and JS can end up targeting different browsers.",[15,258,259,262],{},[157,260,261],{},"4. Fear of breaking old devices without data."," Teams keep low targets because nobody has checked what visitors actually run.",[15,264,265],{},[35,266,42,269,42,272,42,275,42,277,42,280,42,282,42,288,42,295,42,300,42,303,42,307,42,311,42,314,42,319,42,323,42,327,42,331,42],{"viewBox":267,"width":38,"role":39,"ariaLabel":268,"style":41},"0 0 760 194","Bar chart of minified bundle size for the same application compiled with four syntax targets.",[44,270],{"className":271,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],[51,273,274],{},"Output size of one app by syntax target (minified, uncompressed)",[55,276,268],{},[44,278],{"x":59,"y":59,"width":60,"height":279,"rx":62,"fill":63,"stroke":64,"style":65},"192",[67,281,274],{"x":69,"y":70,"fill":64,"style":71},[67,283,240],{"x":284,"y":285,"fill":64,"style":286,"textAnchor":287},"181.9","70.0","font-size:13px","end",[44,289],{"x":290,"y":74,"width":291,"height":292,"rx":293,"fill":78,"stroke":79,"style":294},"193.9","474.1","19","3","fill-opacity:0.7;stroke-opacity:0.9",[67,296,299],{"x":297,"y":285,"fill":64,"style":298},"674.0","font-size:12px;font-weight:600","612KB",[67,301,249],{"x":284,"y":302,"fill":64,"style":286,"textAnchor":287},"101.0",[44,304],{"x":290,"y":305,"width":306,"height":292,"rx":293,"fill":78,"stroke":79,"style":294},"87.0","442.3",[67,308,310],{"x":309,"y":302,"fill":64,"style":298},"642.2","571KB",[67,312,313],{"x":284,"y":99,"fill":64,"style":286,"textAnchor":287},"es2020",[44,315],{"x":290,"y":316,"width":317,"height":292,"rx":293,"fill":118,"stroke":118,"style":318},"118.0","409.8","fill-opacity:0.55;stroke-opacity:0.9",[67,320,322],{"x":321,"y":99,"fill":64,"style":298},"609.7","529KB",[67,324,326],{"x":284,"y":325,"fill":64,"style":286,"textAnchor":287},"163.0","Baseline browsers (2023+)",[44,328],{"x":290,"y":329,"width":330,"height":292,"rx":293,"fill":118,"stroke":118,"style":318},"149.0","401.3",[67,332,334],{"x":333,"y":325,"fill":64,"style":298},"601.2","518KB",[146,336,338],{"id":337},"step-by-step-resolution","Step-by-Step Resolution",[340,341,343],"h3",{"id":342},"_1-express-the-target-as-browsers","1. Express the target as browsers",[345,346,351],"pre",{"className":347,"code":348,"language":349,"meta":350,"style":350},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F vite.config.js — esbuild needs explicit engine versions.\nexport default {\n  build: { target: ['chrome111', 'edge111', 'firefox114', 'safari16.4'] },\n};\n\u002F\u002F trade-off: hard-coded versions go stale. Generate them from Browserslist\n\u002F\u002F (browserslist-to-esbuild) so one policy file drives everything, and revisit\n\u002F\u002F the policy twice a year.\n","javascript","",[162,352,353,362,376,408,417,423,429],{"__ignoreMap":350},[354,355,358],"span",{"class":356,"line":357},"line",1,[354,359,361],{"class":360},"sjfSM","\u002F\u002F vite.config.js — esbuild needs explicit engine versions.\n",[354,363,365,369,372],{"class":356,"line":364},2,[354,366,368],{"class":367},"sPARh","export",[354,370,371],{"class":367}," default",[354,373,375],{"class":374},"sQw3B"," {\n",[354,377,379,383,387,389,392,394,397,399,402,405],{"class":356,"line":378},3,[354,380,382],{"class":381},"saISM","  build: { target: [",[354,384,386],{"class":385},"sZ8jY","'chrome111'",[354,388,197],{"class":381},[354,390,391],{"class":385},"'edge111'",[354,393,197],{"class":381},[354,395,396],{"class":385},"'firefox114'",[354,398,197],{"class":381},[354,400,401],{"class":385},"'safari16.4'",[354,403,404],{"class":381},"] }",[354,406,407],{"class":374},",\n",[354,409,411,414],{"class":356,"line":410},4,[354,412,413],{"class":374},"}",[354,415,416],{"class":381},";\n",[354,418,420],{"class":356,"line":419},5,[354,421,422],{"class":360},"\u002F\u002F trade-off: hard-coded versions go stale. Generate them from Browserslist\n",[354,424,426],{"class":356,"line":425},6,[354,427,428],{"class":360},"\u002F\u002F (browserslist-to-esbuild) so one policy file drives everything, and revisit\n",[354,430,432],{"class":356,"line":431},7,[354,433,434],{"class":360},"\u002F\u002F the policy twice a year.\n",[345,436,440],{"className":437,"code":438,"language":439,"meta":350,"style":350},"language-json shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","{\n  \"jsc\": { \"parser\": { \"syntax\": \"typescript\", \"tsx\": true } },\n  \"env\": { \"targets\": \"chrome >= 111, edge >= 111, firefox >= 114, safari >= 16.4\" }\n}\n","json",[162,441,442,447,484,502],{"__ignoreMap":350},[354,443,444],{"class":356,"line":357},[354,445,446],{"class":381},"{\n",[354,448,449,453,456,459,461,464,467,470,472,475,477,481],{"class":356,"line":364},[354,450,452],{"class":451},"sZBmE","  \"jsc\"",[354,454,455],{"class":381},": { ",[354,457,458],{"class":451},"\"parser\"",[354,460,455],{"class":381},[354,462,463],{"class":451},"\"syntax\"",[354,465,466],{"class":381},": ",[354,468,469],{"class":385},"\"typescript\"",[354,471,197],{"class":381},[354,473,474],{"class":451},"\"tsx\"",[354,476,466],{"class":381},[354,478,480],{"class":479},"sPXB4","true",[354,482,483],{"class":381}," } },\n",[354,485,486,489,491,494,496,499],{"class":356,"line":378},[354,487,488],{"class":451},"  \"env\"",[354,490,455],{"class":381},[354,492,493],{"class":451},"\"targets\"",[354,495,466],{"class":381},[354,497,498],{"class":385},"\"chrome >= 111, edge >= 111, firefox >= 114, safari >= 16.4\"",[354,500,501],{"class":381}," }\n",[354,503,504],{"class":356,"line":410},[354,505,506],{"class":381},"}\n",[15,508,509],{},"Expected outcome: syntax supported by those engines is emitted untouched.",[340,511,513],{"id":512},"_2-keep-nextjs-and-swc-on-browserslist","2. Keep Next.js and SWC on Browserslist",[15,515,516,517,519,520,522],{},"Next.js reads ",[162,518,168],{}," from ",[162,521,172],{}," for SWC syntax lowering and polyfill decisions; its default already targets modern browsers. Make sure nothing overrides it.",[345,524,526],{"className":437,"code":525,"language":439,"meta":350,"style":350},"{\n  \"browserslist\": [\"chrome 111\", \"edge 111\", \"firefox 114\", \"safari 16.4\"]\n}\n",[162,527,528,532,561],{"__ignoreMap":350},[354,529,530],{"class":356,"line":357},[354,531,446],{"class":381},[354,533,534,537,540,543,545,548,550,553,555,558],{"class":356,"line":364},[354,535,536],{"class":451},"  \"browserslist\"",[354,538,539],{"class":381},": [",[354,541,542],{"class":385},"\"chrome 111\"",[354,544,197],{"class":381},[354,546,547],{"class":385},"\"edge 111\"",[354,549,197],{"class":381},[354,551,552],{"class":385},"\"firefox 114\"",[354,554,197],{"class":381},[354,556,557],{"class":385},"\"safari 16.4\"",[354,559,560],{"class":381},"]\n",[354,562,563],{"class":356,"line":378},[354,564,506],{"class":381},[15,566,567],{},"Expected outcome: SWC output matches the same matrix as your CSS tooling. (JSON cannot carry a trade-off comment; the trade-off is the same as above — revisit the list as browsers age out.)",[340,569,571],{"id":570},"_3-handle-runtime-gaps-separately-from-syntax","3. Handle runtime gaps separately from syntax",[15,573,574,575,578,579,582],{},"esbuild and SWC lower syntax; they do not polyfill APIs (SWC can inject ",[162,576,577],{},"core-js"," via ",[162,580,581],{},"env.mode",", esbuild cannot). For the few APIs missing in your targets, add explicit, feature-detected polyfills.",[345,584,586],{"className":347,"code":585,"language":349,"meta":350,"style":350},"\u002F\u002F polyfills.js — imported first in the entry, only what the matrix lacks.\nif (!Array.prototype.findLast) {\n  Array.prototype.findLast = function (fn, thisArg) {\n    for (let i = this.length - 1; i >= 0; i--) if (fn.call(thisArg, this[i], i, this)) return this[i];\n  };\n}\n\u002F\u002F trade-off: hand-written polyfills are small but not spec-complete. Use\n\u002F\u002F core-js modules for anything non-trivial (Intl, iterators, structured clone).\n",[162,587,588,593,615,649,727,732,736,741],{"__ignoreMap":350},[354,589,590],{"class":356,"line":357},[354,591,592],{"class":360},"\u002F\u002F polyfills.js — imported first in the entry, only what the matrix lacks.\n",[354,594,595,598,601,604,607,609,612],{"class":356,"line":364},[354,596,597],{"class":367},"if",[354,599,600],{"class":381}," (",[354,602,603],{"class":367},"!",[354,605,606],{"class":479},"Array",[354,608,188],{"class":381},[354,610,611],{"class":479},"prototype",[354,613,614],{"class":381},".findLast) {\n",[354,616,617,620,622,624,626,630,633,636,638,641,643,646],{"class":356,"line":378},[354,618,619],{"class":479},"  Array",[354,621,188],{"class":381},[354,623,611],{"class":479},[354,625,188],{"class":381},[354,627,629],{"class":628},"smZ65","findLast",[354,631,632],{"class":367}," =",[354,634,635],{"class":367}," function",[354,637,600],{"class":381},[354,639,640],{"class":374},"fn",[354,642,197],{"class":381},[354,644,645],{"class":374},"thisArg",[354,647,648],{"class":381},") {\n",[354,650,651,654,656,659,662,665,668,670,673,676,679,682,685,688,691,694,697,699,702,705,708,711,714,716,719,722,724],{"class":356,"line":410},[354,652,653],{"class":367},"    for",[354,655,600],{"class":381},[354,657,658],{"class":367},"let",[354,660,661],{"class":381}," i ",[354,663,664],{"class":367},"=",[354,666,667],{"class":479}," this",[354,669,188],{"class":381},[354,671,672],{"class":479},"length",[354,674,675],{"class":367}," -",[354,677,678],{"class":479}," 1",[354,680,681],{"class":381},"; i ",[354,683,684],{"class":367},">=",[354,686,687],{"class":479}," 0",[354,689,690],{"class":381},"; i",[354,692,693],{"class":367},"--",[354,695,696],{"class":381},") ",[354,698,597],{"class":367},[354,700,701],{"class":381}," (fn.",[354,703,704],{"class":628},"call",[354,706,707],{"class":381},"(thisArg, ",[354,709,710],{"class":479},"this",[354,712,713],{"class":381},"[i], i, ",[354,715,710],{"class":479},[354,717,718],{"class":381},")) ",[354,720,721],{"class":367},"return",[354,723,667],{"class":479},[354,725,726],{"class":381},"[i];\n",[354,728,729],{"class":356,"line":419},[354,730,731],{"class":381},"  };\n",[354,733,734],{"class":356,"line":425},[354,735,506],{"class":381},[354,737,738],{"class":356,"line":431},[354,739,740],{"class":360},"\u002F\u002F trade-off: hand-written polyfills are small but not spec-complete. Use\n",[354,742,744],{"class":356,"line":743},8,[354,745,746],{"class":360},"\u002F\u002F core-js modules for anything non-trivial (Intl, iterators, structured clone).\n",[15,748,749],{},"Expected outcome: syntax native, APIs present, no blanket polyfill library.",[15,751,752],{},[35,753,42,756,42,759,42,762,42,764,42,767,42,769,42,774,42,779,42,783,42,788,42,791,42,795,42,799,42,803,42,805,42,808,42,810,42,813,42,816,42,820,42,822,42,825,42,827,42,830,42,833,42,837,42,839,42,842,42,844,42,847,42,850,42,854,42,856,42,858,42,860,42,863,42,866,42,870,42,872,42,875,42,877,42],{"viewBox":754,"width":38,"role":39,"ariaLabel":755,"style":41},"0 0 760 258","Common esbuild- and SWC-based toolchains with where their syntax target is configured and whether they read Browserslist.",[44,757],{"className":758,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],[51,760,761],{},"Where each toolchain reads its target",[55,763,755],{},[44,765],{"x":59,"y":59,"width":60,"height":766,"rx":62,"fill":63,"stroke":64,"style":65},"256",[67,768,761],{"x":69,"y":70,"fill":64,"style":71},[44,770],{"x":69,"y":74,"width":771,"height":772,"rx":48,"fill":64,"stroke":64,"style":773},"143.3","30.0","fill-opacity:0.06;stroke-opacity:0.4",[67,775,778],{"x":776,"y":777,"fill":64,"style":90,"textAnchor":95},"38.0","75.5","Toolchain",[44,780],{"x":781,"y":74,"width":782,"height":772,"rx":48,"fill":64,"stroke":64,"style":773},"171.3","280.4",[67,784,787],{"x":785,"y":777,"fill":64,"style":90,"textAnchor":786},"311.5","middle","Target setting",[44,789],{"x":790,"y":74,"width":782,"height":772,"rx":48,"fill":64,"stroke":64,"style":773},"451.6",[67,792,794],{"x":793,"y":777,"fill":64,"style":90,"textAnchor":786},"591.8","Reads Browserslist",[44,796],{"x":69,"y":797,"width":771,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},"86.0","stroke-opacity:0.35",[67,800,802],{"x":776,"y":801,"fill":64,"style":90,"textAnchor":95},"105.5","Vite (esbuild)",[44,804],{"x":781,"y":797,"width":782,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},[67,806,164],{"x":785,"y":801,"fill":64,"style":807,"textAnchor":786},"font-size:12px",[44,809],{"x":790,"y":797,"width":782,"height":772,"rx":48,"fill":78,"stroke":79,"style":80},[67,811,812],{"x":793,"y":801,"fill":64,"style":807,"textAnchor":786},"no — convert it",[44,814],{"x":69,"y":815,"width":771,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},"116.0",[67,817,819],{"x":776,"y":818,"fill":64,"style":90,"textAnchor":95},"135.5","Next.js (SWC)",[44,821],{"x":781,"y":815,"width":782,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},[67,823,824],{"x":785,"y":818,"fill":64,"style":807,"textAnchor":786},"package.json browserslist",[44,826],{"x":790,"y":815,"width":782,"height":772,"rx":48,"fill":118,"stroke":118,"style":119},[67,828,829],{"x":793,"y":818,"fill":64,"style":807,"textAnchor":786},"yes",[44,831],{"x":69,"y":832,"width":771,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},"146.0",[67,834,836],{"x":776,"y":835,"fill":64,"style":90,"textAnchor":95},"165.5","SWC standalone",[44,838],{"x":781,"y":832,"width":782,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},[67,840,841],{"x":785,"y":835,"fill":64,"style":807,"textAnchor":786},"env.targets or jsc.target",[44,843],{"x":790,"y":832,"width":782,"height":772,"rx":48,"fill":64,"stroke":64,"style":773},[67,845,846],{"x":793,"y":835,"fill":64,"style":807,"textAnchor":786},"if env.targets unset",[44,848],{"x":69,"y":849,"width":771,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},"176.0",[67,851,853],{"x":776,"y":852,"fill":64,"style":90,"textAnchor":95},"195.5","esbuild CLI",[44,855],{"x":781,"y":849,"width":782,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},[67,857,176],{"x":785,"y":852,"fill":64,"style":807,"textAnchor":786},[44,859],{"x":790,"y":849,"width":782,"height":772,"rx":48,"fill":78,"stroke":79,"style":80},[67,861,862],{"x":793,"y":852,"fill":64,"style":807,"textAnchor":786},"no",[44,864],{"x":69,"y":865,"width":771,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},"206.0",[67,867,869],{"x":776,"y":868,"fill":64,"style":90,"textAnchor":95},"225.5","Rspack (SWC loader)",[44,871],{"x":781,"y":865,"width":782,"height":772,"rx":48,"fill":63,"stroke":64,"style":798},[67,873,874],{"x":785,"y":868,"fill":64,"style":807,"textAnchor":786},"builtin:swc-loader env",[44,876],{"x":790,"y":865,"width":782,"height":772,"rx":48,"fill":64,"stroke":64,"style":773},[67,878,879],{"x":793,"y":868,"fill":64,"style":807,"textAnchor":786},"configurable",[340,881,883],{"id":882},"_4-verify-dependencies-are-compatible-with-the-target","4. Verify dependencies are compatible with the target",[15,885,886,887,889],{},"Raising your target never breaks dependencies, but lowering it does not fix dependencies shipping newer syntax unless you transpile ",[162,888,226],{},". Run your smoke tests in the oldest targeted engine to catch both kinds of problem.",[146,891,893],{"id":892},"verification","Verification",[15,895,896],{},"Grep the output for helper names; with a Baseline target there should be few or none. Compare minified sizes before and after, and run a throttled trace on a key route: parse\u002Fcompile time in the Bottom-Up view (look for \"Compile Script\" and \"Parse\" entries) should drop roughly in proportion to the size reduction. Run end-to-end tests in WebKit and Firefox at the oldest versions you target.",[146,898,900],{"id":899},"common-mistakes","Common Mistakes",[151,902,903,913,927,933],{},[154,904,905,912],{},[157,906,907,908,911],{},"Using ",[162,909,910],{},"esnext"," as a target."," It emits syntax that may not yet be supported anywhere (stage proposals in some setups). Target real browsers.",[154,914,915,922,923,926],{},[157,916,917,918,921],{},"Setting the TypeScript ",[162,919,920],{},"target"," low while esbuild does the bundling."," Vite ignores ",[162,924,925],{},"tsconfig"," target for output, but other toolchains may honour it; keep them consistent.",[154,928,929,932],{},[157,930,931],{},"Forgetting decorators."," Decorator syntax requires transformation in most targets; it is handled separately from the general target and can add helpers regardless.",[154,934,935,938],{},[157,936,937],{},"Assuming smaller output means faster runtime everywhere."," Native syntax is generally faster, but measure hot paths if you rely on heavily optimised legacy patterns.",[146,940,942],{"id":941},"baseline-as-a-policy-not-just-a-target","Baseline as a Policy, Not Just a Target",[15,944,945,946,949,950,953,954,957],{},"Baseline is useful beyond build configuration because it gives product, design and engineering a shared vocabulary. \"We use Baseline widely available features freely, newly available features with fallbacks, and anything else only behind feature detection\" is a policy that applies equally to CSS (",[162,947,948],{},":has()",", container queries), HTML (",[162,951,952],{},"\u003Cdialog>",", popover) and JavaScript APIs. Tools such as the ",[162,955,956],{},"baseline-browser-mapping"," data and linting rules can flag usage of non-Baseline features in code review, which keeps the target honest: there is little point setting a modern build target if the code quietly depends on features that need polyfills in half the matrix.",[146,959,961],{"id":960},"worked-example-vite-target-mismatch","Worked Example: Vite Target Mismatch",[15,963,964,965,968,969,972],{},"A Vite application had ",[162,966,967],{},"build.target: 'es2015'"," set explicitly in its config — a leftover from a migration from webpack — while its Browserslist (used for CSS) was modern. The JavaScript output contained esbuild helpers for async functions, class fields and spread throughout, and was 14% larger than necessary. Replacing the explicit target with ",[162,970,971],{},"browserslistToEsbuild()"," aligned JavaScript with CSS, removed the helpers, and reduced compile time for the main chunk by roughly 20ms on a 4x-throttled trace. Because esbuild never adds polyfills, nothing else changed — a reminder that with esbuild, target and polyfills are separate decisions.",[146,974,976],{"id":975},"faq","FAQ",[978,979,982,986],"details",{"className":980},[981],"faq-item",[983,984,985],"summary",{},"Is esbuild's output as small as Terser's?",[15,987,988,989,188],{},"esbuild minification is close to Terser's — usually within a few percent — and far faster. The syntax target has a bigger effect on size than the choice of minifier for most codebases. See ",[19,990,992],{"href":991},"\u002Fjavascript-bundle-optimization-code-splitting\u002Ftree-shaking-and-dead-code-elimination\u002Fesbuild-vs-terser-for-production-minification\u002F","esbuild vs Terser for production minification",[978,994,996,999],{"className":995},[981],[983,997,998],{},"What about class fields and older Safari?",[15,1000,1001],{},"Class fields (public and private) are supported in Safari 14.1+\u002F15+ and all current engines. If your matrix includes older Safari, the target will cause lowering — correct, but a reminder to check whether that Safari version is actually in your traffic.",[978,1003,1005,1008],{"className":1004},[981],[983,1006,1007],{},"Does Next.js polyfill anything by default?",[15,1009,1010,1011,1014],{},"Next.js includes a small set of polyfills for older browsers via ",[162,1012,1013],{},"nomodule"," and polyfills certain APIs used by its runtime. Your own code's API polyfills are your responsibility; add them deliberately rather than importing a full polyfill library.",[146,1016,1018],{"id":1017},"related","Related",[151,1020,1021,1028,1035],{},[154,1022,1023,1027],{},[19,1024,1026],{"href":1025},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Fremoving-unneeded-polyfills-with-browserslist\u002F","Removing unneeded polyfills with Browserslist"," — the policy that should drive these targets.",[154,1029,1030,1034],{},[19,1031,1033],{"href":1032},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fvite-and-rollup-build-optimization\u002Fconfiguring-manualchunks-in-vite\u002F","Configuring manualChunks in Vite"," — the other half of a lean Vite build.",[154,1036,1037,1041],{},[19,1038,1040],{"href":1039},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fjavascript-performance-budgets\u002Fmeasuring-javascript-parse-and-compile-cost\u002F","Measuring JavaScript parse and compile cost"," — confirming the parse-time gains.",[1043,1044,1046],"script",{"type":1045},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Target Baseline Browsers with esbuild and SWC\",\n  \"description\": \"How to configure syntax targets in esbuild- and SWC-based toolchains for a modern Baseline browser set, and what changes in output size and parse time.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Express the target as browsers\",\n      \"text\": \"Expected outcome: syntax supported by those engines is emitted untouched.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Keep Next.js and SWC on Browserslist\",\n      \"text\": \"Next.js reads browserslist from package.json for SWC syntax lowering and polyfill decisions; its default already targets modern browsers.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Handle runtime gaps separately from syntax\",\n      \"text\": \"esbuild and SWC lower syntax; they do not polyfill APIs (SWC can inject core-js via env.mode, esbuild cannot).\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Verify dependencies are compatible with the target\",\n      \"text\": \"Raising your target never breaks dependencies, but lowering it does not fix dependencies shipping newer syntax unless you transpile node_modules.\"\n    }\n  ]\n}\n",[1043,1048,1049],{"type":1045},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Target Baseline Browsers with esbuild and SWC\",\n  \"description\": \"How to configure syntax targets in esbuild- and SWC-based toolchains for a modern Baseline browser set, and what changes in output size and parse time.\",\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\u002Fpolyfills-and-differential-serving\u002Ftargeting-baseline-browsers-with-esbuild-and-swc\u002F\"\n  }\n}\n",[1043,1051,1052],{"type":1045},"\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\": \"Polyfills & Differential Serving\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Targeting Baseline Browsers with esbuild and SWC\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Ftargeting-baseline-browsers-with-esbuild-and-swc\u002F\"\n    }\n  ]\n}\n",[1054,1055,1056],"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 .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}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 .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 .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}",{"title":350,"searchDepth":364,"depth":364,"links":1058},[1059,1060,1061,1067,1068,1069,1070,1071,1072],{"id":148,"depth":364,"text":149},{"id":230,"depth":364,"text":231},{"id":337,"depth":364,"text":338,"children":1062},[1063,1064,1065,1066],{"id":342,"depth":378,"text":343},{"id":512,"depth":378,"text":513},{"id":570,"depth":378,"text":571},{"id":882,"depth":378,"text":883},{"id":892,"depth":364,"text":893},{"id":899,"depth":364,"text":900},{"id":941,"depth":364,"text":942},{"id":960,"depth":364,"text":961},{"id":975,"depth":364,"text":976},{"id":1017,"depth":364,"text":1018},"How to configure syntax targets in esbuild- and SWC-based toolchains for a modern Baseline browser set, and what changes in output size and parse time.","md",{"slug":1076,"type":1077,"breadcrumb":1078,"datePublished":1086,"dateModified":1086},"targeting-baseline-browsers-with-esbuild-and-swc","article",[1079,1082,1083,1084],{"name":1080,"url":1081},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1085},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Ftargeting-baseline-browsers-with-esbuild-and-swc\u002F","2026-10-06",true,"\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Ftargeting-baseline-browsers-with-esbuild-and-swc",{"title":5,"description":1090},"Set esbuild and SWC targets to Baseline-supported browsers so modern syntax ships untouched, keep output small and fast to parse, and handle the few real gaps.","javascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Ftargeting-baseline-browsers-with-esbuild-and-swc\u002Findex","hDPmuSlZ0DBYVILhUVHn36a3HEBQTmkb5_oi5ZIYEhk",[1094,1098],{"title":1095,"path":1096,"stem":1097,"children":-1},"Removing Unneeded Polyfills with Browserslist","\u002Fjavascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Fremoving-unneeded-polyfills-with-browserslist","javascript-bundle-optimization-code-splitting\u002Fpolyfills-and-differential-serving\u002Fremoving-unneeded-polyfills-with-browserslist\u002Findex",{"title":1099,"path":1100,"stem":1101,"children":-1},"Third-Party Script Performance","\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance","javascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Findex",1791308070643]