Skip to content

Commit

Permalink
Refactor cli serve command (#8958)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe committed Jul 24, 2023
1 parent fc07945 commit f24016a
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 265 deletions.
12 changes: 9 additions & 3 deletions packages/cli/src/commands/__tests__/serve.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,15 @@ jest.mock('fs', () => {
}
})

jest.mock('../serveHandler', () => {
jest.mock('../serveApiHandler', () => {
return {
...jest.requireActual('../serveHandler'),
...jest.requireActual('../serveApiHandler'),
apiServerHandler: jest.fn(),
}
})
jest.mock('../serveBothHandler', () => {
return {
...jest.requireActual('../serveBothHandler'),
bothServerHandler: jest.fn(),
}
})
Expand All @@ -54,7 +59,8 @@ import execa from 'execa'
import yargs from 'yargs'

import { builder } from '../serve'
import { apiServerHandler, bothServerHandler } from '../serveHandler'
import { apiServerHandler } from '../serveApiHandler'
import { bothServerHandler } from '../serveBothHandler'

describe('yarn rw serve', () => {
afterEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/deploy/flightcontrol.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'
import { getConfig } from '@redwoodjs/project-config'

import { getPaths } from '../../lib'
import { apiServerHandler } from '../serveHandler'
import { apiServerHandler } from '../serveApiHandler'

export const command = 'flightcontrol <side>'
export const alias = 'fc'
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/deploy/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'
import { getConfig } from '@redwoodjs/project-config'

import { getPaths } from '../../lib'
import { apiServerHandler } from '../serveHandler'
import { apiServerHandler } from '../serveApiHandler'

export const command = 'render <side>'
export const description = 'Build, Migrate, and Serve command for Render deploy'
Expand Down
156 changes: 19 additions & 137 deletions packages/cli/src/commands/serve.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import fs from 'fs'
import path from 'path'

import chalk from 'chalk'
import execa from 'execa'
import terminalLink from 'terminal-link'

import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'

import { getPaths, getConfig } from '../lib'
import c from '../lib/colors'

import { webServerHandler, webSsrServerHandler } from './serveWebHandler'

export const command = 'serve [side]'
export const description = 'Run server for api or web in production'

Expand Down Expand Up @@ -43,99 +43,16 @@ export const builder = async (yargs) => {

// Run the experimental server file, if it exists, with web side also
if (hasExperimentalServerFile()) {
console.log(
[
separator,
`🧪 ${chalk.green('Experimental Feature')} 🧪`,
separator,
'Using the experimental API server file at api/dist/server.js',
separator,
].join('\n')
const { bothExperimentalServerFileHandler } = await import(
'./serveBothHandler.js'
)

if (getConfig().experimental?.rsc?.enabled) {
console.warn('')
console.warn('⚠️ Skipping Fastify web server ⚠️')
console.warn('⚠️ Using new RSC server instead ⚠️')
console.warn('')
await execa(
'node',
[
'--conditions react-server',
'./node_modules/@redwoodjs/vite/dist/runRscFeServer.js',
],
{
cwd: getPaths().base,
stdio: 'inherit',
shell: true,
}
)
} else if (getConfig().experimental?.streamingSsr?.enabled) {
console.warn('')
console.warn('⚠️ Skipping Fastify web server ⚠️')
console.warn('⚠️ Using new Streaming FE server instead ⚠️')
console.warn('')
await execa('yarn', ['rw-serve-fe'], {
cwd: getPaths().web.base,
stdio: 'inherit',
shell: true,
})
} else {
await execa(
'yarn',
['node', path.join('dist', 'server.js'), '--enable-web'],
{
cwd: getPaths().api.base,
stdio: 'inherit',
shell: true,
}
)
}
return
}

if (getConfig().experimental?.rsc?.enabled) {
const { apiServerHandler } = await import('./serveHandler.js')
// TODO (RSC) Allow specifying port, socket and apiRootPath
const apiPromise = apiServerHandler({
...argv,
port: 8911,
apiRootPath: '/',
})

// TODO (RSC) More gracefully handle Ctrl-C
const fePromise = execa(
'node',
[
'--conditions react-server',
'./node_modules/@redwoodjs/vite/dist/runRscFeServer.js',
],
{
cwd: getPaths().base,
stdio: 'inherit',
shell: true,
}
)

await Promise.all([apiPromise, fePromise])
await bothExperimentalServerFileHandler()
} else if (getConfig().experimental?.rsc?.enabled) {
const { bothRscServerHandler } = await import('./serveBothHandler.js')
await bothRscServerHandler(argv)
} else if (getConfig().experimental?.streamingSsr?.enabled) {
const { apiServerHandler } = await import('./serveHandler.js')
// TODO (STREAMING) Allow specifying port, socket and apiRootPath
const apiPromise = apiServerHandler({
...argv,
port: 8911,
apiRootPath: '/',
})

// TODO (STREAMING) More gracefully handle Ctrl-C
// Right now you get a big red error box when you kill the process
const fePromise = execa('yarn', ['rw-serve-fe'], {
cwd: getPaths().web.base,
stdio: 'inherit',
shell: true,
})

await Promise.all([apiPromise, fePromise])
const { bothSsrServerHandler } = await import('./serveBothHandler.js')
await bothSsrServerHandler(argv)
} else {
// Wanted to use the new web-server package here, but can't because
// of backwards compatibility reasons. With `bothServerHandler` both
Expand All @@ -144,7 +61,7 @@ export const builder = async (yargs) => {
// them on the same port, and so we lose backwards compatibility.
// TODO: Use @redwoodjs/web-server when we're ok with breaking
// backwards compatibility.
const { bothServerHandler } = await import('./serveHandler.js')
const { bothServerHandler } = await import('./serveBothHandler.js')
await bothServerHandler(argv)
}
},
Expand Down Expand Up @@ -179,25 +96,14 @@ export const builder = async (yargs) => {

// Run the experimental server file, if it exists, api side only
if (hasExperimentalServerFile()) {
console.log(
[
separator,
`🧪 ${chalk.green('Experimental Feature')} 🧪`,
separator,
'Using the experimental API server file at api/dist/server.js',
separator,
].join('\n')
const { apiExperimentalServerFileHandler } = await import(
'./serveApiHandler.js'
)
await execa('yarn', ['node', path.join('dist', 'server.js')], {
cwd: getPaths().api.base,
stdio: 'inherit',
shell: true,
})
return
await apiExperimentalServerFileHandler()
} else {
const { apiServerHandler } = await import('./serveApiHandler.js')
await apiServerHandler(argv)
}

const { apiServerHandler } = await import('./serveHandler.js')
await apiServerHandler(argv)
},
})
.command({
Expand Down Expand Up @@ -227,29 +133,9 @@ export const builder = async (yargs) => {
})

if (getConfig().experimental?.streamingSsr?.enabled) {
await execa('yarn', ['rw-serve-fe'], {
cwd: getPaths().web.base,
stdio: 'inherit',
shell: true,
})
await webSsrServerHandler()
} else {
await execa(
'yarn',
[
'rw-web-server',
'--port',
argv.port,
'--socket',
argv.socket,
'--api-host',
argv.apiHost,
],
{
cwd: getPaths().base,
stdio: 'inherit',
shell: true,
}
)
await webServerHandler(argv)
}
},
})
Expand Down Expand Up @@ -312,10 +198,6 @@ export const builder = async (yargs) => {
)
}

const separator = chalk.hex('#ff845e')(
'------------------------------------------------------------------'
)

// We'll clean this up later, but for now note that this function is
// duplicated between this package and @redwoodjs/fastify
// to avoid importing @redwoodjs/fastify when the CLI starts.
Expand Down
89 changes: 89 additions & 0 deletions packages/cli/src/commands/serveApiHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import path from 'path'

import chalk from 'chalk'
import execa from 'execa'

import { createFastifyInstance, redwoodFastifyAPI } from '@redwoodjs/fastify'
import { getPaths } from '@redwoodjs/project-config'

export const apiExperimentalServerFileHandler = async () => {
logExperimentalHeader()

await execa('yarn', ['node', path.join('dist', 'server.js')], {
cwd: getPaths().api.base,
stdio: 'inherit',
shell: true,
})
return
}

export const apiServerHandler = async (options) => {
const { port, socket, apiRootPath } = options
const tsApiServer = Date.now()

console.log(chalk.dim.italic('Starting API Server...'))

const fastify = createFastifyInstance()

process.on('exit', () => {
fastify?.close()
})

await fastify.register(redwoodFastifyAPI, {
redwood: {
...options,
},
})

let listenOptions

if (socket) {
listenOptions = { path: socket }
} else {
listenOptions = {
port,
host: process.env.NODE_ENV === 'production' ? '0.0.0.0' : '::',
}
}

fastify.listen(listenOptions)

fastify.ready(() => {
fastify.log.trace(
{ custom: { ...fastify.initialConfig } },
'Fastify server configuration'
)
fastify.log.trace(`Registered plugins \n${fastify.printPlugins()}`)
console.log(chalk.italic.dim('Took ' + (Date.now() - tsApiServer) + ' ms'))

const on = socket
? socket
: chalk.magenta(`http://localhost:${port}${apiRootPath}`)

console.log(`API listening on ${on}`)
const graphqlEnd = chalk.magenta(`${apiRootPath}graphql`)
console.log(`GraphQL endpoint at ${graphqlEnd}`)

sendProcessReady()
})
}

function sendProcessReady() {
return process.send && process.send('ready')
}

const separator = chalk.hex('#ff845e')(
'------------------------------------------------------------------'
)

function logExperimentalHeader() {
console.log(
[
separator,
`🧪 ${chalk.green('Experimental Feature')} 🧪`,
separator,
'Using the experimental API server file at api/dist/server.js',
separator,
].join('\n')
)
}
Loading

0 comments on commit f24016a

Please sign in to comment.