Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vercel): incremental static generation + swr #545

Merged
merged 12 commits into from
Nov 15, 2022
26 changes: 24 additions & 2 deletions src/presets/vercel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { resolve } from 'pathe'
import fsp from 'fs/promises'
import { dirname, relative, resolve } from 'pathe'
import { defu } from 'defu'
import { withoutLeadingSlash } from 'ufo'
import { writeFile } from '../utils'
Expand Down Expand Up @@ -34,6 +35,18 @@ export const vercel = defineNitroPreset({
shouldAddHelpers: false
}
await writeFile(functionConfigPath, JSON.stringify(functionConfig, null, 2))

// Write prerender functions
for (const [key, value] of Object.entries(nitro.options.routeRules).filter(([_, value]) => value.cache && (value.cache.swr || value.cache.static))) {
if (!value.cache) { continue } // for type support
const funcPrefix = resolve(nitro.options.output.serverDir, '..' + generateEndpoint(key))
await fsp.mkdir(dirname(funcPrefix), { recursive: true })
await fsp.symlink('./' + relative(dirname(funcPrefix), nitro.options.output.serverDir), funcPrefix + '.func', 'junction')
await writeFile(funcPrefix + '.prerender-config.json', JSON.stringify({
expiration: value.cache.static ? false : typeof value.cache.swr === 'number' ? value.cache.swr : 60,
allowQuery: key.includes('/**') ? ['url'] : undefined
}))
}
}
}
})
Expand Down Expand Up @@ -72,7 +85,6 @@ export const vercelEdge = defineNitroPreset({
})

function generateBuildConfig (nitro: Nitro) {
// const overrides = generateOverrides(nitro._prerenderedRoutes?.filter(r => r.fileName !== r.route) || [])
return defu(nitro.options.vercel?.config, <VercelBuildConfigV3> {
version: 3,
overrides: Object.fromEntries(
Expand Down Expand Up @@ -112,10 +124,20 @@ function generateBuildConfig (nitro: Nitro) {
{
handle: 'filesystem'
},
...Object.entries(nitro.options.routeRules)
.filter(([key, value]) => value.cache && (value.cache.swr || value.cache.static) && key.includes('/**'))
.map(([key]) => ({
src: key.replace(/^(.*)\/\*\*/, '(?<url>$1/.*)'),
dest: generateEndpoint(key) + '?url=$url'
})),
{
src: '/(.*)',
dest: '/__nitro'
}
]
})
}

function generateEndpoint (url: string) {
return url.includes('/**') ? '/__nitro-' + withoutLeadingSlash(url.replace(/\/\*\*.*/, '').replace(/[^a-z]/g, '-')) : url
}
16 changes: 14 additions & 2 deletions src/runtime/entries/vercel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import '#internal/nitro/virtual/polyfill'
import { toNodeListener } from 'h3'
import { toNodeListener, NodeListener } from 'h3'
import { parseQuery } from 'ufo'
import { nitroApp } from '../app'

export default toNodeListener(nitroApp.h3App)
const handler = toNodeListener(nitroApp.h3App)

export default <NodeListener> function (req, res) {
const query = req.headers['x-now-route-matches'] as string
if (query) {
const { url } = parseQuery(query)
if (url) {
req.url = url as string
}
}
return handler(req, res)
}
2 changes: 2 additions & 0 deletions test/presets/netlify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ describe('nitro:preset:netlify', async () => {
/rules/nested/* /base 302
/rules/redirect/obj https://nitro.unjs.io/ 301
/rules/redirect /base 302
/rules/swr-ttl/* /.netlify/builders/server 200
/rules/swr/* /.netlify/builders/server 200
/rules/static /.netlify/builders/server 200
/* /.netlify/functions/server 200"
`)
Expand Down
8 changes: 8 additions & 0 deletions test/presets/vercel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ describe('nitro:preset:vercel', async () => {
{
"handle": "filesystem",
},
{
"dest": "/__nitro--rules-swr?url=$url",
"src": "(?<url>/rules/swr/.*)",
},
{
"dest": "/__nitro--rules-swr-ttl?url=$url",
"src": "(?<url>/rules/swr-ttl/.*)",
},
{
"dest": "/__nitro",
"src": "/(.*)",
Expand Down
2 changes: 2 additions & 0 deletions test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export async function setupTest (preset) {
'/rules/cors': { cors: true, headers: { 'access-control-allowed-methods': 'GET' } },
'/rules/redirect': { redirect: '/base' },
'/rules/static': { static: true },
'/rules/swr/**': { swr: true },
'/rules/swr-ttl/**': { swr: 60 },
'/rules/redirect/obj': {
redirect: { to: 'https://nitro.unjs.io/', statusCode: 308 }
},
Expand Down