From 560d0dab1cc7510e5d01f38955c13b329ebf66ff Mon Sep 17 00:00:00 2001 From: Hee Date: Wed, 2 Aug 2023 08:06:50 +0900 Subject: [PATCH] feat: add cache headers to assets in Vercel adapter (#7729) * feat: cache assets in Vercel adapter * Update tidy-tips-doubt.md * chore: update lockfile * Update packages/integrations/vercel/test/static-assets.test.js * Update packages/integrations/vercel/test/static-assets.test.js * Update packages/integrations/vercel/test/static-assets.test.js * chore: update split test --------- Co-authored-by: Kid <44045911+kidonng@users.noreply.github.com> Co-authored-by: Nate Moore Co-authored-by: Nate Moore --- .changeset/tidy-tips-doubt.md | 5 ++ .../integrations/vercel/src/edge/adapter.ts | 5 ++ .../vercel/src/serverless/adapter.ts | 11 ++- .../integrations/vercel/src/static/adapter.ts | 10 ++- .../fixtures/static-assets/astro.config.mjs | 4 + .../test/fixtures/static-assets/package.json | 9 ++ .../static-assets/src/pages/index.astro | 8 ++ .../integrations/vercel/test/split.test.js | 2 +- .../vercel/test/static-assets.test.js | 84 +++++++++++++++++++ pnpm-lock.yaml | 9 ++ 10 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 .changeset/tidy-tips-doubt.md create mode 100644 packages/integrations/vercel/test/fixtures/static-assets/astro.config.mjs create mode 100644 packages/integrations/vercel/test/fixtures/static-assets/package.json create mode 100644 packages/integrations/vercel/test/fixtures/static-assets/src/pages/index.astro create mode 100644 packages/integrations/vercel/test/static-assets.test.js diff --git a/.changeset/tidy-tips-doubt.md b/.changeset/tidy-tips-doubt.md new file mode 100644 index 000000000000..e0a38c69e858 --- /dev/null +++ b/.changeset/tidy-tips-doubt.md @@ -0,0 +1,5 @@ +--- +'@astrojs/vercel': minor +--- + +Add cache headers to assets in Vercel adapter diff --git a/packages/integrations/vercel/src/edge/adapter.ts b/packages/integrations/vercel/src/edge/adapter.ts index 5af00dfce004..b83c9f2b729e 100644 --- a/packages/integrations/vercel/src/edge/adapter.ts +++ b/packages/integrations/vercel/src/edge/adapter.ts @@ -154,6 +154,11 @@ export default function vercelEdge({ version: 3, routes: [ ...getRedirects(routes, _config), + { + src: `^/${_config.build.assets}/(.*)$`, + headers: { 'cache-control': 'public, max-age=31536000, immutable' }, + continue: true, + }, { handle: 'filesystem' }, { src: '/.*', dest: 'render' }, ], diff --git a/packages/integrations/vercel/src/serverless/adapter.ts b/packages/integrations/vercel/src/serverless/adapter.ts index 2d12db5ad6ca..1a2f9d82a1bd 100644 --- a/packages/integrations/vercel/src/serverless/adapter.ts +++ b/packages/integrations/vercel/src/serverless/adapter.ts @@ -187,7 +187,16 @@ export default function vercelServerless({ // https://vercel.com/docs/build-output-api/v3#build-output-configuration await writeJson(new URL(`./config.json`, _config.outDir), { version: 3, - routes: [...getRedirects(routes, _config), { handle: 'filesystem' }, ...routeDefinitions], + routes: [ + ...getRedirects(routes, _config), + { + src: `^/${_config.build.assets}/(.*)$`, + headers: { 'cache-control': 'public, max-age=31536000, immutable' }, + continue: true, + }, + { handle: 'filesystem' }, + ...routeDefinitions, + ], ...(imageService || imagesConfig ? { images: imagesConfig ? imagesConfig : defaultImageConfig } : {}), diff --git a/packages/integrations/vercel/src/static/adapter.ts b/packages/integrations/vercel/src/static/adapter.ts index f710356aa7af..bc83b24afcf1 100644 --- a/packages/integrations/vercel/src/static/adapter.ts +++ b/packages/integrations/vercel/src/static/adapter.ts @@ -71,7 +71,15 @@ export default function vercelStatic({ // https://vercel.com/docs/build-output-api/v3#build-output-configuration await writeJson(new URL(`./config.json`, getVercelOutput(_config.root)), { version: 3, - routes: [...getRedirects(routes, _config), { handle: 'filesystem' }], + routes: [ + ...getRedirects(routes, _config), + { + src: `^/${_config.build.assets}/(.*)$`, + headers: { 'cache-control': 'public, max-age=31536000, immutable' }, + continue: true, + }, + { handle: 'filesystem' }, + ], ...(imageService || imagesConfig ? { images: imagesConfig ? imagesConfig : defaultImageConfig } : {}), diff --git a/packages/integrations/vercel/test/fixtures/static-assets/astro.config.mjs b/packages/integrations/vercel/test/fixtures/static-assets/astro.config.mjs new file mode 100644 index 000000000000..20b0b8e2ba7f --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/static-assets/astro.config.mjs @@ -0,0 +1,4 @@ +import { defineConfig } from 'astro/config'; + +export default defineConfig({ +}); diff --git a/packages/integrations/vercel/test/fixtures/static-assets/package.json b/packages/integrations/vercel/test/fixtures/static-assets/package.json new file mode 100644 index 000000000000..e1b608a856fd --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/static-assets/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/astro-vercel-static-assets", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/vercel": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/integrations/vercel/test/fixtures/static-assets/src/pages/index.astro b/packages/integrations/vercel/test/fixtures/static-assets/src/pages/index.astro new file mode 100644 index 000000000000..9c077e2a381b --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/static-assets/src/pages/index.astro @@ -0,0 +1,8 @@ + + + Testing + + +

Testing

+ + diff --git a/packages/integrations/vercel/test/split.test.js b/packages/integrations/vercel/test/split.test.js index 4f3f3904edca..9044954f28f5 100644 --- a/packages/integrations/vercel/test/split.test.js +++ b/packages/integrations/vercel/test/split.test.js @@ -24,6 +24,6 @@ describe('build: split', () => { it('creates the route definitions in the config.json', async () => { const json = await fixture.readFile('../.vercel/output/config.json'); const config = JSON.parse(json); - expect(config.routes).to.have.a.lengthOf(3); + expect(config.routes).to.have.a.lengthOf(4); }); }); diff --git a/packages/integrations/vercel/test/static-assets.test.js b/packages/integrations/vercel/test/static-assets.test.js new file mode 100644 index 000000000000..b2bb4542fd6e --- /dev/null +++ b/packages/integrations/vercel/test/static-assets.test.js @@ -0,0 +1,84 @@ +import { expect } from 'chai'; +import { loadFixture } from './test-utils.js'; + +describe('Static Assets', () => { + /** @type {import('../../../astro/test/test-utils.js').Fixture} */ + let fixture; + + const VALID_CACHE_CONTROL = 'public, max-age=31536000, immutable'; + + async function build({ adapter, assets }) { + fixture = await loadFixture({ + root: './fixtures/static-assets/', + adapter, + build: { + assets, + } + }); + await fixture.build(); + } + + async function getConfig() { + const json = await fixture.readFile('../.vercel/output/config.json'); + const config = JSON.parse(json); + + return config; + } + + async function getAssets() { + return fixture.config.build.assets; + } + + async function checkValidCacheControl(assets) { + const config = await getConfig(); + + const route = config.routes.find((r) => r.src === `^/${assets ?? getAssets()}/(.*)$`); + expect(route.headers['cache-control']).to.equal(VALID_CACHE_CONTROL); + expect(route.continue).to.equal(true); + } + + describe('static adapter', async () => { + const adapter = await import('@astrojs/vercel/static'); + + it('has cache control', async () => { + await build({ adapter }); + checkValidCacheControl(); + }); + + it('has cache control other assets', async () => { + const assets = '_foo'; + await build({ adapter, assets }); + checkValidCacheControl(assets); + }); + }); + + describe('serverless adapter', async () => { + const adapter = await import('@astrojs/vercel/serverless'); + + it('has cache control', async () => { + await build({ adapter }); + checkValidCacheControl(); + }); + + it('has cache control other assets', async () => { + const assets = '_foo'; + await build({ adapter, assets }); + checkValidCacheControl(assets); + }); + }); + + describe('edge adapter', async () => { + const adapter = await import('@astrojs/vercel/edge'); + + it('has cache control', async () => { + await build({ adapter }); + checkValidCacheControl(); + }); + + it('has cache control other assets', async () => { + const assets = '_foo'; + await build({ adapter, assets }); + checkValidCacheControl(assets); + }); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01d7ffa3ba12..82c130ed93b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5047,6 +5047,15 @@ importers: specifier: workspace:* version: link:../../../../../astro + packages/integrations/vercel/test/fixtures/static-assets: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + packages/integrations/vercel/test/hosted/hosted-astro-project: dependencies: '@astrojs/vercel':