From b759ad1aa73e2d9277f8bd88b5522a396dad12c0 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Fri, 19 Jan 2024 08:52:03 +0100 Subject: [PATCH] Improve how the api-server watch command works (#9841) --- packages/api-server/src/watch.ts | 7 +- .../cli/src/commands/__tests__/dev.test.js | 13 ++-- packages/cli/src/commands/devHandler.js | 74 +++++++++++++------ 3 files changed, 62 insertions(+), 32 deletions(-) diff --git a/packages/api-server/src/watch.ts b/packages/api-server/src/watch.ts index 29fd4aedf5ed..a4aa51a4fe12 100644 --- a/packages/api-server/src/watch.ts +++ b/packages/api-server/src/watch.ts @@ -32,6 +32,7 @@ const argv = yargs(hideBin(process.argv)) description: 'Debugging port', type: 'number', }) + // `port` is not used when server-file is used .option('port', { alias: 'p', description: 'Port', @@ -133,15 +134,13 @@ const buildAndRestart = async ({ // Check if experimental server file exists const serverFile = resolveFile(`${rwjsPaths.api.dist}/server`) if (serverFile) { - const separator = chalk.hex('#ff845e')( - '------------------------------------------------------------------' - ) + const separator = chalk.hex('#ff845e')('-'.repeat(79)) console.log( [ separator, `🧪 ${chalk.green('Experimental Feature')} 🧪`, separator, - 'Using the experimental API server file at api/dist/server.js', + 'Using the experimental API server file at api/dist/server.js (in watch mode)', separator, ].join('\n') ) diff --git a/packages/cli/src/commands/__tests__/dev.test.js b/packages/cli/src/commands/__tests__/dev.test.js index 7de47c38266a..595e453b7644 100644 --- a/packages/cli/src/commands/__tests__/dev.test.js +++ b/packages/cli/src/commands/__tests__/dev.test.js @@ -25,9 +25,12 @@ jest.mock('@redwoodjs/internal/dist/dev', () => { }) jest.mock('@redwoodjs/project-config', () => { + const actualProjectConfig = jest.requireActual('@redwoodjs/project-config') + return { getConfig: jest.fn(), getConfigPath: () => '/mocked/project/redwood.toml', + resolveFile: actualProjectConfig.resolveFile, getPaths: () => { return { api: { @@ -104,8 +107,8 @@ describe('yarn rw dev', () => { 'yarn cross-env NODE_ENV=development rw-vite-dev' ) - expect(apiCommand.command).toMatchInlineSnapshot( - `"yarn cross-env NODE_ENV=development NODE_OPTIONS="--enable-source-maps" yarn nodemon --quiet --watch "/mocked/project/redwood.toml" --exec "yarn rw-api-server-watch --port 8911 --debug-port 18911 | rw-log-formatter""` + expect(apiCommand.command.replace(/\s+/g, ' ')).toEqual( + 'yarn cross-env NODE_ENV=development NODE_OPTIONS="--enable-source-maps" yarn nodemon --quiet --watch "/mocked/project/redwood.toml" --exec "yarn rw-api-server-watch --port 8911 --debug-port 18911 | rw-log-formatter"' ) expect(generateCommand.command).toEqual('yarn rw-gen-watch') @@ -143,8 +146,8 @@ describe('yarn rw dev', () => { 'yarn cross-env NODE_ENV=development rw-dev-fe' ) - expect(apiCommand.command).toMatchInlineSnapshot( - `"yarn cross-env NODE_ENV=development NODE_OPTIONS="--enable-source-maps" yarn nodemon --quiet --watch "/mocked/project/redwood.toml" --exec "yarn rw-api-server-watch --port 8911 --debug-port 18911 | rw-log-formatter""` + expect(apiCommand.command.replace(/\s+/g, ' ')).toEqual( + 'yarn cross-env NODE_ENV=development NODE_OPTIONS="--enable-source-maps" yarn nodemon --quiet --watch "/mocked/project/redwood.toml" --exec "yarn rw-api-server-watch --port 8911 --debug-port 18911 | rw-log-formatter"' ) expect(generateCommand.command).toEqual('yarn rw-gen-watch') @@ -175,7 +178,7 @@ describe('yarn rw dev', () => { const apiCommand = find(concurrentlyArgs, { name: 'api' }) - expect(apiCommand.command).toContain( + expect(apiCommand.command.replace(/\s+/g, ' ')).toContain( 'yarn rw-api-server-watch --port 8911 --debug-port 90909090' ) }) diff --git a/packages/cli/src/commands/devHandler.js b/packages/cli/src/commands/devHandler.js index e4ed83085460..16ab1e2b71cd 100644 --- a/packages/cli/src/commands/devHandler.js +++ b/packages/cli/src/commands/devHandler.js @@ -5,7 +5,11 @@ import fs from 'fs-extra' import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers' import { shutdownPort } from '@redwoodjs/internal/dist/dev' -import { getConfig, getConfigPath } from '@redwoodjs/project-config' +import { + getConfig, + getConfigPath, + resolveFile, +} from '@redwoodjs/project-config' import { errorTelemetry } from '@redwoodjs/telemetry' import { getPaths } from '../lib' @@ -32,6 +36,9 @@ export const handler = async ({ const rwjsPaths = getPaths() + // Check if experimental server file exists + const serverFile = resolveFile(`${rwjsPaths.api.dist}/server`) + // Starting values of ports from config (redwood.toml) let apiPreferredPort = parseInt(getConfig().api.port) let webPreferredPort = parseInt(getConfig().web.port) @@ -42,8 +49,10 @@ export const handler = async ({ let webAvailablePort = webPreferredPort let webPortChangeNeeded = false - // Check api port - if (side.includes('api')) { + // Check api port, unless there's a serverFile. If there is a serverFile, we + // don't know what port will end up being used in the end. It's up to the + // author of the server file to decide and handle that + if (side.includes('api') && !serverFile) { apiAvailablePort = await getFreePort(apiPreferredPort) if (apiAvailablePort === -1) { exitWithError(undefined, { @@ -76,17 +85,23 @@ export const handler = async ({ // Check for port conflict and exit with message if found if (apiPortChangeNeeded || webPortChangeNeeded) { - let message = `The currently configured ports for the development server are unavailable. Suggested changes to your ports, which can be changed in redwood.toml, are:\n` - message += apiPortChangeNeeded - ? ` - API to use port ${apiAvailablePort} instead of your currently configured ${apiPreferredPort}\n` - : `` - message += webPortChangeNeeded - ? ` - Web to use port ${webAvailablePort} instead of your currently configured ${webPreferredPort}\n` - : `` - message += `\nCannot run the development server until your configured ports are changed or become available.` - exitWithError(undefined, { - message, - }) + const message = [ + 'The currently configured ports for the development server are', + 'unavailable. Suggested changes to your ports, which can be changed in', + 'redwood.toml, are:\n', + apiPortChangeNeeded && ` - API to use port ${apiAvailablePort} instead`, + apiPortChangeNeeded && 'of your currently configured', + apiPortChangeNeeded && `${apiPreferredPort}\n`, + webPortChangeNeeded && ` - Web to use port ${webAvailablePort} instead`, + webPortChangeNeeded && 'of your currently configured', + webPortChangeNeeded && `${webPreferredPort}\n`, + '\nCannot run the development server until your configured ports are', + 'changed or become available.', + ] + .filter(Boolean) + .join(' ') + + exitWithError(undefined, { message }) } if (side.includes('api')) { @@ -104,13 +119,17 @@ export const handler = async ({ console.error(c.error(e.message)) } - try { - await shutdownPort(apiAvailablePort) - } catch (e) { - errorTelemetry(process.argv, `Error shutting down "api": ${e.message}`) - console.error( - `Error whilst shutting down "api" port: ${c.error(e.message)}` - ) + // Again, if a server file is configured, we don't know what port it'll end + // up using + if (!serverFile) { + try { + await shutdownPort(apiAvailablePort) + } catch (e) { + errorTelemetry(process.argv, `Error shutting down "api": ${e.message}`) + console.error( + `Error whilst shutting down "api" port: ${c.error(e.message)}` + ) + } } } @@ -142,7 +161,7 @@ export const handler = async ({ return `--debug-port ${apiDebugPortInToml}` } - // Dont pass in debug port flag, unless configured + // Don't pass in debug port flag, unless configured return '' } @@ -178,7 +197,16 @@ export const handler = async ({ const jobs = { api: { name: 'api', - command: `yarn cross-env NODE_ENV=development NODE_OPTIONS="${getDevNodeOptions()}" yarn nodemon --quiet --watch "${redwoodConfigPath}" --exec "yarn rw-api-server-watch --port ${apiAvailablePort} ${getApiDebugFlag()} | rw-log-formatter"`, + command: [ + `yarn cross-env NODE_ENV=development NODE_OPTIONS="${getDevNodeOptions()}"`, + ' yarn nodemon', + ' --quiet', + ` --watch "${redwoodConfigPath}"`, + ' --exec "yarn rw-api-server-watch', + ` --port ${apiAvailablePort}`, + ` ${getApiDebugFlag()}`, + ' | rw-log-formatter"', + ].join(' '), prefixColor: 'cyan', runWhen: () => fs.existsSync(rwjsPaths.api.src), },