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: add support for post-cache routes #165

Merged
merged 3 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions node/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ test('Ignores function paths from the in-source `config` function if the feature
})
const generatedFiles = await fs.readdir(tmpDir.path)

expect(result.functions.length).toBe(4)
expect(result.functions.length).toBe(6)
expect(generatedFiles.length).toBe(2)

const manifestFile = await fs.readFile(resolve(tmpDir.path, 'manifest.json'), 'utf8')
Expand Down Expand Up @@ -185,22 +185,26 @@ test('Loads function paths from the in-source `config` function', async () => {
})
const generatedFiles = await fs.readdir(tmpDir.path)

expect(result.functions.length).toBe(4)
expect(result.functions.length).toBe(6)
expect(generatedFiles.length).toBe(2)

const manifestFile = await fs.readFile(resolve(tmpDir.path, 'manifest.json'), 'utf8')
const manifest = JSON.parse(manifestFile)
const { bundles, routes } = manifest
const { bundles, routes, post_cache_routes: postCacheRoutes } = manifest

expect(bundles.length).toBe(1)
expect(bundles[0].format).toBe('eszip2')
expect(generatedFiles.includes(bundles[0].asset)).toBe(true)

expect(routes.length).toBe(4)
expect(routes.length).toBe(5)
expect(routes[0]).toEqual({ function: 'framework-func2', pattern: '^/framework-func2/?$' })
expect(routes[1]).toEqual({ function: 'user-func2', pattern: '^/user-func2/?$' })
expect(routes[2]).toEqual({ function: 'framework-func1', pattern: '^/framework-func1/?$' })
expect(routes[3]).toEqual({ function: 'user-func1', pattern: '^/user-func1/?$' })
expect(routes[4]).toEqual({ function: 'user-func3', pattern: '^/user-func3/?$' })

expect(postCacheRoutes.length).toBe(1)
expect(postCacheRoutes[0]).toEqual({ function: 'user-func4', pattern: '^/user-func4/?$' })

await fs.rmdir(tmpDir.path, { recursive: true })
})
7 changes: 7 additions & 0 deletions node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ enum ConfigExitCode {
SerializationError,
}

// eslint-disable-next-line no-shadow
export const enum Mode {
BeforeCache = 'before_cache',
AfterCache = 'after_cache',
}

export interface FunctionConfig {
mode?: Mode
path?: string
}

Expand Down
7 changes: 4 additions & 3 deletions node/declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { FunctionConfig } from './config.js'

interface BaseDeclaration {
function: string
mode?: string
name?: string
}

Expand Down Expand Up @@ -31,7 +32,7 @@ export const getDeclarationsFromConfig = (
if (path) {
functionsVisited.add(declaration.function)

declarations.push({ function: declaration.function, path })
declarations.push({ ...declaration, path })
} else {
declarations.push(declaration)
}
Expand All @@ -40,10 +41,10 @@ export const getDeclarationsFromConfig = (
// Finally, we must create declarations for functions that are not declared
// in the TOML at all.
for (const name in functionsConfig) {
const { path } = functionsConfig[name]
const { path, ...config } = functionsConfig[name]

if (!functionsVisited.has(name) && path) {
declarations.push({ function: name, path })
declarations.push({ ...config, function: name, path })
}
}

Expand Down
39 changes: 39 additions & 0 deletions node/manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,42 @@ test('Generates a manifest without bundles', () => {
expect(manifest.routes).toEqual(expectedRoutes)
expect(manifest.bundler_version).toBe(env.npm_package_version as string)
})

test('Generates a manifest with pre and post-cache routes', () => {
const bundle1 = {
extension: '.ext1',
format: 'format1',
hash: '123456',
}
const bundle2 = {
extension: '.ext2',
format: 'format2',
hash: '654321',
}
const functions = [
{ name: 'func-1', path: '/path/to/func-1.ts' },
{ name: 'func-2', path: '/path/to/func-2.ts' },
{ name: 'func-3', path: '/path/to/func-3.ts' },
]
const declarations = [
{ function: 'func-1', path: '/f1' },
{ function: 'func-2', mode: 'not_a_supported_mode', path: '/f2' },
{ function: 'func-3', mode: 'after_cache', path: '/f3' },
]
const manifest = generateManifest({ bundles: [bundle1, bundle2], declarations, functions })

const expectedBundles = [
{ asset: bundle1.hash + bundle1.extension, format: bundle1.format },
{ asset: bundle2.hash + bundle2.extension, format: bundle2.format },
]
const expectedPreCacheRoutes = [
{ function: 'func-1', name: undefined, pattern: '^/f1/?$' },
{ function: 'func-2', name: undefined, pattern: '^/f2/?$' },
]
const expectedPostCacheRoutes = [{ function: 'func-3', name: undefined, pattern: '^/f3/?$' }]

expect(manifest.bundles).toEqual(expectedBundles)
expect(manifest.routes).toEqual(expectedPreCacheRoutes)
expect(manifest.post_cache_routes).toEqual(expectedPostCacheRoutes)
expect(manifest.bundler_version).toBe(env.npm_package_version as string)
})
28 changes: 23 additions & 5 deletions node/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { join } from 'path'
import globToRegExp from 'glob-to-regexp'

import type { Bundle } from './bundle.js'
import { Mode } from './config.js'
import type { Declaration } from './declaration.js'
import { EdgeFunction } from './edge_function.js'
import { getPackageVersion } from './package_json.js'
Expand All @@ -15,15 +16,26 @@ interface GenerateManifestOptions {
declarations?: Declaration[]
}

/* eslint-disable camelcase */
interface Manifest {
// eslint-disable-next-line camelcase
bundler_version: string
bundles: { asset: string; format: string }[]
routes: { function: string; name?: string; pattern: string }[]
post_cache_routes: { function: string; name?: string; pattern: string }[]
}
/* eslint-enable camelcase */

interface Route {
function: string
name?: string
pattern: string
}

const generateManifest = ({ bundles = [], declarations = [], functions }: GenerateManifestOptions) => {
const routes = declarations.map((declaration) => {
const preCacheRoutes: Route[] = []
const postCacheRoutes: Route[] = []

declarations.forEach((declaration) => {
const func = functions.find(({ name }) => declaration.function === name)

if (func === undefined) {
Expand All @@ -32,20 +44,26 @@ const generateManifest = ({ bundles = [], declarations = [], functions }: Genera

const pattern = getRegularExpression(declaration)
const serializablePattern = pattern.source.replace(/\\\//g, '/')

return {
const route = {
function: func.name,
name: declaration.name,
pattern: serializablePattern,
}

if (declaration.mode === Mode.AfterCache) {
postCacheRoutes.push(route)
} else {
preCacheRoutes.push(route)
}
})
const manifestBundles = bundles.map(({ extension, format, hash }) => ({
asset: hash + extension,
format,
}))
const manifest: Manifest = {
bundles: manifestBundles,
routes: routes.filter(nonNullable),
routes: preCacheRoutes.filter(nonNullable),
post_cache_routes: postCacheRoutes.filter(nonNullable),
bundler_version: getPackageVersion(),
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default async () => new Response('Hello from user function 3')

export const config = () => ({
mode: 'not_a_supported_mode',
path: '/user-func3',
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default async () => new Response('Hello from user function 4. I should run after the cache!')

export const config = () => ({
mode: 'after_cache',
path: '/user-func4',
})