[{"data":1,"prerenderedAt":1155},["ShallowReactive",2],{"content:\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console":3,"surroundings:\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console":1147},{"id":4,"title":5,"body":6,"description":1127,"extension":1128,"meta":1129,"navigation":364,"path":1141,"seo":1142,"stem":1145,"__hash__":1146},"content\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002Findex.md","Fixing Unused-Preload Warnings in the Console",{"type":7,"value":8,"toc":1119},"minimark",[9,14,34,37,42,84,222,226,236,255,261,275,284,288,293,431,434,447,583,586,592,786,789,798,802,805,808,1002,1008,1012,1027,1036,1045,1057,1066,1079,1083,1104,1109,1112,1115],[10,11,13],"h1",{"id":12},"how-to-fix-the-resource-was-preloaded-but-not-used-warnings","How to Fix \"The resource was preloaded but not used\" Warnings",[15,16,17,18,23,24,28,29,33],"p",{},"This walkthrough sits under ",[19,20,22],"a",{"href":21},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002F","Resource Hints & Early Hints"," within ",[19,25,27],{"href":26},"\u002Fadvanced-caching-strategies-cdn-architecture\u002F","Advanced Caching Strategies & CDN Architecture",". The console message is easy to dismiss and expensive to ignore: it means the browser fetched a file at high priority, on the critical path, and then never used it — either because nothing needed it, or because what needed it made a ",[30,31,32],"em",{},"different"," request and downloaded the file a second time.",[15,35,36],{},"Both outcomes waste the bandwidth you were trying to save, and the second one is worse because the page looks correct.",[38,39,41],"h2",{"id":40},"rapid-diagnosis-duplicate-or-genuinely-unused","Rapid Diagnosis: Duplicate, or Genuinely Unused?",[43,44,45,53,68,74],"ul",{},[46,47,48,52],"li",{},[49,50,51],"strong",{},"Filter the Network panel by the filename."," Two entries for the same URL means an attribute mismatch — the preload and the real request are not the same request. One entry means the resource is genuinely never needed.",[46,54,55,58,59,63,64,67],{},[49,56,57],{},"Compare the two rows' details."," Check ",[60,61,62],"code",{},"Priority",", the ",[60,65,66],{},"Accept"," header, and whether the request was sent with credentials. The difference between the rows names your bug.",[46,69,70,73],{},[49,71,72],{},"Check the initiator of the second request."," If it is a stylesheet or a script, that is the consumer whose request shape you must match.",[46,75,76,79,80,83],{},[49,77,78],{},"Time the warning."," Chrome fires it a few seconds after load. A resource used later — on interaction, for instance — will warn even though the preload was arguably reasonable; that is a signal to use ",[60,81,82],{},"prefetch"," instead.",[85,86,93,94,101,102,101,106,101,110,101,119,101,126,101,133,101,137,101,141,101,147,101,156,101,161,101,164,101,167,101,172,101,176,101,179,101,182,101,185,101,189,101,192,101,195,101,199,101,203,101,206,101,209,101,212,101,216,101,219,101],"svg",{"xmlns":87,"viewBox":88,"width":89,"role":90,"ariaLabel":91,"style":92},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","0 0 760 244","100%","img","Table of the five attribute mismatches that cause a duplicate preload request: missing crossorigin, wrong as value, mismatched type, a media query that excludes the resource, and a URL that differs by query string","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)","\n  ",[95,96],"rect",{"className":97,"x":99,"y":99,"width":89,"height":89,"fill":100},[98],"svg-canvas","0","#ffffff"," ",[103,104,105],"title",{},"The five mismatches behind a duplicated preload",[107,108,109],"desc",{},"Each row names an attribute, what the preload sent, what the real request expected, and the resulting symptom.",[95,111],{"x":112,"y":112,"width":113,"height":114,"rx":115,"fill":116,"stroke":117,"style":118},"1","758","242","10","none","currentColor","stroke-opacity:0.18",[120,121,125],"text",{"x":122,"y":123,"fill":117,"style":124},"24","32","font-size:16px;font-weight:700","Why the browser thinks they are two different resources",[120,127,132],{"x":128,"y":129,"fill":117,"style":130,"textAnchor":131},"120","62","font-size:11.5px;font-weight:700;","middle","attribute",[120,134,136],{"x":135,"y":129,"fill":117,"style":130,"textAnchor":131},"380","what goes wrong",[120,138,140],{"x":139,"y":129,"fill":117,"style":130,"textAnchor":131},"650","most common on",[142,143],"line",{"x1":122,"y1":144,"x2":145,"y2":144,"stroke":117,"style":146},"72","736","stroke-opacity:0.3",[95,148],{"x":149,"y":150,"width":151,"height":122,"rx":152,"fill":153,"stroke":154,"style":155},"30","82","180","4","#ffc300","#b8860b","fill-opacity:0.24",[120,157,160],{"x":128,"y":158,"fill":117,"style":159,"textAnchor":131},"99","font-size:11px;","crossorigin missing",[120,162,163],{"x":135,"y":158,"fill":117,"style":159,"textAnchor":131},"anonymous vs credentialed fetch",[120,165,166],{"x":139,"y":158,"fill":117,"style":159,"textAnchor":131},"fonts",[95,168],{"x":149,"y":169,"width":151,"height":122,"rx":152,"fill":170,"stroke":170,"style":171},"114","#0466c8","fill-opacity:0.16;stroke-opacity:0.5",[120,173,175],{"x":128,"y":174,"fill":117,"style":159,"textAnchor":131},"131","wrong `as`",[120,177,178],{"x":135,"y":174,"fill":117,"style":159,"textAnchor":131},"different priority and Accept header",[120,180,181],{"x":139,"y":174,"fill":117,"style":159,"textAnchor":131},"styles, scripts",[95,183],{"x":149,"y":184,"width":151,"height":122,"rx":152,"fill":170,"stroke":170,"style":171},"146",[120,186,188],{"x":128,"y":187,"fill":117,"style":159,"textAnchor":131},"163","`type` mismatch",[120,190,191],{"x":135,"y":187,"fill":117,"style":159,"textAnchor":131},"format negotiated differently",[120,193,194],{"x":139,"y":187,"fill":117,"style":159,"textAnchor":131},"fonts, images",[95,196],{"x":149,"y":197,"width":151,"height":122,"rx":152,"fill":117,"stroke":117,"style":198},"178","fill-opacity:0.08;stroke-opacity:0.35",[120,200,202],{"x":128,"y":201,"fill":117,"style":159,"textAnchor":131},"195","`media` excludes it",[120,204,205],{"x":135,"y":201,"fill":117,"style":159,"textAnchor":131},"preloaded, then never matched",[120,207,208],{"x":139,"y":201,"fill":117,"style":159,"textAnchor":131},"responsive CSS",[95,210],{"x":149,"y":211,"width":151,"height":122,"rx":152,"fill":117,"stroke":117,"style":198},"210",[120,213,215],{"x":128,"y":214,"fill":117,"style":159,"textAnchor":131},"227","URL differs",[120,217,218],{"x":135,"y":214,"fill":117,"style":159,"textAnchor":131},"query string, hash, or stale path",[120,220,221],{"x":139,"y":214,"fill":117,"style":159,"textAnchor":131},"hashed assets",[38,223,225],{"id":224},"root-cause-analysis","Root Cause Analysis",[15,227,228,235],{},[49,229,230,231,234],{},"1. Missing ",[60,232,233],{},"crossorigin"," on a font."," Fonts are always fetched in anonymous CORS mode. A preload without the attribute performs a credentialed fetch, which the browser treats as a distinct resource, so the CSS-initiated request downloads the file again. This is by far the most common cause.",[15,237,238,101,245,247,248,250,251,254],{},[49,239,240,241,244],{},"2. A wrong or absent ",[60,242,243],{},"as"," value.",[60,246,243],{}," determines the request's priority band and its ",[60,249,66],{}," header. ",[60,252,253],{},"as=\"fetch\""," on a stylesheet requests it as an opaque fetch, at a different priority, and the CSS parser will not reuse it.",[15,256,257,260],{},[49,258,259],{},"3. A stale URL after a build."," Content-hashed filenames change on every deploy. A hint written into a template or a server config by hand keeps pointing at last week's file, producing a high-priority 404 while the real asset loads normally.",[15,262,263,270,271,274],{},[49,264,265,266,269],{},"4. A ",[60,267,268],{},"media"," attribute that excludes the current viewport."," Preloading a stylesheet with ",[60,272,273],{},"media=\"(min-width: 900px)\""," on a phone fetches nothing usable; the file is downloaded and then never matched.",[15,276,277,280,281,283],{},[49,278,279],{},"5. The resource is only needed later."," A preload for something used on interaction is the wrong hint entirely — ",[60,282,82],{}," exists for that, and it will not compete with the critical path.",[38,285,287],{"id":286},"step-by-step-resolution","Step-by-Step Resolution",[15,289,290],{},[49,291,292],{},"1. Match the request shape exactly for fonts.",[294,295,300],"pre",{"className":296,"code":297,"language":298,"meta":299,"style":299},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u003C!-- Wrong: credentialed fetch, downloads twice. -->\n\u003Clink rel=\"preload\" href=\"\u002Ffonts\u002Finter-latin.woff2\" as=\"font\" type=\"font\u002Fwoff2\">\n\n\u003C!-- Right: anonymous, same shape as the CSS-initiated request. -->\n\u003Clink rel=\"preload\" href=\"\u002Ffonts\u002Finter-latin.woff2\" as=\"font\"\n      type=\"font\u002Fwoff2\" crossorigin>\n\u003C!-- trade-off: crossorigin is required even same-origin. Adding it to a\n     resource that is NOT fetched anonymously — a credentialed API response,\n     for instance — creates the mismatch in the other direction. -->\n","html","",[60,301,302,310,359,366,372,398,413,419,425],{"__ignoreMap":299},[303,304,306],"span",{"class":142,"line":305},1,[303,307,309],{"class":308},"sjfSM","\u003C!-- Wrong: credentialed fetch, downloads twice. -->\n",[303,311,313,317,321,325,328,332,335,337,340,343,345,348,351,353,356],{"class":142,"line":312},2,[303,314,316],{"class":315},"saISM","\u003C",[303,318,320],{"class":319},"sZBmE","link",[303,322,324],{"class":323},"sPXB4"," rel",[303,326,327],{"class":315},"=",[303,329,331],{"class":330},"sZ8jY","\"preload\"",[303,333,334],{"class":323}," href",[303,336,327],{"class":315},[303,338,339],{"class":330},"\"\u002Ffonts\u002Finter-latin.woff2\"",[303,341,342],{"class":323}," as",[303,344,327],{"class":315},[303,346,347],{"class":330},"\"font\"",[303,349,350],{"class":323}," type",[303,352,327],{"class":315},[303,354,355],{"class":330},"\"font\u002Fwoff2\"",[303,357,358],{"class":315},">\n",[303,360,362],{"class":142,"line":361},3,[303,363,365],{"emptyLinePlaceholder":364},true,"\n",[303,367,369],{"class":142,"line":368},4,[303,370,371],{"class":308},"\u003C!-- Right: anonymous, same shape as the CSS-initiated request. -->\n",[303,373,375,377,379,381,383,385,387,389,391,393,395],{"class":142,"line":374},5,[303,376,316],{"class":315},[303,378,320],{"class":319},[303,380,324],{"class":323},[303,382,327],{"class":315},[303,384,331],{"class":330},[303,386,334],{"class":323},[303,388,327],{"class":315},[303,390,339],{"class":330},[303,392,342],{"class":323},[303,394,327],{"class":315},[303,396,397],{"class":330},"\"font\"\n",[303,399,401,404,406,408,411],{"class":142,"line":400},6,[303,402,403],{"class":323},"      type",[303,405,327],{"class":315},[303,407,355],{"class":330},[303,409,410],{"class":323}," crossorigin",[303,412,358],{"class":315},[303,414,416],{"class":142,"line":415},7,[303,417,418],{"class":308},"\u003C!-- trade-off: crossorigin is required even same-origin. Adding it to a\n",[303,420,422],{"class":142,"line":421},8,[303,423,424],{"class":308},"     resource that is NOT fetched anonymously — a credentialed API response,\n",[303,426,428],{"class":142,"line":427},9,[303,429,430],{"class":308},"     for instance — creates the mismatch in the other direction. -->\n",[15,432,433],{},"Expected outcome: one request instead of two; the warning disappears and the font is used from the preload.",[15,435,436,442,443,446],{},[49,437,438,439,441],{},"2. Use the correct ",[60,440,243],{}," for the consumer."," The value must describe what the resource ",[30,444,445],{},"is",", not how you think of it.",[294,448,450],{"className":296,"code":449,"language":298,"meta":299,"style":299},"\u003Clink rel=\"preload\" href=\"\u002Fcss\u002Fcritical.css\" as=\"style\">\n\u003Clink rel=\"preload\" href=\"\u002Fjs\u002Froute-home.js\" as=\"script\">\n\u003Clink rel=\"modulepreload\" href=\"\u002Fjs\u002Froute-home.js\">   \u003C!-- for ES modules -->\n\u003Clink rel=\"preload\" href=\"\u002Fhero.avif\" as=\"image\" type=\"image\u002Favif\">\n\u003C!-- trade-off: modulepreload also parses the module and its import graph,\n     which costs main-thread time up front. For a large graph that can delay\n     other work — preload the entry and let the rest resolve normally. -->\n",[60,451,452,480,508,533,568,573,578],{"__ignoreMap":299},[303,453,454,456,458,460,462,464,466,468,471,473,475,478],{"class":142,"line":305},[303,455,316],{"class":315},[303,457,320],{"class":319},[303,459,324],{"class":323},[303,461,327],{"class":315},[303,463,331],{"class":330},[303,465,334],{"class":323},[303,467,327],{"class":315},[303,469,470],{"class":330},"\"\u002Fcss\u002Fcritical.css\"",[303,472,342],{"class":323},[303,474,327],{"class":315},[303,476,477],{"class":330},"\"style\"",[303,479,358],{"class":315},[303,481,482,484,486,488,490,492,494,496,499,501,503,506],{"class":142,"line":312},[303,483,316],{"class":315},[303,485,320],{"class":319},[303,487,324],{"class":323},[303,489,327],{"class":315},[303,491,331],{"class":330},[303,493,334],{"class":323},[303,495,327],{"class":315},[303,497,498],{"class":330},"\"\u002Fjs\u002Froute-home.js\"",[303,500,342],{"class":323},[303,502,327],{"class":315},[303,504,505],{"class":330},"\"script\"",[303,507,358],{"class":315},[303,509,510,512,514,516,518,521,523,525,527,530],{"class":142,"line":361},[303,511,316],{"class":315},[303,513,320],{"class":319},[303,515,324],{"class":323},[303,517,327],{"class":315},[303,519,520],{"class":330},"\"modulepreload\"",[303,522,334],{"class":323},[303,524,327],{"class":315},[303,526,498],{"class":330},[303,528,529],{"class":315},">   ",[303,531,532],{"class":308},"\u003C!-- for ES modules -->\n",[303,534,535,537,539,541,543,545,547,549,552,554,556,559,561,563,566],{"class":142,"line":368},[303,536,316],{"class":315},[303,538,320],{"class":319},[303,540,324],{"class":323},[303,542,327],{"class":315},[303,544,331],{"class":330},[303,546,334],{"class":323},[303,548,327],{"class":315},[303,550,551],{"class":330},"\"\u002Fhero.avif\"",[303,553,342],{"class":323},[303,555,327],{"class":315},[303,557,558],{"class":330},"\"image\"",[303,560,350],{"class":323},[303,562,327],{"class":315},[303,564,565],{"class":330},"\"image\u002Favif\"",[303,567,358],{"class":315},[303,569,570],{"class":142,"line":374},[303,571,572],{"class":308},"\u003C!-- trade-off: modulepreload also parses the module and its import graph,\n",[303,574,575],{"class":142,"line":400},[303,576,577],{"class":308},"     which costs main-thread time up front. For a large graph that can delay\n",[303,579,580],{"class":142,"line":415},[303,581,582],{"class":308},"     other work — preload the entry and let the rest resolve normally. -->\n",[15,584,585],{},"Expected outcome: the preloaded response lands in the right cache bucket at the right priority, and the consumer reuses it.",[15,587,588,591],{},[49,589,590],{},"3. Generate hints from the build manifest."," Any hint naming a hashed asset must come from the same source of truth as the asset.",[294,593,597],{"className":594,"code":595,"language":596,"meta":299,"style":299},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F vite\u002Fwebpack plugin sketch: emit head hints from the real emitted filenames.\nfunction emitHints(bundle) {\n  const entry = Object.values(bundle).find((c) => c.isEntry);\n  const font = Object.keys(bundle).find((f) => f.endsWith('.woff2'));\n  return [\n    `\u003Clink rel=\"modulepreload\" href=\"\u002F${entry.fileName}\">`,\n    `\u003Clink rel=\"preload\" href=\"\u002F${font}\" as=\"font\" type=\"font\u002Fwoff2\" crossorigin>`\n  ].join('\\n');\n}\n\u002F\u002F trade-off: generated hints are correct but easy to over-generate — a plugin\n\u002F\u002F that hints every emitted font will preload five faces. Filter to the ones\n\u002F\u002F the above-the-fold design actually uses.\n","javascript",[60,598,599,604,624,662,703,711,731,742,763,768,774,780],{"__ignoreMap":299},[303,600,601],{"class":142,"line":305},[303,602,603],{"class":308},"\u002F\u002F vite\u002Fwebpack plugin sketch: emit head hints from the real emitted filenames.\n",[303,605,606,610,614,617,621],{"class":142,"line":312},[303,607,609],{"class":608},"sPARh","function",[303,611,613],{"class":612},"smZ65"," emitHints",[303,615,616],{"class":315},"(",[303,618,620],{"class":619},"sQw3B","bundle",[303,622,623],{"class":315},") {\n",[303,625,626,629,632,635,638,641,644,647,650,653,656,659],{"class":142,"line":361},[303,627,628],{"class":608},"  const",[303,630,631],{"class":323}," entry",[303,633,634],{"class":608}," =",[303,636,637],{"class":315}," Object.",[303,639,640],{"class":612},"values",[303,642,643],{"class":315},"(bundle).",[303,645,646],{"class":612},"find",[303,648,649],{"class":315},"((",[303,651,652],{"class":619},"c",[303,654,655],{"class":315},") ",[303,657,658],{"class":608},"=>",[303,660,661],{"class":315}," c.isEntry);\n",[303,663,664,666,669,671,673,676,678,680,682,685,687,689,692,695,697,700],{"class":142,"line":368},[303,665,628],{"class":608},[303,667,668],{"class":323}," font",[303,670,634],{"class":608},[303,672,637],{"class":315},[303,674,675],{"class":612},"keys",[303,677,643],{"class":315},[303,679,646],{"class":612},[303,681,649],{"class":315},[303,683,684],{"class":619},"f",[303,686,655],{"class":315},[303,688,658],{"class":608},[303,690,691],{"class":315}," f.",[303,693,694],{"class":612},"endsWith",[303,696,616],{"class":315},[303,698,699],{"class":330},"'.woff2'",[303,701,702],{"class":315},"));\n",[303,704,705,708],{"class":142,"line":374},[303,706,707],{"class":608},"  return",[303,709,710],{"class":315}," [\n",[303,712,713,716,719,722,725,728],{"class":142,"line":400},[303,714,715],{"class":330},"    `\u003Clink rel=\"modulepreload\" href=\"\u002F${",[303,717,718],{"class":315},"entry",[303,720,721],{"class":330},".",[303,723,724],{"class":315},"fileName",[303,726,727],{"class":330},"}\">`",[303,729,730],{"class":315},",\n",[303,732,733,736,739],{"class":142,"line":415},[303,734,735],{"class":330},"    `\u003Clink rel=\"preload\" href=\"\u002F${",[303,737,738],{"class":315},"font",[303,740,741],{"class":330},"}\" as=\"font\" type=\"font\u002Fwoff2\" crossorigin>`\n",[303,743,744,747,750,752,755,758,760],{"class":142,"line":421},[303,745,746],{"class":315},"  ].",[303,748,749],{"class":612},"join",[303,751,616],{"class":315},[303,753,754],{"class":330},"'",[303,756,757],{"class":608},"\\n",[303,759,754],{"class":330},[303,761,762],{"class":315},");\n",[303,764,765],{"class":142,"line":427},[303,766,767],{"class":315},"}\n",[303,769,771],{"class":142,"line":770},10,[303,772,773],{"class":308},"\u002F\u002F trade-off: generated hints are correct but easy to over-generate — a plugin\n",[303,775,777],{"class":142,"line":776},11,[303,778,779],{"class":308},"\u002F\u002F that hints every emitted font will preload five faces. Filter to the ones\n",[303,781,783],{"class":142,"line":782},12,[303,784,785],{"class":308},"\u002F\u002F the above-the-fold design actually uses.\n",[15,787,788],{},"Expected outcome: hints can never point at a file the deploy does not contain.",[15,790,791,794,795,797],{},[49,792,793],{},"4. Downgrade or delete hints that do not qualify."," If the resource is used on interaction, switch to ",[60,796,82],{},". If it is used on a viewport the visitor does not have, move the hint behind the same media query. If nothing uses it, delete it — a removed hint is a guaranteed improvement.",[38,799,801],{"id":800},"verification","Verification",[15,803,804],{},"Reload with an empty cache and confirm the Network panel shows exactly one request per preloaded URL, at the priority you expect, with the console clean. Then check the thing the warning was protecting you from: compare the LCP timestamp before and after. Removing a duplicated high-priority download often improves LCP by more than the preload ever did.",[15,806,807],{},"Automate the check so it cannot regress:",[294,809,811],{"className":594,"code":810,"language":596,"meta":299,"style":299},"\u002F\u002F Playwright: fail the build if any preload warning appears during a load.\nconst warnings = [];\npage.on('console', (m) => {\n  if (\u002Fpreloaded using link preload but not used\u002Fi.test(m.text())) {\n    warnings.push(m.text());\n  }\n});\nawait page.goto(url, { waitUntil: 'networkidle' });\nawait page.waitForTimeout(4000);          \u002F\u002F the warning fires a few seconds in\nif (warnings.length) throw new Error(warnings.join('\\n'));\n\u002F\u002F trade-off: the fixed wait makes the check slow and slightly flaky. Scope it\n\u002F\u002F to a handful of representative routes in a nightly job rather than running\n\u002F\u002F it on every pull request.\n",[60,812,813,818,831,857,884,899,904,909,929,949,986,991,996],{"__ignoreMap":299},[303,814,815],{"class":142,"line":305},[303,816,817],{"class":308},"\u002F\u002F Playwright: fail the build if any preload warning appears during a load.\n",[303,819,820,823,826,828],{"class":142,"line":312},[303,821,822],{"class":608},"const",[303,824,825],{"class":323}," warnings",[303,827,634],{"class":608},[303,829,830],{"class":315}," [];\n",[303,832,833,836,839,841,844,847,850,852,854],{"class":142,"line":361},[303,834,835],{"class":315},"page.",[303,837,838],{"class":612},"on",[303,840,616],{"class":315},[303,842,843],{"class":330},"'console'",[303,845,846],{"class":315},", (",[303,848,849],{"class":619},"m",[303,851,655],{"class":315},[303,853,658],{"class":608},[303,855,856],{"class":315}," {\n",[303,858,859,862,865,868,871,873,876,879,881],{"class":142,"line":368},[303,860,861],{"class":608},"  if",[303,863,864],{"class":315}," (",[303,866,867],{"class":330},"\u002Fpreloaded using link preload but not used\u002F",[303,869,870],{"class":608},"i",[303,872,721],{"class":315},[303,874,875],{"class":612},"test",[303,877,878],{"class":315},"(m.",[303,880,120],{"class":612},[303,882,883],{"class":315},"())) {\n",[303,885,886,889,892,894,896],{"class":142,"line":374},[303,887,888],{"class":315},"    warnings.",[303,890,891],{"class":612},"push",[303,893,878],{"class":315},[303,895,120],{"class":612},[303,897,898],{"class":315},"());\n",[303,900,901],{"class":142,"line":400},[303,902,903],{"class":315},"  }\n",[303,905,906],{"class":142,"line":415},[303,907,908],{"class":315},"});\n",[303,910,911,914,917,920,923,926],{"class":142,"line":421},[303,912,913],{"class":608},"await",[303,915,916],{"class":315}," page.",[303,918,919],{"class":612},"goto",[303,921,922],{"class":315},"(url, { waitUntil: ",[303,924,925],{"class":330},"'networkidle'",[303,927,928],{"class":315}," });\n",[303,930,931,933,935,938,940,943,946],{"class":142,"line":427},[303,932,913],{"class":608},[303,934,916],{"class":315},[303,936,937],{"class":612},"waitForTimeout",[303,939,616],{"class":315},[303,941,942],{"class":323},"4000",[303,944,945],{"class":315},");          ",[303,947,948],{"class":308},"\u002F\u002F the warning fires a few seconds in\n",[303,950,951,954,957,960,962,965,968,971,974,976,978,980,982,984],{"class":142,"line":770},[303,952,953],{"class":608},"if",[303,955,956],{"class":315}," (warnings.",[303,958,959],{"class":323},"length",[303,961,655],{"class":315},[303,963,964],{"class":608},"throw",[303,966,967],{"class":608}," new",[303,969,970],{"class":612}," Error",[303,972,973],{"class":315},"(warnings.",[303,975,749],{"class":612},[303,977,616],{"class":315},[303,979,754],{"class":330},[303,981,757],{"class":608},[303,983,754],{"class":330},[303,985,702],{"class":315},[303,987,988],{"class":142,"line":776},[303,989,990],{"class":308},"\u002F\u002F trade-off: the fixed wait makes the check slow and slightly flaky. Scope it\n",[303,992,993],{"class":142,"line":782},[303,994,995],{"class":308},"\u002F\u002F to a handful of representative routes in a nightly job rather than running\n",[303,997,999],{"class":142,"line":998},13,[303,1000,1001],{"class":308},"\u002F\u002F it on every pull request.\n",[15,1003,1004,1005,1007],{},"Keep this in the same job that runs your other budget assertions, described in ",[19,1006,22],{"href":21},". A hint that silently stops matching after a refactor is the single most common way this regresses.",[38,1009,1011],{"id":1010},"faq","FAQ",[1013,1014,1017,1021],"details",{"className":1015},[1016],"faq-item",[1018,1019,1020],"summary",{},"Is the warning ever safe to ignore?",[15,1022,1023,1024,1026],{},"Only in one case: a resource deliberately preloaded for an interaction that usually happens after the warning's timeout. Even then, ",[60,1025,82],{}," expresses that intent correctly and does not compete with the critical path, so the better fix is to change the hint. Every other instance of the warning means you either paid for a file twice or paid for one you never used.",[1013,1028,1030,1033],{"className":1029},[1016],[1018,1031,1032],{},"Why does removing the preload sometimes make the page faster?",[15,1034,1035],{},"Because the preload was competing with resources that mattered more. A duplicated high-priority font download consumes bandwidth that would otherwise have gone to the LCP image or the critical stylesheet. Deleting a wrong hint is one of the few performance changes that is guaranteed not to make things worse.",[1013,1037,1039,1042],{"className":1038},[1016],[1018,1040,1041],{},"Does the warning appear for Link header hints too?",[15,1043,1044],{},"Yes — the source of the hint does not matter, only whether the fetched resource is used. Header-delivered hints are actually more prone to this, because they are frequently configured per location block and therefore apply to routes that do not need the asset. Scope header hints per route, and generate them from the build.",[1013,1046,1048,1051],{"className":1047},[1016],[1018,1049,1050],{},"Why does the warning sometimes appear only on mobile?",[15,1052,1053,1054,1056],{},"Because a ",[60,1055,268],{}," attribute or a responsive layout excluded the resource at that viewport. A stylesheet preloaded for a wide-screen layout is downloaded on a phone and then never matched, which is exactly the condition the warning describes. Reproduce it by emulating the narrow viewport before loading, then either scope the hint with the same media query as the resource or drop it for that breakpoint.",[1013,1058,1060,1063],{"className":1059},[1016],[1018,1061,1062],{},"Can a service worker cause a false positive?",[15,1064,1065],{},"It can. If a worker intercepts the real request and serves it from a cache, the browser may not associate that response with the preloaded one, so the preload looks unused even though the resource was needed. Confirm by testing with the worker unregistered: if the warning disappears, the hint is fine and the interaction is the artefact. In that case, either let the preloaded response satisfy the worker's fetch or drop the hint, since the cache already made it redundant.",[1013,1067,1069,1072],{"className":1068},[1016],[1018,1070,1071],{},"Does the same warning exist for modulepreload?",[15,1073,1074,1075,1078],{},"Yes, and it is worth taking more seriously, because ",[60,1076,1077],{},"modulepreload"," also parses the module and its import graph. An unused one wastes main-thread time as well as bandwidth. The usual cause is preloading an entry that the route no longer imports after a refactor — another argument for generating hints from the build manifest rather than maintaining them by hand.",[38,1080,1082],{"id":1081},"related","Related",[43,1084,1085,1090,1097],{},[46,1086,1087,1089],{},[19,1088,22],{"href":21}," — when a preload is justified in the first place.",[46,1091,1092,1096],{},[19,1093,1095],{"href":1094},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Fpreload-vs-preconnect-when-to-use-each\u002F","Preload vs preconnect: when to use each"," — pick the hint that matches what you actually know.",[46,1098,1099,1103],{},[19,1100,1102],{"href":1101},"\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002F","Font Loading & Text Rendering Performance"," — the resource class where this mistake is most frequent and most costly.",[1105,1106,1108],"script",{"type":1107},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Fix an unused-preload console warning\",\n  \"description\": \"Determine whether a preload warning indicates a duplicated request or a genuinely unused resource, then correct the crossorigin, as, type, media or URL mismatch behind it.\",\n  \"step\": [\n    { \"@type\": \"HowToStep\", \"position\": 1, \"name\": \"Match font request shape\", \"text\": \"Add crossorigin to font preloads so the preload and the CSS-initiated request are the same request.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 2, \"name\": \"Set the correct as value\", \"text\": \"Use the as value that describes the resource so it lands at the right priority with the right Accept header.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 3, \"name\": \"Generate hints from the manifest\", \"text\": \"Emit hints from the build output so hashed filenames cannot go stale.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 4, \"name\": \"Downgrade or delete\", \"text\": \"Switch interaction-time resources to prefetch, scope media-specific hints, and remove hints nothing uses.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002F#step-by-step-resolution\" }\n  ]\n}\n",[1105,1110,1111],{"type":1107},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Fix \\\"The resource was preloaded but not used\\\" Warnings\",\n  \"description\": \"Diagnose the attribute mismatch that makes a preloaded file download twice, and remove hints that spend critical-path bandwidth on nothing.\",\n  \"datePublished\": \"2026-08-01\",\n  \"dateModified\": \"2026-08-01\",\n  \"author\": { \"@type\": \"Organization\", \"name\": \"frontend-performance.com\" },\n  \"publisher\": { \"@type\": \"Organization\", \"name\": \"frontend-performance.com\" },\n  \"mainEntityOfPage\": { \"@type\": \"WebPage\", \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002F\" }\n}\n",[1105,1113,1114],{"type":1107},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    { \"@type\": \"ListItem\", \"position\": 1, \"name\": \"Home\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 2, \"name\": \"Advanced Caching Strategies & CDN Architecture\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 3, \"name\": \"Resource Hints & Early Hints\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 4, \"name\": \"Fixing Unused-Preload Warnings in the Console\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002F\" }\n  ]\n}\n",[1116,1117,1118],"style",{},"html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}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 .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}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 .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}",{"title":299,"searchDepth":312,"depth":312,"links":1120},[1121,1122,1123,1124,1125,1126],{"id":40,"depth":312,"text":41},{"id":224,"depth":312,"text":225},{"id":286,"depth":312,"text":287},{"id":800,"depth":312,"text":801},{"id":1010,"depth":312,"text":1011},{"id":1081,"depth":312,"text":1082},"The warning means you spent critical-path bandwidth on nothing. Find the mismatch between the preload request and the real one, and fix the duplicate download.","md",{"slug":1130,"type":1131,"breadcrumb":1132,"datePublished":1140,"dateModified":1140},"fixing-unused-preload-warnings-in-the-console","article",[1133,1136,1137,1138],{"name":1134,"url":1135},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1139},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002F","2026-08-01","\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console",{"title":1143,"description":1144},"Fixing 'Preloaded Resource Not Used' Console Warnings","Chrome warns when a preloaded file goes unused. Diagnose the attribute mismatch — crossorigin, as, type, media or a changed URL — that made the browser fetch it twice.","advanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Ffixing-unused-preload-warnings-in-the-console\u002Findex","5-MP-NSJRI2641AeiqnpqlDy9-gynywe7yXgF-YLHDY",[1148,1151],{"title":22,"path":1149,"stem":1150,"children":-1},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints","advanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Findex",{"title":1152,"path":1153,"stem":1154,"children":-1},"Preload vs Preconnect: When to Use Each","\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Fpreload-vs-preconnect-when-to-use-each","advanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002Fpreload-vs-preconnect-when-to-use-each\u002Findex",1785622406681]