Skip to content

perf(astro): group chunks on emit#15123

Merged
ematipico merged 4 commits intowithastro:mainfrom
43081j:super-chunks
Jan 7, 2026
Merged

perf(astro): group chunks on emit#15123
ematipico merged 4 commits intowithastro:mainfrom
43081j:super-chunks

Conversation

@43081j
Copy link
Contributor

@43081j 43081j commented Jan 6, 2026

When we render to an async iterable, we basically start rendering the
given template into chunks and return an iterator which reads from that
same queue of chunks in parallel.

The rendering causes the following process:

  • Convert the rendered chunk into a byte array if it isn't one already
  • Add the byte array to the queue
  • Resolve if nothing left in the queue

The iterator then reads from this same queue and does the following:

  • Take the entire contents of the queue right now
  • Concat them into one array
  • Yield the concatenated array

The bottleneck in this process is Convert the rendered chunk into a byte array.

Basically, if a chunk isn't already a Uint8Array, we pass the string
representation through a TextEncoder to turn it into one.

This means for 10,000 string chunks, we call encode 10,000 times.

It turns out TextEncode#encode is costly.

This PR reworks this process to the following:

Rendering:

  • Convert the rendered chunk into a string or byte array if it isn't one
    already
  • Add the string or byte array to the queue
  • Resolve if nothing left in the queue

Iterator:

  • Take the entire contents of the queue right now
  • Merge consecutive strings into one string, and convert that into a
    byte array
  • Concat them into one array (now the set of arrays consists only of
    byte arrays again
    )
  • Yield the concatenated array

This means we call TextEncode#encode on larger strings, and fewer
times - which it turns out is a lot more performant.

Benchmarks

Given this astro file:

<h1>Foo</h1>
<div style="display:none">
  {
    new Array(50_000).fill(0).map((_, i) => (
      <div>
        Go to <a href={`/${i}`}>{i}</a>
      </div>
    ))
  }
</div>

I can use wrk to benchmark server response times directly:

# Before
wrk http://localhost:4321/astro

Running 10s test @ http://localhost:4321/astro
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.04s   303.51ms   1.91s    71.60%
    Req/Sec     5.56      4.30    20.00     64.94%
  85 requests in 10.10s, 180.61MB read
  Socket errors: connect 0, read 0, write 0, timeout 4
Requests/sec:      8.42
Transfer/sec:     17.88MB

# Ater
wrk http://localhost:4321/astro

Running 10s test @ http://localhost:4321/astro
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   553.97ms  154.48ms   1.57s    82.78%
    Req/Sec     9.68      5.28    29.00     58.57%
  178 requests in 10.09s, 378.34MB read
Requests/sec:     17.64
Transfer/sec:     37.49MB

This seems to show 17 requests/sec vs 8 requests/sec.

Meanwhile, if I do a CPU profile and check out the top functions:

Before:

