-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Description
Reproduction
Go to https://stackblitz.com/edit/github-gccjk6nw?file=package.json which should run npm run build && npm run start and view network calls for css-component-jBA8ckt5.css and you will see a mix of fetching of the same asset from react-router tags and vite tags, which are using different variants of the crossorigin attribute.
However, you will not see the complete failure as reported below in Stackblitz because the assets are always returned via serviceworker and not via CDN with CORS + browser file cache.
System Info
System:
OS: Linux 5.0 undefined
CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 0 Bytes / 0 Bytes
Shell: 1.0 - /bin/jsh
Binaries:
Node: 20.19.1 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 10.8.2 - /usr/local/bin/npm
pnpm: 8.15.6 - /usr/local/bin/pnpm
npmPackages:
@react-router/dev: 7.10.1 => 7.10.1
@react-router/node: 7.10.1 => 7.10.1
@react-router/serve: 7.10.1 => 7.10.1
react-router: 7.10.1 => 7.10.1
vite: ^7.1.7 => 7.3.0Used Package Manager
npm
Expected Behavior
I expect the asset to be fetched only once, or with the same crossorigin value so that when the browser re-uses cached assets, one of the calls does not unexpectedly fail.
Actual Behavior
When using a CDN like AWS cloudfront with access-control-allow-origin headers, these CDNs will not return any CORS headers when an asset is fetched via a <link /> tag with no crossorigin attributes. However, Chrome will then cache this response, and try to re-use it when vite is later trying to preload the asset, which Chrome will then later fail because the cached version of the asset is missing the access-control-allow-origin header.
After the implementation of the fix in #14463, Chrome is re-using the cache for the two requests, and vite is also trying to fetch the asset since it doesn't find a matching <link /> tag in the DOM as designed due to the # suffix. As a result, Chrome re-uses the cache for both requests, but the former one may not have any CORS response headers due to no crossorigin attribute on the react-router injected tags.
This previously worked in versions of react-router prior to #14463 because vite would not re-attempt to fetch the css asset since it was already found in the DOM.
This article does a good job explaining Chrome's cache usage in combination with CORS headers in more detail: https://anthonymineo.com/solving-a-cors-issue-when-serving-from-chromes-browser-cache/
And the Chromium issue that describes this caching behavior in more detail: https://issues.chromium.org/issues/40381978