Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .changeset/floppy-times-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
'@astrojs/sitemap': minor
---

Adds the ability to split sitemap generation into chunks based on customizable logic. This allows for better management of large sitemaps and improved performance. The new `chunks` option in the sitemap configuration allows users to define functions that categorize sitemap items into different chunks. Each chunk is then written to a separate sitemap file.

```
integrations: [
sitemap({
serialize(item) { th
return item
},
chunks: { // this property will be treated last on the configuration
'blog': (item) => { // will produce a sitemap file with `blog` name (sitemap-blog-0.xml)
if (/blog/.test(item.url)) { // filter path that will be included in this specific sitemap file
item.changefreq = 'weekly';
item.lastmod = new Date();
item.priority = 0.9; // define specific properties for this filtered path
return item;
}
},
'glossary': (item) => {
if (/glossary/.test(item.url)) {
item.changefreq = 'weekly';
item.lastmod = new Date();
item.priority = 0.7;
return item;
}
}

// the rest of the path will be stored in `sitemap-pages.0.xml`
},
}),
],

```
8 changes: 8 additions & 0 deletions .changeset/great-jokes-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@astrojs/language-server': patch
'@astrojs/netlify': patch
'@astrojs/rss': patch
'astro': patch
---

Fixes the links to Astro Docs so that they match the current docs structure.
5 changes: 5 additions & 0 deletions .changeset/tender-mice-spend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes CSS url() references to public assets returning 404 in dev mode when base path is configured
4 changes: 2 additions & 2 deletions examples/blog/src/content/blog/using-mdx.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This theme comes with the [@astrojs/mdx](https://docs.astro.build/en/guides/inte

## Why MDX?

MDX is a special flavor of Markdown that supports embedded JavaScript & JSX syntax. This unlocks the ability to [mix JavaScript and UI Components into your Markdown content](https://docs.astro.build/en/guides/markdown-content/#mdx-features) for things like interactive charts or alerts.
MDX is a special flavor of Markdown that supports embedded JavaScript & JSX syntax. This unlocks the ability to [mix JavaScript and UI Components into your Markdown content](https://docs.astro.build/en/guides/integrations-guide/mdx/#mdx-in-astro) for things like interactive charts or alerts.

If you have existing content authored in MDX, this integration will hopefully make migrating to Astro a breeze.

Expand All @@ -27,5 +27,5 @@ import HeaderLink from '../../components/HeaderLink.astro';
## More Links

- [MDX Syntax Documentation](https://mdxjs.com/docs/what-is-mdx)
- [Astro Usage Documentation](https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages)
- [Astro Usage Documentation](https://docs.astro.build/en/basics/astro-pages/#markdownmdx-pages)
- **Note:** [Client Directives](https://docs.astro.build/en/reference/directives-reference/#client-directives) are still required to create interactive components. Otherwise, all components in your MDX will render as static HTML (no JavaScript) by default.
2 changes: 1 addition & 1 deletion examples/portfolio/src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
// Learn about using Astro layouts:
// https://docs.astro.build/en/core-concepts/layouts/
// https://docs.astro.build/en/basics/layouts/

import Footer from '../components/Footer.astro';
// Component Imports
Expand Down
2 changes: 1 addition & 1 deletion examples/portfolio/src/pages/work/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface Props {

// This is a dynamic route that generates a page for every Markdown file in src/content/
// Read more about dynamic routes and this `getStaticPaths` function in the Astro docs:
// https://docs.astro.build/en/core-concepts/routing/#dynamic-routes
// https://docs.astro.build/en/guides/routing/#dynamic-routes
export async function getStaticPaths() {
const work = await getCollection('work');
return work.map((entry) => ({
Expand Down
2 changes: 1 addition & 1 deletion examples/with-mdx/src/pages/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Published on: {new Intl.DateTimeFormat('en', {dateStyle: 'long'}).format(publish

## Syntax highlighting

We also support syntax highlighting in MDX out-of-the-box! This example uses the default [Shiki](https://shiki.style) theme. See the [MDX integration docs](https://docs.astro.build/en/guides/integrations-guide/mdx/#syntax-highlighting) for configuration options.
We also support syntax highlighting in MDX out-of-the-box! This example uses the default [Shiki](https://shiki.style) theme. See the [MDX integration docs](https://docs.astro.build/en/guides/integrations-guide/mdx/#configuration) for configuration options.

```astro
---
Expand Down
2 changes: 1 addition & 1 deletion examples/with-nanostores/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ npm create astro@latest -- --template with-nanostores
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/with-nanostores)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/with-nanostores/devcontainer.json)

This example showcases using [`nanostores`](https://github.com/nanostores/nanostores) to provide shared state between components of any framework. [**Read our documentation on sharing state**](https://docs.astro.build/en/core-concepts/sharing-state/) for a complete breakdown of this project, along with guides to use React, Vue, Svelte, or Solid!
This example showcases using [`nanostores`](https://github.com/nanostores/nanostores) to provide shared state between components of any framework. [**Read our documentation on sharing state**](https://docs.astro.build/en/recipes/sharing-state-islands/) for a complete breakdown of this project, along with guides to use React, Vue, Svelte, or Solid!
8 changes: 3 additions & 5 deletions packages/astro-rss/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The `<description>` attribute of your RSS feed's output xml.

Type: `string (required)`

The base URL to use when generating RSS item links. We recommend using the [endpoint context object](https://docs.astro.build/en/reference/api-reference/#contextsite), which includes the `site` configured in your project's `astro.config.*`:
The base URL to use when generating RSS item links. We recommend using the [endpoint context object](https://docs.astro.build/en/reference/api-reference/#site), which includes the `site` configured in your project's `astro.config.*`:

```ts
import rss from '@astrojs/rss';
Expand Down Expand Up @@ -87,7 +87,7 @@ Type: `string (optional)`

The full text content of the item suitable for presentation as HTML. If used, you should also provide a short article summary in the `description` field.

To render Markdown content from a glob result or from a content collection, see the [content rendering guide](https://docs.astro.build/en/guides/rss/#including-full-post-content).
To render Markdown content from a glob result or from a content collection, see the [content rendering guide](https://docs.astro.build/en/recipes/rss/#including-full-post-content).

#### `categories`

Expand Down Expand Up @@ -304,10 +304,8 @@ MIT

Copyright (c) 2023–present [Astro][astro]

[docs]: https://docs.astro.build/en/guides/rss/
[astro-endpoints]: https://docs.astro.build/en/core-concepts/astro-pages/#non-html-pages
[docs]: https://docs.astro.build/en/recipes/rss/
[astro]: https://astro.build/
[docs]: https://docs.astro.build/en/guides/integrations-guide/alpinejs/
[contributing]: https://github.com/withastro/astro/blob/main/CONTRIBUTING.md
[coc]: https://github.com/withastro/.github/blob/main/CODE_OF_CONDUCT.md
[community]: https://github.com/withastro/.github/blob/main/COMMUNITY_GUIDE.md
Expand Down
8 changes: 4 additions & 4 deletions packages/astro-rss/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type RSSOptions = {
description: z.infer<typeof rssOptionsValidator>['description'];
/**
* Specify the base URL to use for RSS feed links.
* We recommend using the [endpoint context object](https://docs.astro.build/en/reference/api-reference/#contextsite),
* We recommend using the [endpoint context object](https://docs.astro.build/en/reference/api-reference/#site),
* which includes the `site` configured in your project's `astro.config.*`
*/
site: z.infer<typeof rssOptionsValidator>['site'] | URL;
Expand Down Expand Up @@ -72,7 +72,7 @@ const rssOptionsValidator = z.object({
if (!Array.isArray(items)) {
console.warn(
colors.yellow(
'[RSS] Passing a glob result directly has been deprecated. Please migrate to the `pagesGlobToRssItems()` helper: https://docs.astro.build/en/guides/rss/',
'[RSS] Passing a glob result directly has been deprecated. Please migrate to the `pagesGlobToRssItems()` helper: https://docs.astro.build/en/recipes/rss/',
),
);
return pagesGlobToRssItems(items);
Expand Down Expand Up @@ -116,7 +116,7 @@ async function validateRssOptions(rssOptions: RSSOptions) {
return [
message,
`The \`items\` property requires at least the \`title\` or \`description\` key. They must be properly typed, as well as \`pubDate\` and \`link\` keys if provided.`,
`Check your collection's schema, and visit https://docs.astro.build/en/guides/rss/#generating-items for more info.`,
`Check your collection's schema, and visit https://docs.astro.build/en/recipes/rss/#generating-items for more info.`,
].join('\n');
}

Expand All @@ -133,7 +133,7 @@ export function pagesGlobToRssItems(items: GlobResult): Promise<ValidatedRSSFeed
const { url, frontmatter } = await getInfo();
if (url === undefined || url === null) {
throw new Error(
`[RSS] You can only glob entries within 'src/pages/' when passing import.meta.glob() directly. Consider mapping the result to an array of RSSFeedItems. See the RSS docs for usage examples: https://docs.astro.build/en/guides/rss/#2-list-of-rss-feed-objects`,
`[RSS] You can only glob entries within 'src/pages/' when passing import.meta.glob() directly. Consider mapping the result to an array of RSSFeedItems. See the RSS docs for usage examples: https://docs.astro.build/en/recipes/rss/`,
);
}
const parsedResult = rssSchema
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Astro = import('./dist/types/public/context.js').AstroGlobal;
/**
* Astro global available in all contexts in .astro files
*
* [Astro documentation](https://docs.astro.build/en/reference/api-reference/#astro-global)
* [Astro documentation](https://docs.astro.build/en/reference/api-reference/)
*/
declare const Astro: Readonly<Astro>;

Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,14 +452,14 @@ function getInvalidRouteSegmentError(
const invalidParam = /^Expected "([^"]+)"/.exec(e.message)?.[1];
const received = invalidParam ? staticPath.params[invalidParam] : undefined;
let hint =
'Learn about dynamic routes at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes';
'Learn about dynamic routes at https://docs.astro.build/en/guides/routing/#dynamic-routes';
if (invalidParam && typeof received === 'string') {
const matchingSegment = route.segments.find(
(segment) => segment[0]?.content === invalidParam,
)?.[0];
const mightBeMissingSpread = matchingSegment?.dynamic && !matchingSegment?.spread;
if (mightBeMissingSpread) {
hint = `If the param contains slashes, try using a rest parameter: **[...${invalidParam}]**. Learn more at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes`;
hint = `If the param contains slashes, try using a rest parameter: **[...${invalidParam}]**. Learn more at https://docs.astro.build/en/guides/routing/#dynamic-routes`;
}
}
return new AstroError({
Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/core/compile/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export async function compile({
preprocessStyle: createStylePreprocessor({
filename,
viteConfig,
astroConfig,
cssPartialCompileResults,
cssTransformErrors,
}),
Expand Down
79 changes: 78 additions & 1 deletion packages/astro/src/core/compile/style.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,93 @@
import fs from 'node:fs';
import type { TransformOptions } from '@astrojs/compiler';
import { preprocessCSS, type ResolvedConfig } from 'vite';
import type { AstroConfig } from '../../types/public/config.js';
import { AstroErrorData, CSSError, positionAt } from '../errors/index.js';
import { normalizePath } from '../viteUtils.js';
import type { CompileCssResult } from './types.js';

export type PartialCompileCssResult = Pick<CompileCssResult, 'isGlobal' | 'dependencies'>;

/**
* Rewrites absolute URLs in CSS to include the base path.
*
* Vite's `preprocessCSS` function explicitly does NOT resolve URLs in `url()` or `image-set()`
* (https://vite.dev/guide/api-javascript.html#preprocesscss). During build, Vite's CSS plugin handles URL rewriting through its
* full transform pipeline, but during dev, Astro calls `preprocessCSS` directly through the
* compiler, bypassing that pipeline.
*
* Only absolute URLs starting with `/` (e.g., `/fonts/font.woff`, `/images/bg.png`) are rewritten
*
* Uses Vite's cssUrlRE regex pattern for reliable URL matching.
* See: https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/css.ts
*
* @param css - The CSS string to process
* @param base - The base path to prepend (e.g., `/my-base`)
* @returns The CSS with rewritten URLs
*/
function rewriteCssUrls(css: string, base: string): string {
// Only rewrite if base is not the default '/'
if (!base || base === '/') {
return css;
}

// Normalize base path (remove trailing slash for consistent joining)
const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;

// Safety check: base should start with '/' (already normalized by Astro config)
if (!normalizedBase.startsWith('/')) {
return css;
}

// Vite's production-tested regex for matching url() in CSS
// Matches url(...) while handling quotes, unquoted URLs, and edge cases
// Excludes @import statements via negative lookbehind
// Matches Vite's cssUrlRE pattern exactly - capturing groups preserved for compatibility
const cssUrlRE =
// eslint-disable-next-line regexp/no-unused-capturing-group
/(?<!@import\s+)(?<=^|[^\w\-\u0080-\uffff])url\((\s*('[^']+'|"[^"]+")\s*|(?:\\.|[^'")\\])+)\)/g;

return css.replace(cssUrlRE, (match, rawUrl: string) => {
// Extract URL value, removing quotes if present
let url = rawUrl.trim();
let quote = '';

// Check if URL is quoted (single or double)
if ((url.startsWith("'") && url.endsWith("'")) || (url.startsWith('"') && url.endsWith('"'))) {
quote = url[0];
url = url.slice(1, -1);
}

url = url.trim();

// Only rewrite root-relative URLs (start with / but not //)
const isRootRelative = url.startsWith('/') && !url.startsWith('//');

// Skip external URLs and data URIs
const isExternal =
url.startsWith('data:') || url.startsWith('http:') || url.startsWith('https:');

// Skip if already has base path (makes function idempotent)
const alreadyHasBase = url.startsWith(normalizedBase + '/');

if (isRootRelative && !isExternal && !alreadyHasBase) {
return `url(${quote}${normalizedBase}${url}${quote})`;
}

return match;
});
}

export function createStylePreprocessor({
filename,
viteConfig,
astroConfig,
cssPartialCompileResults,
cssTransformErrors,
}: {
filename: string;
viteConfig: ResolvedConfig;
astroConfig: AstroConfig;
cssPartialCompileResults: Partial<CompileCssResult>[];
cssTransformErrors: Error[];
}): TransformOptions['preprocessStyle'] {
Expand All @@ -27,6 +100,10 @@ export function createStylePreprocessor({
try {
const result = await preprocessCSS(content, id, viteConfig);

// Rewrite CSS URLs to include the base path
// This is necessary because preprocessCSS doesn't handle URL rewriting
const rewrittenCode = rewriteCssUrls(result.code, astroConfig.base);

cssPartialCompileResults[index] = {
isGlobal: !!attrs['is:global'],
dependencies: result.deps ? [...result.deps].map((dep) => normalizePath(dep)) : [],
Expand All @@ -41,7 +118,7 @@ export function createStylePreprocessor({
}
}

return { code: result.code, map };
return { code: rewrittenCode, map };
} catch (err: any) {
try {
err = enhanceCSSError(err, filename, content);
Expand Down
8 changes: 4 additions & 4 deletions packages/astro/src/types/public/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { APIContext } from './context.js';
/**
* getStaticPaths() options
*
* [Astro Reference](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
* [Astro Reference](https://docs.astro.build/en/reference/routing-reference/#getstaticpaths)
*/
export interface GetStaticPathsOptions {
paginate: PaginateFunction;
Expand All @@ -24,7 +24,7 @@ export type GetStaticPathsResultKeyed = GetStaticPathsResult & {
/**
* Return an array of pages to generate for a [dynamic route](https://docs.astro.build/en/guides/routing/#dynamic-routes). (**SSG Only**)
*
* [Astro Reference](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
* [Astro Reference](https://docs.astro.build/en/reference/routing-reference/#getstaticpaths)
*/
export type GetStaticPaths = (
options: GetStaticPathsOptions,
Expand All @@ -33,7 +33,7 @@ export type GetStaticPaths = (
/**
* paginate() Options
*
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#paginate)
* [Astro reference](https://docs.astro.build/en/reference/routing-reference/#paginate)
*/
export interface PaginateOptions<PaginateProps extends Props, PaginateParams extends Params> {
/** the number of items per-page (default: `10`) */
Expand All @@ -47,7 +47,7 @@ export interface PaginateOptions<PaginateProps extends Props, PaginateParams ext
/**
* Represents a single page of data in a paginated collection
*
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#the-pagination-page-prop)
* [Astro reference](https://docs.astro.build/en/reference/routing-reference/#the-pagination-page-prop)
*/
export interface Page<T = any> {
/** result */
Expand Down
6 changes: 3 additions & 3 deletions packages/astro/src/types/public/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ export interface AstroSharedContext<
/**
* An object containing the values of dynamic route segments matched for a request.
*
* In static builds, this will be the `params` returned by [`getStaticPaths()`](https://docs.astro.build/en/reference/api-reference/#getstaticpaths). With on-demand rendering, `params` can be any value matching the path segments in the dynamic route pattern.
* In static builds, this will be the `params` returned by [`getStaticPaths()`](https://docs.astro.build/en/reference/routing-reference/#getstaticpaths). With on-demand rendering, `params` can be any value matching the path segments in the dynamic route pattern.
*
* ## Example
*
Expand All @@ -368,7 +368,7 @@ export interface AstroSharedContext<
params: Params;

/**
* An object containing any values that have been passed as component attributes. In static builds, this can also be the `props` returned by [`getStaticPaths()`](https://docs.astro.build/en/reference/api-reference/#getstaticpaths).
* An object containing any values that have been passed as component attributes. In static builds, this can also be the `props` returned by [`getStaticPaths()`](https://docs.astro.build/en/reference/routing-reference/#getstaticpaths).
*
* ## Example
*
Expand Down Expand Up @@ -613,7 +613,7 @@ export interface AstroSharedContext<
* - The value when rendering `src/pages/blog/[slug].astro` will be `/blog/[slug]`.
* - The value when rendering `src/pages/[...path].astro` will be `/[...path]`.
*
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#routepattern)
* [Astro reference](https://docs.astro.build/en/reference/routing-reference/#routepattern)
*/
routePattern: string;
}
Expand Down
Loading
Loading