-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Description
Astro Info
Astro v5.16.11
Vite v6.4.1
Node v24.10.0
System macOS (arm64)
Package Manager npm
Output static
Adapter @astrojs/node (v9.5.1)
Integrations event-validation-integration
download-vendor-scripts
nonce-generator
sri-integrity
@astrojs/react (v4.4.2)
@astrojs/sitemap (v3.6.1)
@astrojs/mdx (v4.3.13)
If this issue only occurs in one browser, which browser is a problem?
No response
Describe the Bug
Description
When using build.assetsPrefix with a remote URL (e.g., https://cdn.example.com) for CSS assets, the generated <link> elements have an incorrect href attribute with a leading / prepended to the full URL.
Expected: <link href="https://cdn.example.com/assets/style.css" rel="stylesheet">
Actual: <link href="/https://cdn.example.com/assets/style.css" rel="stylesheet">
This only affects CSS assets. JavaScript assets with the same assetsPrefix configuration work correctly.
Reproduction
Minimal reproduction
- Create an Astro project with content collections (MDX files)
- Configure
astro.config.tswith a remoteassetsPrefix:
export default defineConfig({
build: {
assetsPrefix: {
js: 'https://cdn.example.com',
css: 'https://cdn.example.com',
},
},
});- Build the project:
astro build - Inspect the generated HTML files
Expected behavior
CSS links should use the full CDN URL without modification:
<link href="https://cdn.example.com/_astro/style.css" rel="stylesheet">Actual behavior
CSS links have a / prepended to the URL:
<link href="/https://cdn.example.com/_astro/style.css" rel="stylesheet">Root Cause Analysis
The bug is in packages/astro/src/content/runtime.ts (compiled to dist/content/runtime.js).
In the createComponent factory function that handles content collection rendering, external stylesheets are processed at approximately line 590:
if (Array.isArray(collectedLinks)) {
links = collectedLinks.map((link) => {
return renderUniqueStylesheet(result, {
type: "external",
src: prependForwardSlash(link) // BUG: Always prepends "/" even for remote URLs
});
}).join("");
}The prependForwardSlash(link) call unconditionally adds a / prefix, even when link is already a full URL with a protocol (http/https).
Why scripts work correctly
The build-time code in vite-plugin-content-assets.js correctly handles the assetsPrefix:
const prependBase = (src) => {
const { assetsPrefix } = options.settings.config.build;
if (assetsPrefix) {
const fileExtension = extname(src);
const pf = getAssetsPrefix(fileExtension, assetsPrefix);
return joinPaths(pf, src); // Correctly joins without extra "/"
} else {
return prependForwardSlash(joinPaths(options.settings.config.base, src));
}
};This prependBase function is applied at build time when replacing LINKS_PLACEHOLDER. However, the runtime code then applies prependForwardSlash again, breaking remote URLs.
Proposed Fix
Check if the link is a remote URL before prepending the forward slash. The isRemotePath utility from @astrojs/internal-helpers/path can be used:
// Before (buggy):
src: prependForwardSlash(link)
// After (fixed):
src: isRemotePath(link) ? link : prependForwardSlash(link)The isRemotePath function already exists in the codebase and correctly identifies URLs with protocols.
Impact
This bug prevents using CDN URLs for CSS assets, which is a common use case for:
- Serving static assets from a CDN for performance
- Implementing CDN fallback patterns
- Multi-region deployments with regional CDNs
Workaround
Currently, the only workaround is to patch the Astro package directly or use a forked version.
What's the expected result?
Expected behavior
CSS links should use the full CDN URL without modification:
<link href="https://cdn.example.com/_astro/style.css" rel="stylesheet">Link to Minimal Reproducible Example
Participation
- I am willing to submit a pull request for this issue.