Skip to content

Commit

Permalink
feat: export metadata object in local stage 2 (#126)
Browse files Browse the repository at this point in the history
* feat: add `metadata` object to local stage 2

* chore: add comment

* chore: use file URL in test

* chore: adjust test for Node <14

* chore: run stage 2 in Deno
  • Loading branch information
eduardoboucas committed Sep 15, 2022
1 parent 99214c7 commit ed7503a
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 18 deletions.
42 changes: 24 additions & 18 deletions node/formats/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,24 +108,30 @@ const getLocalEntryPoint = (
}: GetLocalEntryPointOptions,
) => {
const bootImport = `import { boot } from "${getBootstrapURL()}";`
const declaration = `const functions = {};`
const imports = functions.map(
(func) => `
try {
const { default: func } = await import("${pathToFileURL(func.path)}");
if (typeof func === "function") {
functions["${func.name}"] = func;
} else {
console.log(${JSON.stringify(formatExportTypeError(func.name))});
const declaration = `const functions = {}; const metadata = {};`
const imports = functions.map((func) => {
const url = pathToFileURL(func.path)
const metadata = {
url,
}
} catch (error) {
console.log(${JSON.stringify(formatImportError(func.name))});
console.error(error);
}
`,
)
const bootCall = `boot(functions);`

return `
try {
const { default: func } = await import("${url}");
if (typeof func === "function") {
functions["${func.name}"] = func;
metadata["${func.name}"] = ${JSON.stringify(metadata)}
} else {
console.log(${JSON.stringify(formatExportTypeError(func.name))});
}
} catch (error) {
console.log(${JSON.stringify(formatImportError(func.name))});
console.error(error);
}
`
})
const bootCall = `boot(functions, metadata);`

return [bootImport, declaration, ...imports, bootCall].join('\n\n')
}
Expand All @@ -150,4 +156,4 @@ const getProductionEntryPoint = (functions: EdgeFunction[]) => {
return [bootImport, importLines, exportDeclaration, defaultExport].join('\n\n')
}

export { bundleJS as bundle, generateStage2, getBootstrapURL }
export { bundleJS as bundle, generateStage2, getBootstrapURL, getLocalEntryPoint }
67 changes: 67 additions & 0 deletions test/node/stage_2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { promises as fs } from 'fs'
import { join } from 'path'
import process from 'process'
import { pathToFileURL } from 'url'

import test from 'ava'
import del from 'del'
import { execa } from 'execa'
import semver from 'semver'
import tmp from 'tmp-promise'

import { getLocalEntryPoint } from '../../node/formats/javascript.js'

test('`getLocalEntryPoint` returns a valid stage 2 file for local development', async (t) => {
const { path: tmpDir } = await tmp.dir()

// This is a fake bootstrap that we'll create just for the purpose of logging
// the functions and the metadata that are sent to the `boot` function.
const printer = `
export const boot = async (functions, metadata) => {
const responses = {}
for (const name in functions) {
responses[name] = await functions[name]()
}
console.log(JSON.stringify({ responses, metadata }))
}
`
const printerPath = join(tmpDir, 'printer.mjs')

await fs.writeFile(printerPath, printer)
process.env.NETLIFY_EDGE_BOOTSTRAP = pathToFileURL(printerPath).toString()

const functions = [
{ name: 'func1', path: join(tmpDir, 'func1.mjs'), response: 'Hello from function 1' },
{ name: 'func2', path: join(tmpDir, 'func2.mjs'), response: 'Hello from function 2' },
]

for (const func of functions) {
const contents = `export default () => ${JSON.stringify(func.response)}`

await fs.writeFile(func.path, contents)
}

const stage2 = getLocalEntryPoint(
functions.map(({ name, path }) => ({ name, path })),
{},
)
const stage2Path = join(tmpDir, 'stage2.mjs')

await fs.writeFile(stage2Path, stage2)

const { stdout, stderr } = await execa('deno', ['run', '--allow-all', stage2Path])

t.is(stderr, '')

const { metadata, responses } = JSON.parse(stdout)

for (const func of functions) {
t.is(responses[func.name], func.response)
t.is(metadata[func.name].url, pathToFileURL(func.path).toString())
}

await del(tmpDir, { force: true })
delete process.env.NETLIFY_EDGE_BOOTSTRAP
})

0 comments on commit ed7503a

Please sign in to comment.