Skip to content

Commit

Permalink
feat: rename Edge Handlers to Edge Functions (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardoboucas committed Mar 24, 2022
1 parent 9b0376b commit a3906d4
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 49 deletions.
42 changes: 21 additions & 21 deletions src/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { getBootstrapImport } from './bootstrap.js'
import { DenoBridge, LifecycleHook } from './bridge.js'
import type { BundleAlternate } from './bundle_alternate.js'
import type { Declaration } from './declaration.js'
import { EdgeFunction } from './edge_function.js'
import { getESZIPBundler } from './eszip.js'
import { findHandlers } from './finder.js'
import { Handler } from './handler.js'
import { findFunctions } from './finder.js'
import { ImportMap, ImportMapFile } from './import_map.js'
import { generateManifest } from './manifest.js'
import { getFileHash } from './utils/sha256.js'

interface HandlerLine {
interface FunctionLine {
exportLine: string
importLine: string
}
Expand Down Expand Up @@ -56,7 +56,7 @@ const bundle = async (
// Creating an ImportMap instance with any import maps supplied by the user,
// if any.
const importMap = new ImportMap(importMaps)
const { handlers, preBundlePath } = await preBundle(sourceDirectories, distDirectory, `${buildID}-pre.js`)
const { functions, preBundlePath } = await preBundle(sourceDirectories, distDirectory, `${buildID}-pre.js`)
const bundleAlternates: BundleAlternate[] = ['js']
const bundleOps = [bundleJS({ buildID, deno, distDirectory, importMap, preBundlePath })]

Expand All @@ -71,7 +71,7 @@ const bundle = async (
bundleHash,
declarations,
distDirectory,
handlers,
functions,
})

await fs.unlink(preBundlePath)
Expand All @@ -80,7 +80,7 @@ const bundle = async (
await importMap.writeToFile(distImportMapPath)
}

return { handlers, manifest, preBundlePath }
return { functions, manifest, preBundlePath }
}

const bundleESZIP = async ({ buildID, deno, distDirectory, preBundlePath }: BundleAlternateOptions) => {
Expand All @@ -106,7 +106,7 @@ const bundleJS = async ({ buildID, deno, distDirectory, importMap, preBundlePath
const createFinalBundles = async (bundleOps: Promise<string>[], distDirectory: string, buildID: string) => {
const bundleExtensions = await Promise.all(bundleOps)

// We want to generate a fingerprint of the handlers and their dependencies,
// We want to generate a fingerprint of the functions and their dependencies,
// so let's compute a SHA256 hash of the bundle. That hash will be different
// for the various artifacts we produce, so we can just take the first one.
const bundleHash = await getFileHash(join(distDirectory, `${buildID}${bundleExtensions[0]}`))
Expand All @@ -122,21 +122,21 @@ const createFinalBundles = async (bundleOps: Promise<string>[], distDirectory: s
return bundleHash
}

const generateEntrypoint = (handlers: Handler[], distDirectory: string) => {
const lines = handlers.map((handler, index) => generateHandlerReference(handler, index, distDirectory))
const generateEntrypoint = (functions: EdgeFunction[], distDirectory: string) => {
const lines = functions.map((func, index) => generateFunctionReference(func, index, distDirectory))
const bootImport = getBootstrapImport()
const importLines = lines.map(({ importLine }) => importLine).join('\n')
const exportLines = lines.map(({ exportLine }) => exportLine).join(', ')
const exportDeclaration = `const handlers = {${exportLines}};`
const defaultExport = 'boot(handlers);'
const exportDeclaration = `const functions = {${exportLines}};`
const defaultExport = 'boot(functions);'

return [bootImport, importLines, exportDeclaration, defaultExport].join('\n\n')
}

const generateHandlerReference = (handler: Handler, index: number, targetDirectory: string): HandlerLine => {
const importName = `handler${index}`
const exportLine = `"${handler.name}": ${importName}`
const relativePath = relative(targetDirectory, handler.path)
const generateFunctionReference = (func: EdgeFunction, index: number, targetDirectory: string): FunctionLine => {
const importName = `func${index}`
const exportLine = `"${func.name}": ${importName}`
const relativePath = relative(targetDirectory, func.path)

return {
exportLine,
Expand All @@ -148,14 +148,14 @@ const preBundle = async (sourceDirectories: string[], distDirectory: string, pre
await del(distDirectory, { force: true })
await fs.mkdir(distDirectory, { recursive: true })

const handlers = await findHandlers(sourceDirectories)
const entrypoint = generateEntrypoint(handlers, distDirectory)
const functions = await findFunctions(sourceDirectories)
const entrypoint = generateEntrypoint(functions, distDirectory)
const preBundlePath = join(distDirectory, preBundleName)

await fs.writeFile(preBundlePath, entrypoint)

return {
handlers,
functions,
preBundlePath,
}
}
Expand All @@ -165,17 +165,17 @@ interface WriteManifestOptions {
bundleHash: string
declarations: Declaration[]
distDirectory: string
handlers: Handler[]
functions: EdgeFunction[]
}

const writeManifest = ({
bundleAlternates,
bundleHash,
declarations = [],
distDirectory,
handlers,
functions,
}: WriteManifestOptions) => {
const manifest = generateManifest({ bundleAlternates, bundleHash, declarations, handlers })
const manifest = generateManifest({ bundleAlternates, bundleHash, declarations, functions })
const manifestPath = join(distDirectory, 'manifest.json')

return fs.writeFile(manifestPath, JSON.stringify(manifest))
Expand Down
4 changes: 2 additions & 2 deletions src/declaration.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
interface DeclarationWithPath {
handler: string
function: string
path: string
}

interface DeclarationWithPattern {
handler: string
function: string
pattern: string
}

Expand Down
2 changes: 1 addition & 1 deletion src/handler.ts → src/edge_function.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface Handler {
export interface EdgeFunction {
name: string
path: string
}
30 changes: 15 additions & 15 deletions src/finder.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { promises as fs } from 'fs'
import { basename, extname, join } from 'path'

import { Handler } from './handler.js'
import { EdgeFunction } from './edge_function.js'
import { nonNullable } from './utils/non_nullable.js'

const ALLOWED_EXTENSIONS = new Set(['.js', '.ts'])

const findHandlerInDirectory = async (directory: string): Promise<Handler | undefined> => {
const findFunctionInDirectory = async (directory: string): Promise<EdgeFunction | undefined> => {
const name = basename(directory)
const candidatePaths = [`${name}.js`, `index.js`, `${name}.ts`, `index.ts`].map((filename) =>
join(directory, filename),
)

let handlerPath
let functionPath

for (const candidatePath of candidatePaths) {
try {
const stats = await fs.stat(candidatePath)

// eslint-disable-next-line max-depth
if (stats.isFile()) {
handlerPath = candidatePath
functionPath = candidatePath

break
}
Expand All @@ -29,21 +29,21 @@ const findHandlerInDirectory = async (directory: string): Promise<Handler | unde
}
}

if (handlerPath === undefined) {
if (functionPath === undefined) {
return
}

return {
name,
path: handlerPath,
path: functionPath,
}
}

const findHandlerInPath = async (path: string): Promise<Handler | undefined> => {
const findFunctionInPath = async (path: string): Promise<EdgeFunction | undefined> => {
const stats = await fs.stat(path)

if (stats.isDirectory()) {
return findHandlerInDirectory(path)
return findFunctionInDirectory(path)
}

const extension = extname(path)
Expand All @@ -53,7 +53,7 @@ const findHandlerInPath = async (path: string): Promise<Handler | undefined> =>
}
}

const findHandlersInDirectory = async (baseDirectory: string) => {
const findFunctionsInDirectory = async (baseDirectory: string) => {
let items: string[] = []

try {
Expand All @@ -62,15 +62,15 @@ const findHandlersInDirectory = async (baseDirectory: string) => {
// no-op
}

const handlers = await Promise.all(items.map((item) => findHandlerInPath(join(baseDirectory, item))))
const functions = await Promise.all(items.map((item) => findFunctionInPath(join(baseDirectory, item))))

return handlers.filter(nonNullable)
return functions.filter(nonNullable)
}

const findHandlers = async (directories: string[]) => {
const handlers = await Promise.all(directories.map(findHandlersInDirectory))
const findFunctions = async (directories: string[]) => {
const functions = await Promise.all(directories.map(findFunctionsInDirectory))

return handlers.flat()
return functions.flat()
}

export { findHandlers }
export { findFunctions }
16 changes: 8 additions & 8 deletions src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,41 @@ import globToRegExp from 'glob-to-regexp'

import type { BundleAlternate } from './bundle_alternate.js'
import type { Declaration } from './declaration.js'
import { Handler } from './handler.js'
import { EdgeFunction } from './edge_function.js'
import { nonNullable } from './utils/non_nullable.js'

interface GenerateManifestOptions {
bundleAlternates?: BundleAlternate[]
bundleHash: string
handlers: Handler[]
functions: EdgeFunction[]
declarations?: Declaration[]
}

const generateManifest = ({
bundleAlternates = [],
bundleHash,
declarations = [],
handlers,
functions,
}: GenerateManifestOptions) => {
const handlersWithRoutes = declarations.map((declaration) => {
const handler = handlers.find(({ name }) => declaration.handler === name)
const functionsWithRoutes = declarations.map((declaration) => {
const func = functions.find(({ name }) => declaration.function === name)

if (handler === undefined) {
if (func === undefined) {
return
}

const pattern = 'pattern' in declaration ? new RegExp(declaration.pattern) : globToRegExp(declaration.path)
const serializablePattern = pattern.source.replace(/\\\//g, '/')

return {
handler: handler.name,
function: func.name,
pattern: serializablePattern,
}
})
const manifest = {
bundle: bundleHash,
bundle_alternates: bundleAlternates,
handlers: handlersWithRoutes.filter(nonNullable),
functions: functionsWithRoutes.filter(nonNullable),
}

return manifest
Expand Down
4 changes: 2 additions & 2 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ const serve = async (
onBeforeDownload,
})
const distDirectory = await tmpName()
const { handlers, preBundlePath } = await preBundle(sourceDirectories, distDirectory, 'dev.js')
const { functions, preBundlePath } = await preBundle(sourceDirectories, distDirectory, 'dev.js')
const getManifest = (declarations: Declaration[]) =>
generateManifest({ bundleHash: preBundlePath, declarations, handlers })
generateManifest({ bundleHash: preBundlePath, declarations, functions })

// Wait for the binary to be downloaded if needed.
await deno.getBinaryPath()
Expand Down

0 comments on commit a3906d4

Please sign in to comment.