Skip to content

Commit

Permalink
feat: vercel-edge provider (#337)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 authored Jul 12, 2022
1 parent b6c941b commit ad2b976
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 1 deletion.
13 changes: 13 additions & 0 deletions docs/deploy/providers/vercel.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,16 @@ After your project has been imported and deployed, all subsequent pushes to bran

Learn more about Vercel’s [Git Integration](https://vercel.com/docs/concepts/git).

## Vercel Edge Functions

**Preset:** `vercel-edge` ([switch to this preset](/deploy/#changing-the-deployment-preset))

It is possible to deploy your nitro applications directly on [Vercel Edge Functions](https://vercel.com/docs/concepts/functions/edge-functions).

> Vercel Edge Functions allow you to deliver content to your site's visitors with speed and personalization.
> They are deployed globally by default on Vercel's Edge Network and enable you to move server-side logic to the Edge, close to your visitor's origin.
> Edge Functions use the Vercel Edge Runtime, which is built on the same high-performance V8 JavaScript and WebAssembly engine that is used by the Chrome browser.
> By taking advantage of this small runtime, Edge Functions can have faster cold boots and higher scalability than Serverless Functions.
> Edge Functions run after the cache, and can both cache and return responses. [Read More](https://vercel.com/docs/concepts/functions/edge-functions)
In oerder to enable this target, please set `NITRO_PRESET` environment variable to `vercel-edge`.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"@types/semver": "^7.3.10",
"@types/serve-static": "^1.13.10",
"c8": "^7.11.3",
"edge-runtime": "1.1.0-beta.11",
"eslint": "^8.19.0",
"execa": "^6.1.0",
"miniflare": "^2.6.0",
Expand Down
70 changes: 70 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions src/presets/vercel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,49 @@ export const vercel = defineNitroPreset({
}
}
})

export const vercelEdge = defineNitroPreset({
extends: 'base-worker',
entry: '#internal/nitro/entries/vercel-edge',
output: {
dir: '{{ rootDir }}/.vercel/output',
serverDir: '{{ output.dir }}/functions/index.func',
publicDir: '{{ output.dir }}/static'
},
commands: {
deploy: '',
preview: 'npx edge-runtime ./functions/index.func/index.mjs --listen'
},
hooks: {
async 'compiled' (nitro: Nitro) {
const buildConfigPath = resolve(nitro.options.output.dir, 'config.json')
const buildConfig = {
version: '3',
routes: [
...nitro.options.publicAssets
.filter(asset => !asset.fallthrough)
.map(asset => asset.baseURL)
.map(baseURL => ({
src: baseURL + '(.*)',
headers: {
'cache-control': 'public,max-age=31536000,immutable'
},
continue: true
})),
{
src: '/(.*)',
dest: '/'
}
]
}
await writeFile(buildConfigPath, JSON.stringify(buildConfig, null, 2))

const functionConfigPath = resolve(nitro.options.output.serverDir, '.vc-config.json')
const functionConfig = {
runtime: 'edge',
entrypoint: 'index.mjs'
}
await writeFile(functionConfigPath, JSON.stringify(functionConfig, null, 2))
}
}
})
36 changes: 36 additions & 0 deletions src/runtime/entries/vercel-edge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import '#internal/nitro/virtual/polyfill'
import { requestHasBody, useRequestBody } from '#internal/nitro/utils'
import { nitroApp } from '#internal/nitro/app'

addEventListener('fetch', (event: any) => {
event.respondWith(handleEvent(event))
})

async function handleEvent (event) {
const url = new URL(event.request.url)
let body
if (requestHasBody(event.request)) {
body = await useRequestBody(event.request)
}

const r = await nitroApp.localCall({
event,
url: url.pathname + url.search,
host: url.hostname,
protocol: url.protocol,
headers: Object.fromEntries(event.request.headers.entries()),
method: event.request.method,
redirect: event.request.redirect,
body
})

return new Response(r.body, {
headers: normalizeOutgoingHeaders(r.headers),
status: r.status,
statusText: r.statusText
})
}

function normalizeOutgoingHeaders (headers: Record<string, string | string[] | undefined>) {
return Object.entries(headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(',') : v])
}
15 changes: 15 additions & 0 deletions test/presets/vercel.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { promises as fsp } from 'fs'
import { resolve } from 'pathe'
import { describe } from 'vitest'
import { EdgeRuntime } from 'edge-runtime'
import { setupTest, startServer, testNitro } from '../tests'

describe('nitro:preset:vercel', async () => {
Expand All @@ -14,3 +16,16 @@ describe('nitro:preset:vercel', async () => {
}
})
})

describe('nitro:preset:vercel-edge', async () => {
const ctx = await setupTest('vercel-edge')
testNitro(ctx, async () => {
const entry = resolve(ctx.outDir, 'functions/index.func/index.mjs')
const entryCode = await fsp.readFile(entry, 'utf8')
const runtime = new EdgeRuntime({ initialCode: entryCode })
return async ({ url }) => {
const res = await runtime.dispatchFetch('http://localhost' + url)
return res
}
})
})
2 changes: 1 addition & 1 deletion test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export async function setupTest (preset) {
const nitro = ctx.nitro = await createNitro({
preset: ctx.preset,
rootDir: ctx.rootDir,
serveStatic: preset !== 'cloudflare',
serveStatic: preset !== 'cloudflare' && preset !== 'vercel-edge',
output: { dir: ctx.outDir }
})
await prepare(nitro)
Expand Down

0 comments on commit ad2b976

Please sign in to comment.