diff --git a/.changeset/tricky-clocks-end.md b/.changeset/tricky-clocks-end.md
new file mode 100644
index 000000000000..8b57899881cb
--- /dev/null
+++ b/.changeset/tricky-clocks-end.md
@@ -0,0 +1,7 @@
+---
+'@astrojs/vercel': minor
+---
+
+The Vercel adapter now streams responses!
+
+This brings better performance to your visitors by showing them content as it is rendered. The browser can also start loading the required stylesheets and scripts much sooner, which ultimately results in faster full page loads.
diff --git a/packages/integrations/vercel/src/serverless/adapter.ts b/packages/integrations/vercel/src/serverless/adapter.ts
index ea7cd7e533f8..621849688ff3 100644
--- a/packages/integrations/vercel/src/serverless/adapter.ts
+++ b/packages/integrations/vercel/src/serverless/adapter.ts
@@ -341,7 +341,7 @@ interface CreateFunctionFolderArgs {
NTF_CACHE: any;
includeFiles: URL[];
excludeFiles?: string[];
- maxDuration?: number;
+ maxDuration: number | undefined;
}
async function createFunctionFolder({
@@ -381,6 +381,7 @@ async function createFunctionFolder({
handler,
launcherType: 'Nodejs',
maxDuration,
+ supportsResponseStreaming: true,
});
}
diff --git a/packages/integrations/vercel/test/fixtures/streaming/astro.config.mjs b/packages/integrations/vercel/test/fixtures/streaming/astro.config.mjs
new file mode 100644
index 000000000000..b1a48b07df94
--- /dev/null
+++ b/packages/integrations/vercel/test/fixtures/streaming/astro.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'astro/config';
+import vercel from '@astrojs/vercel/serverless';
+
+export default defineConfig({
+ output: "server",
+ adapter: vercel()
+});
diff --git a/packages/integrations/vercel/test/fixtures/streaming/package.json b/packages/integrations/vercel/test/fixtures/streaming/package.json
new file mode 100644
index 000000000000..80068581cc33
--- /dev/null
+++ b/packages/integrations/vercel/test/fixtures/streaming/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@test/vercel-streaming",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/vercel": "workspace:*",
+ "astro": "workspace:*"
+ }
+}
+
\ No newline at end of file
diff --git a/packages/integrations/vercel/test/fixtures/streaming/src/pages/one.astro b/packages/integrations/vercel/test/fixtures/streaming/src/pages/one.astro
new file mode 100644
index 000000000000..0c7fb90a735e
--- /dev/null
+++ b/packages/integrations/vercel/test/fixtures/streaming/src/pages/one.astro
@@ -0,0 +1,8 @@
+
+
+ One
+
+
+ One
+
+
diff --git a/packages/integrations/vercel/test/fixtures/streaming/src/pages/two.astro b/packages/integrations/vercel/test/fixtures/streaming/src/pages/two.astro
new file mode 100644
index 000000000000..e7ba9910e2a6
--- /dev/null
+++ b/packages/integrations/vercel/test/fixtures/streaming/src/pages/two.astro
@@ -0,0 +1,8 @@
+
+
+ Two
+
+
+ Two
+
+
diff --git a/packages/integrations/vercel/test/static-assets.test.js b/packages/integrations/vercel/test/static-assets.test.js
index 7f360aebc70c..92e37c0af9ce 100644
--- a/packages/integrations/vercel/test/static-assets.test.js
+++ b/packages/integrations/vercel/test/static-assets.test.js
@@ -7,9 +7,10 @@ describe('Static Assets', () => {
const VALID_CACHE_CONTROL = 'public, max-age=31536000, immutable';
- async function build({ adapter, assets }) {
+ async function build({ adapter, assets, output }) {
fixture = await loadFixture({
root: './fixtures/static-assets/',
+ output,
adapter,
build: {
assets,
@@ -38,31 +39,31 @@ describe('Static Assets', () => {
}
describe('static adapter', async () => {
- const adapter = await import('@astrojs/vercel/static');
+ const { default: vercel } = await import('@astrojs/vercel/static');
it('has cache control', async () => {
- await build({ adapter });
+ await build({ adapter: vercel() });
checkValidCacheControl();
});
it('has cache control other assets', async () => {
const assets = '_foo';
- await build({ adapter, assets });
+ await build({ adapter: vercel(), assets });
checkValidCacheControl(assets);
});
});
describe('serverless adapter', async () => {
- const adapter = await import('@astrojs/vercel/serverless');
+ const { default: vercel } = await import('@astrojs/vercel/serverless');
it('has cache control', async () => {
- await build({ adapter });
+ await build({ output: "server", adapter: vercel() });
checkValidCacheControl();
});
it('has cache control other assets', async () => {
const assets = '_foo';
- await build({ adapter, assets });
+ await build({ output: "server", adapter: vercel(), assets });
checkValidCacheControl(assets);
});
});
diff --git a/packages/integrations/vercel/test/streaming.test.js b/packages/integrations/vercel/test/streaming.test.js
new file mode 100644
index 000000000000..93dc95c39508
--- /dev/null
+++ b/packages/integrations/vercel/test/streaming.test.js
@@ -0,0 +1,21 @@
+import { loadFixture } from './test-utils.js';
+import { expect } from 'chai';
+
+describe('maxDuration', () => {
+ /** @type {import('./test-utils.js').Fixture} */
+ let fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/streaming/',
+ });
+ await fixture.build();
+ });
+
+ it('makes it to vercel function configuration', async () => {
+ const vcConfig = JSON.parse(
+ await fixture.readFile('../.vercel/output/functions/render.func/.vc-config.json')
+ );
+ expect(vcConfig).to.deep.include({ supportsResponseStreaming: true });
+ });
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0bfaef637100..525adb49ac9a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4731,6 +4731,15 @@ importers:
specifier: workspace:*
version: link:../../../../../astro
+ packages/integrations/vercel/test/fixtures/streaming:
+ dependencies:
+ '@astrojs/vercel':
+ specifier: workspace:*
+ version: link:../../..
+ astro:
+ specifier: workspace:*
+ version: link:../../../../../astro
+
packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server:
dependencies:
'@astrojs/vercel':