Skip to content

Commit

Permalink
feat: allow custom stderr and stdout in server (#564)
Browse files Browse the repository at this point in the history
* feat: allow custom `stderr` and `stdout` in server

* chore: add test

* chore: update test
  • Loading branch information
eduardoboucas committed Jan 16, 2024
1 parent af17202 commit 837027e
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 10 deletions.
39 changes: 30 additions & 9 deletions node/bridge.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { promises as fs } from 'fs'
import { promises as fs, type WriteStream } from 'fs'
import path from 'path'
import process from 'process'

Expand Down Expand Up @@ -35,9 +35,11 @@ interface ProcessRef {
}

interface RunOptions {
pipeOutput?: boolean
env?: NodeJS.ProcessEnv
extendEnv?: boolean
pipeOutput?: boolean
stderr?: WriteStream
stdout?: WriteStream
rejectOnExitCode?: boolean
}

Expand Down Expand Up @@ -159,14 +161,30 @@ class DenoBridge {
return this.currentDownload
}

private static runWithBinary(binaryPath: string, args: string[], options?: Options, pipeOutput?: boolean) {
private static runWithBinary(
binaryPath: string,
args: string[],
{
options,
pipeOutput,
stderr,
stdout,
}: { options?: Options; pipeOutput?: boolean; stderr?: WriteStream; stdout?: WriteStream },
) {
const runDeno = execa(binaryPath, args, options)

if (pipeOutput) {
runDeno.stdout?.pipe(process.stdout)
if (stderr) {
runDeno.stderr?.pipe(stderr)
} else if (pipeOutput) {
runDeno.stderr?.pipe(process.stderr)
}

if (stdout) {
runDeno.stdout?.pipe(stdout)
} else if (pipeOutput) {
runDeno.stdout?.pipe(process.stdout)
}

return runDeno
}

Expand Down Expand Up @@ -219,25 +237,28 @@ class DenoBridge {

// Runs the Deno CLI in the background and returns a reference to the child
// process, awaiting its execution.
async run(args: string[], { pipeOutput, env: inputEnv, extendEnv = true, rejectOnExitCode = true }: RunOptions = {}) {
async run(
args: string[],
{ env: inputEnv, extendEnv = true, rejectOnExitCode = true, stderr, stdout }: RunOptions = {},
) {
const { path: binaryPath } = await this.getBinaryPath()
const env = this.getEnvironmentVariables(inputEnv)
const options: Options = { env, extendEnv, reject: rejectOnExitCode }

return DenoBridge.runWithBinary(binaryPath, args, options, pipeOutput)
return DenoBridge.runWithBinary(binaryPath, args, { options, stderr, stdout })
}

// Runs the Deno CLI in the background, assigning a reference of the child
// process to a `ps` property in the `ref` argument, if one is supplied.
async runInBackground(
args: string[],
ref?: ProcessRef,
{ pipeOutput, env: inputEnv, extendEnv = true }: RunOptions = {},
{ env: inputEnv, extendEnv = true, stderr, stdout }: RunOptions = {},
) {
const { path: binaryPath } = await this.getBinaryPath()
const env = this.getEnvironmentVariables(inputEnv)
const options: Options = { env, extendEnv }
const ps = DenoBridge.runWithBinary(binaryPath, args, options, pipeOutput)
const ps = DenoBridge.runWithBinary(binaryPath, args, { options, stderr, stdout })

if (ref !== undefined) {
// eslint-disable-next-line no-param-reassign
Expand Down
12 changes: 12 additions & 0 deletions node/server/server.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { createWriteStream } from 'fs'
import { readFile } from 'fs/promises'
import { join } from 'path'
import process from 'process'

import getPort from 'get-port'
import fetch from 'node-fetch'
import tmp from 'tmp-promise'
import { v4 as uuidv4 } from 'uuid'
import { test, expect } from 'vitest'

Expand Down Expand Up @@ -107,6 +109,9 @@ test('Starts a server and serves requests for edge functions', async () => {
})

test('Serves edge functions in a monorepo setup', async () => {
const tmpFile = await tmp.file()
const stderr = createWriteStream(tmpFile.path)

const rootPath = join(fixturesDir, 'monorepo_npm_module')
const basePath = join(rootPath, 'packages', 'frontend')
const paths = {
Expand All @@ -121,6 +126,7 @@ test('Serves edge functions in a monorepo setup', async () => {
port,
rootPath,
servePath,
stderr,
})

const functions = [
Expand All @@ -141,6 +147,7 @@ test('Serves edge functions in a monorepo setup', async () => {
},
options,
)

expect(features).toEqual({ npmModules: true })
expect(success).toBe(true)
expect(functionsConfig).toEqual([{ path: '/func1' }])
Expand All @@ -161,8 +168,13 @@ test('Serves edge functions in a monorepo setup', async () => {
'X-NF-Request-ID': uuidv4(),
},
})

expect(response1.status).toBe(200)
expect(await response1.text()).toBe(
`<parent-1><child-1>JavaScript</child-1></parent-1>, <parent-2><child-2><grandchild-1>APIs<cwd>${process.cwd()}</cwd></grandchild-1></child-2></parent-2>, <parent-3><child-2><grandchild-1>Markup<cwd>${process.cwd()}</cwd></grandchild-1></child-2></parent-3>`,
)

expect(await readFile(tmpFile.path, 'utf8')).toContain('[func1] Something is on fire')

await tmpFile.cleanup()
})
25 changes: 24 additions & 1 deletion node/server/server.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { WriteStream } from 'fs'
import { readdir, unlink } from 'fs/promises'
import { join } from 'path'

Expand Down Expand Up @@ -28,6 +29,8 @@ interface PrepareServerOptions {
formatExportTypeError?: FormatFunction
formatImportError?: FormatFunction
logger: Logger
stderr?: WriteStream
stdout?: WriteStream
port: number
rootPath?: string
}
Expand Down Expand Up @@ -60,6 +63,8 @@ const prepareServer = ({
logger,
port,
rootPath,
stderr,
stdout,
}: PrepareServerOptions) => {
const processRef: ProcessRef = {}
const startServer = async (
Expand Down Expand Up @@ -134,9 +139,11 @@ const prepareServer = ({
// with variables from the user's system, since those will not be available
// in the production environment.
await deno.runInBackground(['run', ...denoFlags, ...extraDenoFlags, stage2Path, ...applicationFlags], processRef, {
pipeOutput: true,
env,
extendEnv: false,
pipeOutput: true,
stderr,
stdout,
})

let functionsConfig: FunctionConfig[] = []
Expand Down Expand Up @@ -190,6 +197,8 @@ interface ServeOptions {
port: number
rootPath?: string
servePath: string
stderr?: WriteStream
stdout?: WriteStream
userLogger?: LogFunction
systemLogger?: LogFunction
}
Expand Down Expand Up @@ -274,6 +283,18 @@ export const serve = async ({
*/
servePath,

/**
* Writable stream to receive the stderr of the server process. If not set,
* the stderr of the parent process will be used.
*/
stderr,

/**
* Writable stream to receive the stdout of the server process. If not set,
* the stdout of the parent process will be used.
*/
stdout,

/**
* Custom logging function to be used for user-facing messages. Defaults to
* `console.log`.
Expand Down Expand Up @@ -330,6 +351,8 @@ export const serve = async ({
formatExportTypeError,
formatImportError,
logger,
stderr,
stdout,
port,
rootPath,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ await Promise.resolve()
new HTMLRewriter()

export default async () => {
console.error('Something is on fire')

const text = [parent1('JavaScript'), parent2('APIs'), parent3('Markup')].join(', ')

return new Response(echo(text))
Expand Down

0 comments on commit 837027e

Please sign in to comment.