Skip to content

Commit

Permalink
fix(deploy): handle server file (#10061)
Browse files Browse the repository at this point in the history
At first this PR was similar to
#10055 but for Flightcontrol.
But in the process of testing that and updating deploy target CI, I
noticed a few other things were off:

- coherence logic for the server file was flipped. fixed here
- in general, a few duplicate ways of checking for the server file.
tried to dedupe them the best i could without making massive changes
- stylistic change to render
- the flightcontrol setup wasn't handing corepack

Test as much as I could locally. Going to get this one into next so I
can test in deploy target CI.
  • Loading branch information
jtoar committed Feb 29, 2024
1 parent f8bc3f9 commit 00b1920
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 64 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
"peacock.color": "#b85833",
"cSpell.words": [
"autoplay",
"corepack",
"execa",
"Fastify",
"Flightcontrol",
"graphiql",
"opentelemetry",
"pino",
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

## Unreleased

- fix(deploy): handle server file (#10061)

This fixes the CLI commands for Coherence and Flightcontrol. For Coherence, it fixes a bug introduced in the last patch where the logic for detecting the server file in the setup command (`yarn rw setup deploy coherence`) was flipped. For Flightcontrol, it updates the setup command (`yarn rw setup deploy flightcontrol`) so that it handles Corepack and updates the corresponding deploy command (`yarn rw deploy flightcontrol`) so that it detects the server file similar to the Coherence fix.

- chore(docs): Add link to SuperTokens auth (#10067)

Add a missing link to the SuperTokens auth page in the docs. @danbtl

- fix(coherence): update setup command to detect server file
Expand Down
2 changes: 1 addition & 1 deletion __fixtures__/test-project/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@types/react-dom": "^18.2.19",
"autoprefixer": "^10.4.17",
"postcss": "^8.4.35",
"postcss-loader": "^8.1.0",
"postcss-loader": "^8.1.1",
"prettier-plugin-tailwindcss": "0.4.1",
"tailwindcss": "^3.4.1"
}
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/commands/__tests__/dev.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ vi.mock('@redwoodjs/project-config', async () => {
getPaths: () => {
return {
api: {
base: '/mocked/project/api',
src: '/mocked/project/api/src',
dist: '/mocked/project/api/dist',
},
web: {
base: '/mocked/project/web',
dist: '/mocked/project/web/dist',
},
generated: {
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/commands/__tests__/serve.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ vi.mock('@redwoodjs/project-config', async (importOriginal) => {
return {
api: {
base: '/mocked/project/api',
src: '/mocked/project/api/src',
dist: '/mocked/project/api/dist',
},
web: {
Expand All @@ -39,8 +40,8 @@ vi.mock('fs-extra', async (importOriginal) => {
default: {
...originalFsExtra,
existsSync: (p) => {
// Don't detect the experimental server file, can't use path.sep here so the replaceAll is used
if (p.replaceAll('\\', '/') === '/mocked/project/api/dist/server.js') {
// Don't detect the server file, can't use path.sep here so the replaceAll is used
if (p.replaceAll('\\', '/') === '/mocked/project/api/src/server.ts') {
return false
}
return true
Expand Down
63 changes: 35 additions & 28 deletions packages/cli/src/commands/deploy/flightcontrol.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import path from 'path'

import execa from 'execa'
import fs from 'fs-extra'
import terminalLink from 'terminal-link'

import { handler as apiServerHandler } from '@redwoodjs/api-server/dist/apiCLIConfigHandler'
import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'
import { getConfig } from '@redwoodjs/project-config'

import { getPaths } from '../../lib'
import { getPaths } from '@redwoodjs/project-config'

export const command = 'flightcontrol <side>'
export const alias = 'fc'
export const description =
'Build, Migrate, and Serve commands for Flightcontrol deploy'

export const builder = (yargs) => {
yargs
.positional('side', {
choices: ['api', 'web'],
description: 'select side to build',
description: 'Side to deploy',
type: 'string',
})
.option('prisma', {
Expand All @@ -31,7 +30,7 @@ export const builder = (yargs) => {
default: false,
})
.option('data-migrate', {
description: 'Migrate the data in your database',
description: 'Apply data migrations',
type: 'boolean',
default: true,
alias: 'dm',
Expand All @@ -55,45 +54,53 @@ export const handler = async ({ side, serve, prisma, dm: dataMigrate }) => {
const rwjsPaths = getPaths()

const execaConfig = {
cwd: rwjsPaths.base,
shell: true,
stdio: 'inherit',
cwd: rwjsPaths.base,
extendEnv: true,
cleanup: true,
}

async function runApiCommands() {
if (serve) {
console.log('\nStarting api...')
await apiServerHandler({
port: getConfig().api?.port || 8911,
apiRootPath: '/',
})
} else {
console.log('\nBuilding api...')
execa.sync('yarn rw build api', execaConfig)
if (!serve) {
console.log('Building api...')
execa.commandSync('yarn rw build api --verbose', execaConfig)

prisma &&
execa.sync(
path.join(rwjsPaths.base, 'node_modules/.bin/prisma'),
['migrate', 'deploy', '--schema', `"${rwjsPaths.api.dbSchema}"`],
if (prisma) {
console.log('Running database migrations...')
execa.commandSync(
`node_modules/.bin/prisma migrate deploy --schema "${rwjsPaths.api.dbSchema}"`,
execaConfig
)
dataMigrate && execa.sync('yarn rw dataMigrate up', execaConfig)
}

if (dataMigrate) {
console.log('Running data migrations...')
execa.commandSync('yarn rw dataMigrate up', execaConfig)
}

return
}

const serverFilePath = path.join(rwjsPaths.api.dist, 'server.js')
const hasServerFile = fs.pathExistsSync(serverFilePath)

if (hasServerFile) {
execa(`yarn node ${serverFilePath}`, execaConfig)
} else {
const { handler } = await import(
'@redwoodjs/api-server/dist/apiCLIConfigHandler.js'
)
handler()
}
}

async function runWebCommands() {
execa.sync('yarn rw build web', execaConfig)
console.log('Building web...')
execa.commandSync('yarn rw build web --verbose', execaConfig)
}

if (side === 'api') {
runApiCommands()
} else if (side === 'web') {
console.log('\nBuilding web...')
runWebCommands()
} else {
console.log('Error with arguments provided')
// you broke something, which should be caught by Yargs
}
}
10 changes: 3 additions & 7 deletions packages/cli/src/commands/devHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@ import fs from 'fs-extra'

import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'
import { shutdownPort } from '@redwoodjs/internal/dist/dev'
import {
getConfig,
getConfigPath,
resolveFile,
} from '@redwoodjs/project-config'
import { getConfig, getConfigPath } from '@redwoodjs/project-config'
import { errorTelemetry } from '@redwoodjs/telemetry'

import { getPaths } from '../lib'
import c from '../lib/colors'
import { exitWithError } from '../lib/exit'
import { generatePrismaClient } from '../lib/generatePrismaClient'
import { getFreePort } from '../lib/ports'
import { serverFileExists } from '../lib/project'

const defaultApiDebugPort = 18911

Expand All @@ -36,8 +33,7 @@ export const handler = async ({

const rwjsPaths = getPaths()

// Check if experimental server file exists
const serverFile = resolveFile(`${rwjsPaths.api.dist}/server`)
const serverFile = serverFileExists()

// Starting values of ports from config (redwood.toml)
let apiPreferredPort = parseInt(getConfig().api.port)
Expand Down
13 changes: 2 additions & 11 deletions packages/cli/src/commands/experimental/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import fs from 'fs-extra'
import terminalLink from 'terminal-link'

import { getPaths } from '../../lib'
import { isTypeScriptProject } from '../../lib/project'
import { isTypeScriptProject, serverFileExists } from '../../lib/project'

const link = (topicId, isTerminal = false) => {
const communityLink = `https://community.redwoodjs.com/t/${topicId}`
Expand Down Expand Up @@ -44,17 +44,8 @@ export const printTaskEpilogue = (command, description, topicId) => {
)
}

export const serverFileExists = () => {
const serverFilePath = path.join(
getPaths().api.src,
`server.${isTypeScriptProject() ? 'ts' : 'js'}`
)

return fs.existsSync(serverFilePath)
}

export const isServerFileSetup = () => {
if (!serverFileExists) {
if (!serverFileExists()) {
throw new Error(
'RedwoodJS Realtime requires a serverful environment. Please run `yarn rw exp setup-server-file` first.'
)
Expand Down
10 changes: 3 additions & 7 deletions packages/cli/src/commands/serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import * as webServerCLIConfig from '@redwoodjs/web-server'

import { getPaths } from '../lib'
import c from '../lib/colors'
import { serverFileExists } from '../lib/project.js'

export const command = 'serve [side]'
export const description =
'Start a server for serving both the api and web sides'

function hasServerFile() {
const serverFilePath = path.join(getPaths().api.dist, 'server.js')
return fs.existsSync(serverFilePath)
}

export const builder = async (yargs) => {
yargs
.command({
Expand All @@ -35,7 +31,7 @@ export const builder = async (yargs) => {
})

// Run the server file, if it exists, with web side also
if (hasServerFile()) {
if (serverFileExists()) {
const { bothServerFileHandler } = await import('./serveHandler.js')
await bothServerFileHandler(argv)
} else {
Expand All @@ -57,7 +53,7 @@ export const builder = async (yargs) => {
})

// Run the server file, if it exists, api side only
if (hasServerFile()) {
if (serverFileExists()) {
const { apiServerFileHandler } = await import('./serveHandler.js')
await apiServerFileHandler(argv)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { errorTelemetry } from '@redwoodjs/telemetry'

import { printSetupNotes } from '../../../../lib'
import { serverFileExists } from '../../../../lib/project'
import { addFilesTask } from '../helpers'

const redwoodProjectPaths = getPaths()
Expand Down Expand Up @@ -106,11 +107,8 @@ async function getCoherenceConfigFileContent() {
db = 'postgres'
}

const hasServerFile = fs.pathExistsSync(
path.join(getPaths().api.dist, 'server.js')
)
const apiProdCommand = ['yarn', 'rw', 'build', 'api', '&&']
if (!hasServerFile) {
if (serverFileExists()) {
apiProdCommand.push(
'yarn',
'node',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const flightcontrolConfig = {
buildType: 'nixpacks',
cpu: 0.5,
memory: 1,
installCommand: 'corepack enable && yarn install',
buildCommand: 'yarn rw deploy flightcontrol api',
startCommand: 'yarn rw deploy flightcontrol api --serve',
port: 8911,
Expand All @@ -32,6 +33,7 @@ export const flightcontrolConfig = {
type: 'static',
buildType: 'nixpacks',
singlePageApp: true,
installCommand: 'corepack enable && yarn install',
buildCommand: 'yarn rw deploy flightcontrol web',
outputDirectory: 'web/dist',
envVariables: {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/setup/deploy/templates/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ services:
plan: free
env: node
region: oregon
buildCommand: corepack enable && yarn && yarn rw build api
buildCommand: corepack enable && yarn install && yarn rw build api
startCommand: yarn rw deploy render api
envVars:
Expand Down
4 changes: 1 addition & 3 deletions packages/cli/src/commands/setup/realtime/realtimeHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import { errorTelemetry } from '@redwoodjs/telemetry'

import { getPaths, transformTSToJS, writeFile } from '../../../lib'
import c from '../../../lib/colors'
import { isTypeScriptProject } from '../../../lib/project'
// Move this check out of experimental when server file is moved as well
import { serverFileExists } from '../../experimental/util'
import { isTypeScriptProject, serverFileExists } from '../../../lib/project'
import { setupServerFileTasks } from '../server-file/serverFileHandler'

const { version } = JSON.parse(
Expand Down
9 changes: 9 additions & 0 deletions packages/cli/src/lib/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ export const sides = () => {
}
return sides
}

export const serverFileExists = () => {
const serverFilePath = path.join(
getPaths().api.src,
`server.${isTypeScriptProject() ? 'ts' : 'js'}`
)

return fs.existsSync(serverFilePath)
}

0 comments on commit 00b1920

Please sign in to comment.