Flat Flat % Sum % Cumulative Cumulative % Function
49.41ms 17.81% 17.81% 49.41ms 17.81% Garbage
41.81ms 15.07% 32.88% 53.21ms 19.18% encode
11.40ms 4.11% 36.99% 68.42ms 24.66% write
11.40ms 4.11% 41.10% 11.40ms 4.11% encodeUtf8String
11.40ms 4.11% 45.21% 11.40ms 4.11% (anonymous:L#722)
10.14ms 3.65% 48.86% 87.42ms 31.51% iterate

After:

Flat Flat % Sum % Cumulative Cumulative % Function
32.86ms 15.29% 15.29% 32.86ms 15.29% Garbage
11.38ms 5.29% 20.59% 11.38ms 5.29% (anonymous:L#722)
8.85ms 4.12% 24.71% 16.43ms 7.65% write
8.85ms 4.12% 28.82% 22.75ms 10.59% next
7.58ms 3.53% 32.35% 7.58ms 3.53% stringifyChunk
7.58ms 3.53% 35.88% 21.49ms 10.00% flush

Testing

Existing tests should cover this.

Docs

No changes to functionality.

When we render to an async iterable, we basically start rendering the
given template into chunks and return an iterator which reads from that
same queue of chunks in parallel.

The rendering causes the following process:

- Convert the rendered chunk into a byte array if it isn't one already
- Add the byte array to the queue
- Resolve if nothing left in the queue

The iterator then reads from this same queue and does the following:

- Take the entire contents of the queue right now
- Concat them into one array
- Yield the concatenated array

The bottleneck in this process is `Convert the rendered chunk into a
byte array`.

Basically, if a chunk isn't already a `Uint8Array`, we pass the string
representation through a `TextEncoder` to turn it into one.

This means for 10,000 _string_ chunks, we call `encode` 10,000 times.

**It turns out `TextEncode#encode` is costly.**

This PR reworks this process to the following:

Rendering:

- Convert the rendered chunk into a **string or** byte array if it isn't one
	already
- Add the **string or** byte array to the queue
- Resolve if nothing left in the queue

Iterator:

- Take the entire contents of the queue right now
- **Merge consecutive strings into one string, and convert that into a
	byte array**
- Concat them into one array (**now the set of arrays consists only of
	byte arrays again**)
- Yield the concatenated array

This means we call `TextEncode#encode` on larger strings, and fewer
times - which it turns out is a lot more performant.
@changeset-bot
Copy link

changeset-bot bot commented Jan 6, 2026

🦋 Changeset detected

Latest commit: 748f5cc

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the pkg: astro Related to the core `astro` package (scope) label Jan 6, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 6, 2026

Merging this PR will improve performance by ×11

Summary

⚡ 4 improved benchmarks
✅ 2 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
Rendering: streaming [true], .md file 12.8 ms 1.2 ms ×11
Rendering: streaming [true], .astro file 940.7 ms 619.1 ms +51.96%
Rendering: streaming [false], .md file 12.9 ms 1.2 ms ×11
Rendering: streaming [false], .astro file 923.2 ms 618.6 ms +49.23%

Comparing 43081j:super-chunks (748f5cc) with main (b1e8e32)

Open in CodSpeed

@matthewp
Copy link
Contributor

matthewp commented Jan 6, 2026

Could you add a changeset? I believe this would be a patch. pnpm run changeset.

Copy link
Contributor

@matthewp matthewp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see 11x improvement and I press approve

@matthewp
Copy link
Contributor

matthewp commented Jan 6, 2026

These E2E tests are flaky, will rerun.

@ematipico ematipico merged commit 3f58fa2 into withastro:main Jan 7, 2026
46 of 47 checks passed
@astrobot-houston astrobot-houston mentioned this pull request Jan 7, 2026
@43081j 43081j deleted the super-chunks branch January 7, 2026 11:01
const bufferEntry = buffer[i];

if (typeof bufferEntry === 'string') {
const nextIsString = i + 1 < len && typeof buffer[i + 1] === 'string';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than checking if next is string, why don't we just store a separate array for string values and just check that in general? This would simplify this implementation and we don't have to store string | buffer in this array.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

garbage collection? we would be storing an array of strings and throwing it away shortly after, no?

the buffer array is always the same and gets cleared each time. i suppose we could do that with two arrays but just figured it'd be cheaper to hold one

// the encoding earlier, we know the only remaining strings are empty
// and have been skipped above.
mergedArray.set(item as Uint8Array, offset);
offset += item.length;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also construct this offset in the previous for loop, can't we ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, what difference do you think it'd make? we also increment it fewer times than there are buffer items since we clear some earlier

if (ArrayBuffer.isView(chunk)) {
return chunk as Uint8Array;
} else {
return stringifyChunk(result, chunk).toString();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stringifyChunk already returns string, toString() seems redundant

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this method has a huge switch/case statement comparing strings, if they're enums, comparing numbers to numbers would be a lot faster (referring to instruction.type)

Copy link
Contributor Author

@43081j 43081j Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just retaining what it was before here. the other helper does this. i did spot this too but assumed there was a reason in the existing code, something to do with html strings

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, instruction.type could definitely just be number constants.

dadezzz pushed a commit to dadezzz/ice-notes that referenced this pull request Jan 11, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [astro](https://astro.build) ([source](https://github.com/withastro/astro/tree/HEAD/packages/astro)) | [`5.16.6` → `5.16.7`](https://renovatebot.com/diffs/npm/astro/5.16.6/5.16.7) | ![age](https://developer.mend.io/api/mc/badges/age/npm/astro/5.16.7?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/astro/5.16.6/5.16.7?slim=true) |

---

### Release Notes

<details>
<summary>withastro/astro (astro)</summary>

### [`v5.16.7`](https://github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#5167)

[Compare Source](https://github.com/withastro/astro/compare/[email protected]@5.16.7)

##### Patch Changes

- [#&#8203;15122](withastro/astro#15122) [`b137946`](withastro/astro@b137946) Thanks [@&#8203;florian-lefebvre](https://github.com/florian-lefebvre)! - Improves JSDoc annotations for `AstroGlobal`, `AstroSharedContext` and `APIContext` types

- [#&#8203;15123](withastro/astro#15123) [`3f58fa2`](withastro/astro@3f58fa2) Thanks [@&#8203;43081j](https://github.com/43081j)! - Improves rendering performance by grouping render chunks when emitting from async iterables to avoid encoding costs

- [#&#8203;14954](withastro/astro#14954) [`7bec4bd`](withastro/astro@7bec4bd) Thanks [@&#8203;volpeon](https://github.com/volpeon)! - Fixes remote images `Etag` header handling by disabling internal cache

- [#&#8203;15052](withastro/astro#15052) [`b2bcd5a`](withastro/astro@b2bcd5a) Thanks [@&#8203;Princesseuh](https://github.com/Princesseuh)! - Fixes images not working in development when using setups with port forwarding

- [#&#8203;15028](withastro/astro#15028) [`87b19b8`](withastro/astro@87b19b8) Thanks [@&#8203;Princesseuh](https://github.com/Princesseuh)! - Fixes certain aliases not working when using images in JSON files with the content layer

- [#&#8203;15118](withastro/astro#15118) [`cfa382b`](withastro/astro@cfa382b) Thanks [@&#8203;florian-lefebvre](https://github.com/florian-lefebvre)! - **BREAKING CHANGE to the experimental Fonts API only**

  Removes the `defineAstroFontProvider()` type helper.

  If you are building a custom font provider, remove any occurrence of `defineAstroFontProvider()` and use the `FontProvider` type instead:

  ```diff
  -import { defineAstroFontProvider } from 'astro/config';

  -export function myProvider() {
  -    return defineAstroFontProvider({
  -        entrypoint: new URL('./implementation.js', import.meta.url)
  -    });
  -};

  +import type { FontProvider } from 'astro';

  +export function myProvider(): FontProvider {
  +    return {
  +        entrypoint: new URL('./implementation.js', import.meta.url)
  +    },
  +}
  ```

- [#&#8203;15055](withastro/astro#15055) [`4e28db8`](withastro/astro@4e28db8) Thanks [@&#8203;delucis](https://github.com/delucis)! - Reduces Astro’s install size by around 8 MB

- [#&#8203;15088](withastro/astro#15088) [`a19140f`](withastro/astro@a19140f) Thanks [@&#8203;martrapp](https://github.com/martrapp)! - Enables the ClientRouter to preserve the original hash part of the target URL during server side redirects.

- [#&#8203;15117](withastro/astro#15117) [`b1e8e32`](withastro/astro@b1e8e32) Thanks [@&#8203;florian-lefebvre](https://github.com/florian-lefebvre)! - **BREAKING CHANGE to the experimental Fonts API only**

  Changes the font format downloaded by default when using the experimental Fonts API. Additionally, adds a new `formats` configuration option to specify which font formats to download.

  Previously, Astro was opinionated about which font sources would be kept for usage, mainly keeping `woff2` and `woff` files.

  You can now specify what font formats should be downloaded (if available). Only `woff2` files are downloaded by default.

##### What should I do?

If you were previously relying on Astro downloading the `woff` format, you will now need to specify this explicitly with the new `formats` configuration option. Additionally, you may also specify any additional file formats to download if available:

```diff
// astro.config.mjs
import { defineConfig, fontProviders } from 'astro/config'

export default defineConfig({
    experimental: {
        fonts: [{
            name: 'Roboto',
            cssVariable: '--font-roboto',
            provider: fontProviders.google(),
+            formats: ['woff2', 'woff', 'otf']
        }]
    }
})
```

- [#&#8203;15034](withastro/astro#15034) [`8115752`](withastro/astro@8115752) Thanks [@&#8203;florian-lefebvre](https://github.com/florian-lefebvre)! - Fixes a vite warning log during builds when using npm

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi43MS4yIiwidXBkYXRlZEluVmVyIjoiNDIuNzEuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: Renovate Bot <[email protected]>
Co-committed-by: Renovate Bot <[email protected]>
matthewp added a commit that referenced this pull request Jan 12, 2026
* fix(ci): Reinstall deps after having published VS Code (#14996)

* fix(svelte): allow client directives (#15004)

* fix(assets): Fixes missing format option for svgs in the passthrough service (#14987)

* fix(assets): Fixes missing format option for svgs in the passthrough service

* fix: wtf is going on

* chore: changeset

* [ci] format

* chore: auto format next (#15009)

* chore(deps): update github-actions (#15019)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update all non-major dependencies (#15020)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Support extending the image API props type (#15014)

* [ci] release (#14997)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(content-layer): Try a smarter solution to normalize bare image paths in JSON (#15028)

* fix(content-layer): Try a smarter solution to normalize bare image paths in JSON

* chore: changeset

* [ci] format

* chore: document core/infra architecture (#14815)

Co-authored-by: Emanuele Stoppa <[email protected]>
Co-authored-by: Matt Kane <[email protected]>
Co-authored-by:  Matthew Phillips <[email protected]>
Co-authored-by: Matthew Phillips <[email protected]>

* [ci] format

* fix(astro): assets vite build log (#15034)

* chore(sitemap): migrate to astro:routes:resolved (#15033)

* fix: Remote images: Prevent internal caching from interfering with Astro's cache (#14954)

Co-authored-by: Florian Lefebvre <[email protected]>

* [ci] format

* Update font utility dependencies to use lighter versions (#15055)

* Update font utility dependencies to use lighter versions

* Add changeset

* skip flaky view transitions redirect test (#15060)

* chore(deps): update actions-cool/issues-helper action to v3.7.5 (#15071)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* ClientRouter: Preserve hash fragment during redirects (#15088)

* try resurrecting a flaky test (#15089)

* fix(deps): update astro adapters (#15084)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update all non-major dependencies (#15072)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update astro client runtimes (#15085)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix: move ts-plugin node_modules to dist (#15083)

* fix: move ts-plugin node_modules to dist

* add: changeset

* [ci] format

* Update image-size (#15105)

* fix: components imports paths (#15107)

* Tailwind example, README.md: update link (#15099)

* fix(assets): Use Vite's isFileLoadingAllowed to check if a file can be loaded (#15052)

* fix(assets): Use Vite's isFileLoadingAllowed to check if a file can be loaded

* test: add

* fix: windwos perhaos?

* chore: changeset

* [ci] format

* Update prettier extension to new one (#15108)

* fix(vscode): Correctly handle TypeScript blocks ending with types (#15109)

* fix(vscode): Correctly handle TypeScript blocks ending with types

* chore: changeset

* [ci] format

* fix(svelte): improve Svelte children prop type checking (#15070)

* chore: Replace fast-glob with tinyglobby in language server (#15057)

* chore: Replace fast-glob with tinyglobby in language server

* Use `expandDirectories` option for compatibility with fast-glob

* Update packages/language-tools/language-server/src/check.ts

---------

Co-authored-by: Erika <[email protected]>

* view transitions: fix Firefox e2e tests for playwright 1.57 (#15113)

* fix(deps): update astro dependencies (#15103)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Florian Lefebvre <[email protected]>

* fix: lint vt test (#15114)

* [ci] format

* fix(deps): update language tools (#15104)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Florian Lefebvre <[email protected]>

* Feature/allow node 24 vercel adapter (#15116)

* feat(fonts): new font resolver abstraction (#15111)

* [ci] format

* feat(fonts)!: upgrade unifont and support formats (#15117)

Co-authored-by: Sarah Rainsberger <[email protected]>

* fix(vue): add HTML attributes to generated TypeScript types (#15016)

* fix(vue): add HTML attributes to generated TypeScript types

Fixes #14686

* fix: add package exports and update tests for HTML attributes support

* test(vue): add astro check test for HTML attributes

Add test fixture and test case to verify that Vue components
correctly accept HTML attributes (class, style, id, data-*) and
client directives via astro check.

Follows the same pattern as the Svelte integration tests.

* chore: update lockfile for vue prop-types fixture

* feat: deduplicate context types (#15122)

Co-authored-by: Armand Philippot <[email protected]>

* perf(astro): group chunks on emit (#15123)

Co-authored-by: Florian Lefebvre <[email protected]>


Co-authored-by: matthewp <[email protected]>
Co-authored-by: florian-lefebvre <[email protected]>
Co-authored-by: ematipico <[email protected]>

* feat(fonts): clean types (#15118)

* [ci] release (#15031)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(vscode): Don't update @types/vscode automatically (#15131)

* fix(vscode): Don't update @types/vscode automatically

* chore: changeset

* fix: adjust page warning to only show up in more relevant times (#15127)

* fix: adjust page warning to only show up in more relevant times

* chore: changeset

* [ci] format

* Update security contacts list (#15143)

* fix(dev): preserve query params when base path is stripped (#15124)

Co-authored-by: Florian Lefebvre <[email protected]>

* fix(assets): hoist ?? inside JSON.stringify in virtual module codegen (#15140)

* fix(assets): hoist nullish coalescing inside JSON.stringify

Moves ?? fallbacks before serialization to eliminate dead code in
generated virtual module. Fixes esbuild suspicious-nullish-coalescing
warning.

* chore: add changeset

* Attempt to reduce falkiness in view transition e2e tests (#15142)

* Attempt to reduce falkiness in view transition e2e tests

* try wait for idle state

* next try

* Update view-transitions.test.js

* [ci] format

* fix(toolbar): skip image audit for framework components (#15149)

* fix(toolbar): skip image audit for framework components

Images inside astro-island elements (React, Vue, Svelte, etc. with client:* directives) now skip the 'Use the Image component' audit warning, since these components can't directly use Astro's Image component.

Fixes #15048

* test: remove unused image

* test: use smaller test image (22KB instead of 253KB)

* fix: Accept setCookie from both context and headers (#15152)

Co-authored-by: Florian Lefebvre <[email protected]>

* [ci] release (#15132)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(ci): Move ts-plugin-bundle to node_modules after recreating node_modules (#15156)

* fix(ci): Move ts-plugin-bundle to node_modules after recreating node_modules

* fix: make itw ork in dev

* chore: changeset

* [ci] release (#15158)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix: scripts not rendering with unused Fragment slots (#13847) (#15147)

* Fix hydration for framework components in MDX slots (#15150)

* Fix hydration for framework components in MDX slots using Astro.slots.render()

* Update packages/astro/src/runtime/server/render/slot.ts

Co-authored-by: Luiz Ferraz <[email protected]>

---------

Co-authored-by: Luiz Ferraz <[email protected]>

* [ci] format

* Fixes build

* fix: apply trailing slash query params fix to new architecture

Port fix from #15124 to vite-plugin-app/app.ts

---------

Co-authored-by: Erika <[email protected]>
Co-authored-by: Antony Faris <[email protected]>
Co-authored-by: Erika <[email protected]>
Co-authored-by: Florian Lefebvre <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Chris Swithinbank <[email protected]>
Co-authored-by: Houston (Bot) <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Emanuele Stoppa <[email protected]>
Co-authored-by: Matt Kane <[email protected]>
Co-authored-by: Florian Lefebvre <[email protected]>
Co-authored-by: Volpeon <[email protected]>
Co-authored-by: Martin Trapp <[email protected]>
Co-authored-by: fkatsuhiro <[email protected]>
Co-authored-by: Oliver Speir <[email protected]>
Co-authored-by: Andreas Deininger <[email protected]>
Co-authored-by: Roman <[email protected]>
Co-authored-by: fabon <[email protected]>
Co-authored-by: Raanelom <[email protected]>
Co-authored-by: Sarah Rainsberger <[email protected]>
Co-authored-by: Rahul Dogra <[email protected]>
Co-authored-by: Armand Philippot <[email protected]>
Co-authored-by: James Garbutt <[email protected]>
Co-authored-by: matthewp <[email protected]>
Co-authored-by: florian-lefebvre <[email protected]>
Co-authored-by: ematipico <[email protected]>
Co-authored-by: Pegasus <[email protected]>
Co-authored-by: Cameron Smith <[email protected]>
Co-authored-by: Martin Trapp <[email protected]>
Co-authored-by: Rafael ヤスヒデ 須藤 <[email protected]>
Co-authored-by: Luiz Ferraz <[email protected]>
matthewp added a commit that referenced this pull request Jan 20, 2026
* fix(ci): Reinstall deps after having published VS Code (#14996)

* fix(svelte): allow client directives (#15004)

* fix(assets): Fixes missing format option for svgs in the passthrough service (#14987)

* fix(assets): Fixes missing format option for svgs in the passthrough service

* fix: wtf is going on

* chore: changeset

* [ci] format

* chore: auto format next (#15009)

* chore(deps): update github-actions (#15019)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update all non-major dependencies (#15020)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Support extending the image API props type (#15014)

* [ci] release (#14997)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(content-layer): Try a smarter solution to normalize bare image paths in JSON (#15028)

* fix(content-layer): Try a smarter solution to normalize bare image paths in JSON

* chore: changeset

* [ci] format

* chore: document core/infra architecture (#14815)

Co-authored-by: Emanuele Stoppa <[email protected]>
Co-authored-by: Matt Kane <[email protected]>
Co-authored-by:  Matthew Phillips <[email protected]>
Co-authored-by: Matthew Phillips <[email protected]>

* [ci] format

* fix(astro): assets vite build log (#15034)

* chore(sitemap): migrate to astro:routes:resolved (#15033)

* fix: Remote images: Prevent internal caching from interfering with Astro's cache (#14954)

Co-authored-by: Florian Lefebvre <[email protected]>

* [ci] format

* Update font utility dependencies to use lighter versions (#15055)

* Update font utility dependencies to use lighter versions

* Add changeset

* skip flaky view transitions redirect test (#15060)

* chore(deps): update actions-cool/issues-helper action to v3.7.5 (#15071)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* ClientRouter: Preserve hash fragment during redirects (#15088)

* try resurrecting a flaky test (#15089)

* fix(deps): update astro adapters (#15084)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update all non-major dependencies (#15072)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update astro client runtimes (#15085)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix: move ts-plugin node_modules to dist (#15083)

* fix: move ts-plugin node_modules to dist

* add: changeset

* [ci] format

* Update image-size (#15105)

* fix: components imports paths (#15107)

* Tailwind example, README.md: update link (#15099)

* fix(assets): Use Vite's isFileLoadingAllowed to check if a file can be loaded (#15052)

* fix(assets): Use Vite's isFileLoadingAllowed to check if a file can be loaded

* test: add

* fix: windwos perhaos?

* chore: changeset

* [ci] format

* Update prettier extension to new one (#15108)

* fix(vscode): Correctly handle TypeScript blocks ending with types (#15109)

* fix(vscode): Correctly handle TypeScript blocks ending with types

* chore: changeset

* [ci] format

* fix(svelte): improve Svelte children prop type checking (#15070)

* chore: Replace fast-glob with tinyglobby in language server (#15057)

* chore: Replace fast-glob with tinyglobby in language server

* Use `expandDirectories` option for compatibility with fast-glob

* Update packages/language-tools/language-server/src/check.ts

---------

Co-authored-by: Erika <[email protected]>

* view transitions: fix Firefox e2e tests for playwright 1.57 (#15113)

* fix(deps): update astro dependencies (#15103)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Florian Lefebvre <[email protected]>

* fix: lint vt test (#15114)

* [ci] format

* fix(deps): update language tools (#15104)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Florian Lefebvre <[email protected]>

* Feature/allow node 24 vercel adapter (#15116)

* feat(fonts): new font resolver abstraction (#15111)

* [ci] format

* feat(fonts)!: upgrade unifont and support formats (#15117)

Co-authored-by: Sarah Rainsberger <[email protected]>

* fix(vue): add HTML attributes to generated TypeScript types (#15016)

* fix(vue): add HTML attributes to generated TypeScript types

Fixes #14686

* fix: add package exports and update tests for HTML attributes support

* test(vue): add astro check test for HTML attributes

Add test fixture and test case to verify that Vue components
correctly accept HTML attributes (class, style, id, data-*) and
client directives via astro check.

Follows the same pattern as the Svelte integration tests.

* chore: update lockfile for vue prop-types fixture

* feat: deduplicate context types (#15122)

Co-authored-by: Armand Philippot <[email protected]>

* perf(astro): group chunks on emit (#15123)

Co-authored-by: Florian Lefebvre <[email protected]>


Co-authored-by: matthewp <[email protected]>
Co-authored-by: florian-lefebvre <[email protected]>
Co-authored-by: ematipico <[email protected]>

* feat(fonts): clean types (#15118)

* [ci] release (#15031)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(vscode): Don't update @types/vscode automatically (#15131)

* fix(vscode): Don't update @types/vscode automatically

* chore: changeset

* fix: adjust page warning to only show up in more relevant times (#15127)

* fix: adjust page warning to only show up in more relevant times

* chore: changeset

* [ci] format

* Update security contacts list (#15143)

* fix(dev): preserve query params when base path is stripped (#15124)

Co-authored-by: Florian Lefebvre <[email protected]>

* fix(assets): hoist ?? inside JSON.stringify in virtual module codegen (#15140)

* fix(assets): hoist nullish coalescing inside JSON.stringify

Moves ?? fallbacks before serialization to eliminate dead code in
generated virtual module. Fixes esbuild suspicious-nullish-coalescing
warning.

* chore: add changeset

* Attempt to reduce falkiness in view transition e2e tests (#15142)

* Attempt to reduce falkiness in view transition e2e tests

* try wait for idle state

* next try

* Update view-transitions.test.js

* [ci] format

* fix(toolbar): skip image audit for framework components (#15149)

* fix(toolbar): skip image audit for framework components

Images inside astro-island elements (React, Vue, Svelte, etc. with client:* directives) now skip the 'Use the Image component' audit warning, since these components can't directly use Astro's Image component.

Fixes #15048

* test: remove unused image

* test: use smaller test image (22KB instead of 253KB)

* fix: Accept setCookie from both context and headers (#15152)

Co-authored-by: Florian Lefebvre <[email protected]>

* [ci] release (#15132)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(ci): Move ts-plugin-bundle to node_modules after recreating node_modules (#15156)

* fix(ci): Move ts-plugin-bundle to node_modules after recreating node_modules

* fix: make itw ork in dev

* chore: changeset

* [ci] release (#15158)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix: scripts not rendering with unused Fragment slots (#13847) (#15147)

* Fix hydration for framework components in MDX slots (#15150)

* Fix hydration for framework components in MDX slots using Astro.slots.render()

* Update packages/astro/src/runtime/server/render/slot.ts

Co-authored-by: Luiz Ferraz <[email protected]>

---------

Co-authored-by: Luiz Ferraz <[email protected]>

* [ci] format

* feat: add benchmarks for build times (#15144)

* feat: add benchmarks for build times

* fix: put back old benchmarks

* fix: remove old files

* fix: reduce iteration count

* fix: move setup in a different step

* fix: ignore lints in benchmark projects

* chore: lockfile

* fix: just straight up nonsense

* fix: im stuck in linting hell

* [ci] format

* feat(fonts)!: update font provider API (#15130)

Co-authored-by: Sarah Rainsberger <[email protected]>

* [ci] format

* fix(deps): update astro adapters (#15173)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update dependency ovsx to ^0.10.8 (#15172)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update dependency preact to v10.28.2 [security] (#15160)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat(fonts): export googleicons provider (#15174)

Co-authored-by: HiDeoo <[email protected]>

* [ci] release (#15159)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix: fix image 500 error when moving dist directory in standalone Node (#15169)

* fix: fix image 500 error when moving dist directory in standalone Node

* clean up old output directory

* [ci] format

* simplify gif image detection in sharp service (#15161)

* Revert fix: Allow node: prefix for Node builtins for Vercel middleware (#14863)

* Revert "fix: Allow node: prefix for Node builtins for Vercel middleware (#14839)"

This reverts commit 9a284cd.

* fix: adjust for feedback

* chore: changeset

---------

Co-authored-by: Princesseuh <[email protected]>

* [ci] format

* fix(node): hash URL stripping (#15196)

* [ci] format

* fix(core): add defensive validation for mod.page in App.render (#15148)

* chore(deps): update dependency undici to v6.23.0 [security] (#15209)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(css): rewrite absolute URLs with base path in dev mode (#14622)

* fix(css): rewrite absolute URLs with base path in dev mode

Fixes CSS url() references to public assets returning 404 in dev mode
when base path is configured. Applies URL rewriting after preprocessCSS()
using Vite's cssUrlRE regex pattern.

Closes #14585

* fix linting error

* add changeset

* fix spelling in changeset

* Update packages/astro/test/units/compile/css-base-path.test.js

* fix: experimental

---------

Co-authored-by: Florian Lefebvre <[email protected]>
Co-authored-by: Emanuele Stoppa <[email protected]>
Co-authored-by: Erika <[email protected]>

* [ci] format

* Feature(sitemap): named files chunking strategy (#14471)

* feat(sitemap): add chunking strategy for sitemaps

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.

This change introduces a new `writeSitemapChunk` function to handle
the writing of individual sitemap chunks.

* feat(sitemap): add chunks option to sitemap config

Adds a `chunks` option to the sitemap configuration schema.
This allows users to define custom chunking strategies for
generating sitemaps, providing flexibility in how the sitemap
is split into multiple files.

* feat(sitemap): add sitemap chunk writing functionality

* fix(sitemap): fix empty callback in writeSitemap

The empty callback function in the `writeSitemap` function was
causing unnecessary function calls. This commit fixes this by
removing the empty callback.

* feat(sitemap): add test fixture for sitemap chunking

This commit adds a test fixture to verify the sitemap chunking
functionality. It includes a configuration file, dependencies,
and several pages to simulate a real-world scenario.

* test(sitemap): add test for sitemap chunking with files

* feat(sitemap): add changeset for sitemap chunking

Adds changeset to document the new sitemap chunking feature.
This feature allows splitting sitemap generation into chunks
based on customizable logic, improving management of large
sitemaps and performance.

* build: update dependencies and add astro

* chore: remove unused astro dependency

* chore: remove unused entries from lockfile

* refactor(sitemap): improve import ordering and formatting

* refactor(sitemap): improve import ordering

The import order of `AstroConfig` has been moved to align
with other imports, improving code readability and
consistency. This change ensures that type imports are
grouped together, making the codebase easier to maintain.

* refactor(sitemap): improve import ordering

* refactor(sitemap): improve import ordering

* refactor(sitemap): improve import ordering

* refactor(sitemap): improve chunk file test readability

Simplify the chunk file test by using `path.resolve` and
`includes` for better readability and maintainability.
This change improves the test's clarity without altering
its functionality.

* test(sitemap): fix flaky chunk file tests

The tests were failing intermittently because the `readXML` function
was not properly resolving the file path. This commit updates the
`readXML` function to use `fixture.readFile` to ensure that the file
path is resolved correctly. Additionally, the `flatMapUrls` function
is now async to ensure that the `readXML` function is awaited.

* refactor(sitemap): improve import ordering

* Update .changeset/floppy-times-grab.md

Co-authored-by: Matt Kane <[email protected]>

* chore(sitemap): update changeset to minor

The previous changeset incorrectly marked the sitemap chunking feature as a major change. This commit corrects the changeset to reflect that it is a minor feature addition.

* feat(sitemap): add chunking support for sitemap generation

* fix: attempt to fix lockfile

* fix: conflict

* fix: lockfile

---------

Co-authored-by: Matt Kane <[email protected]>
Co-authored-by: Princesseuh <[email protected]>

* [ci] format

* fix(docs): replace outdated Astro docs links (#15199)

* fix: update outdated links to Astro Docs

* some were correctly redirected, but might as well use the new links
* some used the right page, but the section has been renamed or removed
* some were no longer targeting the correct page

* docs: add changeset

* fix(lint): Move ESLint comment (#15216)

* chore: move all pnpm settings to `pnpm-workspace.yaml` (#15139)

* Upgrade diff package to v8 (#15219)

* Upgrade diff package to v8

* Update packages/astro/package.json

Co-authored-by: Chris Swithinbank <[email protected]>

---------

Co-authored-by: Chris Swithinbank <[email protected]>

* [ci] release (#15188)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix: update devalue to the latest (#15222)

* fix(css): prevent CSS double-bundling (#14991) (#15017)

* fix(css): prevent double-bundling when CSS imported from multiple locations

Fixes #14991

When CSS was imported in both a page's frontmatter and a component's script tag,
it was bundled twice in production builds. This happened because the CSS plugins
run for both SSR and client builds, adding CSS to the same pageData.styles array.

The fix adds content-based deduplication that checks existing styles before adding
new ones - comparing by content for inline CSS and by src for external CSS.

* chore: update pnpm-lock.yaml for new test fixture

---------

Co-authored-by: Erika <[email protected]>

* chore: add devalue changeset (#15225)

* [ci] release (#15224)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* ci(benchmark): Run benchmarks on next as well (#15226)

* fix: assets referenced via js chunks are not flagged as orphaned (#14607)

* test: add failing case for url imports

* fix: files added to chunks are not orphaned

* docs: add comment explaining updated orphaned logic

* docs: add changeset

* fix: only check importedAssets

* test: add case for ?url&no-inline import

* Revert "Revert "fix(build): Prevent duplicate CSS for hydrated client components" (#14612)"

This reverts commit 18552c7.

* docs: update changeset

* docs: update changeset

* fix: lockfile

---------

Co-authored-by: Erika <[email protected]>

* [ci] format

* Include styles for conditionally rendered Svelte 5 components (#15227)

* fix(css): include styles for conditionally rendered Svelte 5 components

When Svelte 5 components are conditionally rendered (e.g., inside {#if} blocks
with an initially false condition), their styles were not being included in
production builds. This happened because:

1. Svelte 5.26+ added css.hasGlobal flag to compiler output
2. vite-plugin-svelte 5.1.0+ uses this to add cssScopeTo metadata
3. Vite 6.2+ cssScopeTo allows CSS treeshaking if the export isn't "used"

During SSR, conditionally rendered components aren't included in the server
build (tree-shaken), but they are in the client build. Astro's CSS-to-page
mapping primarily happens during the server build, so the CSS gets orphaned.

The fix adds logic in the client build's generateBundle to:
- Track which component exports are actually rendered (renderedComponentExports)
- For CSS modules with cssScopeTo metadata where the export IS rendered,
  walk up the module graph to find pages and ensure the CSS is included

Fixes #14252

* Track components from server pages

* Revert "Update prettier extension to new one (#15108)" (#15235)

This reverts commit a012a86.

* fix(deps): update astro client runtimes (#15240)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update e18e/action-dependency-diff action to v1.4.3 (#15239)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update astro adapters (#15243)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update astro dependencies (#15241)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update dependency prettier to ^3.8.0 (#15244)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update all non-major dependencies (#15242)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Florian Lefebvre <[email protected]>

* fix: build

* fix: lint

* chore: upgrade pnpm (#15246)

* chore: enable lockfile maintenance (#15245)

* [ci] format

* refactor(fonts): do not mutate provider name (#15190)

* refactor(fonts): use runtime as entrypoint (#15181)

* revert: renovate config rename (#15250)

* Fix greedy regex in error message markdown rendering (#15230)

Fixes #15068

* bug: Support remote url for css in content collection (#15254)

fixes: #15252

* fix: prevent font copying when stopping dev server with q+enter (#15178)

Co-authored-by: Florian Lefebvre <[email protected]>

* fix: renovate config typo (#15256)

* React / MDX nested regression (#15253)

* test: add e2e test for React component nested in div in MDX

Adds a regression test for issue #15251 where React components with
client:load nested inside HTML elements in MDX files fail to hydrate.

* fix: revert renderComponentToString changes that broke nested React hydration in MDX

Reverts the changes to renderComponentToString from PR #15150 that
caused React components nested inside HTML elements in MDX files to
fail to hydrate. The original fix for MDX slot hydration still works
without these changes.

Fixes #15251

* chore: add changeset

* chore(deps): lock file maintenance (#15257)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Fix tests that needed updating

* Fix test that's statically false by mistake

* Add virtual modules from astro integrations to external list

---------

Co-authored-by: Erika <[email protected]>
Co-authored-by: Antony Faris <[email protected]>
Co-authored-by: Erika <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Chris Swithinbank <[email protected]>
Co-authored-by: Houston (Bot) <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Emanuele Stoppa <[email protected]>
Co-authored-by: Matt Kane <[email protected]>
Co-authored-by: Matthew Phillips <[email protected]>
Co-authored-by: Florian Lefebvre <[email protected]>
Co-authored-by: Volpeon <[email protected]>
Co-authored-by: Martin Trapp <[email protected]>
Co-authored-by: fkatsuhiro <[email protected]>
Co-authored-by: Oliver Speir <[email protected]>
Co-authored-by: Andreas Deininger <[email protected]>
Co-authored-by: Roman <[email protected]>
Co-authored-by: fabon <[email protected]>
Co-authored-by: Raanelom <[email protected]>
Co-authored-by: Sarah Rainsberger <[email protected]>
Co-authored-by: Rahul Dogra <[email protected]>
Co-authored-by: Armand Philippot <[email protected]>
Co-authored-by: James Garbutt <[email protected]>
Co-authored-by: matthewp <[email protected]>
Co-authored-by: ematipico <[email protected]>
Co-authored-by: Pegasus <[email protected]>
Co-authored-by: Cameron Smith <[email protected]>
Co-authored-by: Martin Trapp <[email protected]>
Co-authored-by: Rafael ヤスヒデ 須藤 <[email protected]>
Co-authored-by: Luiz Ferraz <[email protected]>
Co-authored-by: Matthew Phillips <[email protected]>
Co-authored-by: HiDeoo <[email protected]>
Co-authored-by: Julien Cayzac <[email protected]>
Co-authored-by: Drew Powers <[email protected]>
Co-authored-by: Emanuele Stoppa <[email protected]>
Co-authored-by: MkDev11 <[email protected]>
Co-authored-by: andy <[email protected]>
Co-authored-by: Luky Setiawan <[email protected]>
Co-authored-by: btea <[email protected]>
Co-authored-by: cid <[email protected]>
Co-authored-by: Simen Sagholen Førrisdal <[email protected]>
Co-authored-by: Alex Launi <[email protected]>
Co-authored-by: Kedar Vartak <[email protected]>
Co-authored-by: Matthew Phillips <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: astro Related to the core `astro` package (scope)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants