diff --git a/.changeset/great-pants-chew.md b/.changeset/great-pants-chew.md new file mode 100644 index 000000000000..189d09bd37fb --- /dev/null +++ b/.changeset/great-pants-chew.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes response.arrayBuffer() handling in large pages diff --git a/packages/astro/src/runtime/server/response.ts b/packages/astro/src/runtime/server/response.ts index 184d00a32d52..35be534427cd 100644 --- a/packages/astro/src/runtime/server/response.ts +++ b/packages/astro/src/runtime/server/response.ts @@ -34,11 +34,19 @@ function createResponseClass() { async arrayBuffer(): Promise { if (this.#isStream && isNodeJS) { let body = this.#body as AsyncIterable; - let chunks: number[] = []; + let chunks: Uint8Array[] = []; + let len = 0; for await (let chunk of body) { - chunks.push(...chunk); + chunks.push(chunk); + len += chunk.length; } - return Uint8Array.from(chunks); + let ab = new Uint8Array(len); + let offset = 0; + for(const chunk of chunks) { + ab.set(chunk, offset); + offset += chunk.length; + } + return ab; } return super.arrayBuffer(); } diff --git a/packages/astro/test/fixtures/large-array/astro.config.mjs b/packages/astro/test/fixtures/large-array/astro.config.mjs new file mode 100644 index 000000000000..a6c39b8535d2 --- /dev/null +++ b/packages/astro/test/fixtures/large-array/astro.config.mjs @@ -0,0 +1,7 @@ +import { defineConfig } from 'astro/config'; +import solid from '@astrojs/solid-js'; + +// https://astro.build/config +export default defineConfig({ + integrations: [solid()], +}); diff --git a/packages/astro/test/fixtures/large-array/package.json b/packages/astro/test/fixtures/large-array/package.json new file mode 100644 index 000000000000..c8e0013659e4 --- /dev/null +++ b/packages/astro/test/fixtures/large-array/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/large-array-solid", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/solid-js": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/large-array/src/components/Counter.jsx b/packages/astro/test/fixtures/large-array/src/components/Counter.jsx new file mode 100644 index 000000000000..fb8706e03796 --- /dev/null +++ b/packages/astro/test/fixtures/large-array/src/components/Counter.jsx @@ -0,0 +1,18 @@ +import { createSignal } from 'solid-js'; + +export default function Counter({ children, largeProp }) { + const [count, setCount] = createSignal(0); + const add = () => setCount(count() + 1); + const subtract = () => setCount(count() - 1); + + return ( + <> +
+ +
{count()}
+ +
+
{children}
+ + ); +} diff --git a/packages/astro/test/fixtures/large-array/src/pages/index.astro b/packages/astro/test/fixtures/large-array/src/pages/index.astro new file mode 100644 index 000000000000..1a77ebed644f --- /dev/null +++ b/packages/astro/test/fixtures/large-array/src/pages/index.astro @@ -0,0 +1,32 @@ +--- +import Counter from '../components/Counter.jsx'; +const largeArray = [] +for (let i = 0; i < 600; i++) { + largeArray.push({ a: 'abc', b: 'abc', c: 'abc', d: 'abc', e: 'abc', foo: 'bar' }) +} +--- + + + + + + + + + +
+ +

Hello, Solid!

+
+
+ + diff --git a/packages/astro/test/ssr-large-array.test.js b/packages/astro/test/ssr-large-array.test.js new file mode 100644 index 000000000000..64a82222b32b --- /dev/null +++ b/packages/astro/test/ssr-large-array.test.js @@ -0,0 +1,35 @@ +import { expect } from 'chai'; +import * as cheerio from 'cheerio'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; + +describe('SSR with Large Array and client rendering', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/large-array/', + experimental: { + ssr: true, + }, + adapter: testAdapter(), + }); + await fixture.build(); + }); + + it('Using response.arrayBuffer() gets the right HTML', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/'); + const response = await app.render(request); + const data = await response.arrayBuffer(); + const html = new TextDecoder().decode(data); + + const $ = cheerio.load(html); + expect($('head meta[name="viewport"]')).to.have.a.lengthOf(1); + expect($('head link[rel="icon"]')).to.have.a.lengthOf(1); + expect($('main')).to.have.a.lengthOf(1); + expect($('astro-island')).to.have.a.lengthOf(1); + expect($('h1').text()).to.equal('Hello, Solid!'); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4553823e742f..88161e515e91 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1538,6 +1538,14 @@ importers: '@astrojs/vue': link:../../../../integrations/vue astro: link:../../.. + packages/astro/test/fixtures/large-array: + specifiers: + '@astrojs/solid-js': workspace:* + astro: workspace:* + dependencies: + '@astrojs/solid-js': link:../../../../integrations/solid + astro: link:../../.. + packages/astro/test/fixtures/legacy-build: specifiers: '@astrojs/vue': workspace:*