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':