diff --git a/.changeset/tricky-clocks-end.md b/.changeset/tricky-clocks-end.md new file mode 100644 index 0000000000..8b57899881 --- /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 ea7cd7e533..621849688f 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 0000000000..b1a48b07df --- /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 0000000000..80068581cc --- /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 0000000000..0c7fb90a73 --- /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 0000000000..e7ba9910e2 --- /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 7f360aebc7..92e37c0af9 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 0000000000..93dc95c395 --- /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 0bfaef6371..525adb49ac 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':