diff --git a/.changesets/10265.md b/.changesets/10265.md new file mode 100644 index 000000000000..318b981768bd --- /dev/null +++ b/.changesets/10265.md @@ -0,0 +1,3 @@ +- fix(cli): Update build and serve to handle the absence of the api side (#10265) by @Josh-Walker-GM + +This change allows you to successfully build your app with `yarn rw build` even when you choose to totally delete you api side. Previously you would have seen errors related to both Prisma and GraphQL. It also improves the error messages produced by `yarn rw serve` in this case. diff --git a/__fixtures__/test-project/web/package.json b/__fixtures__/test-project/web/package.json index 62e918264c24..47370d3eb84b 100644 --- a/__fixtures__/test-project/web/package.json +++ b/__fixtures__/test-project/web/package.json @@ -24,7 +24,7 @@ "@types/react": "^18.2.55", "@types/react-dom": "^18.2.19", "autoprefixer": "^10.4.18", - "postcss": "^8.4.36", + "postcss": "^8.4.37", "postcss-loader": "^8.1.1", "prettier-plugin-tailwindcss": "^0.5.12", "tailwindcss": "^3.4.1" diff --git a/packages/cli/src/commands/__tests__/build.test.js b/packages/cli/src/commands/__tests__/build.test.js index 74736a2a52a0..d6b4ab32b7d6 100644 --- a/packages/cli/src/commands/__tests__/build.test.js +++ b/packages/cli/src/commands/__tests__/build.test.js @@ -6,6 +6,7 @@ vi.mock('@redwoodjs/project-config', async (importOriginal) => { return { api: { dist: '/mocked/project/api/dist', + dbSchema: '/mocked/project/api/db/schema.prisma', }, web: { dist: '/mocked/project/web/dist', @@ -23,6 +24,22 @@ vi.mock('@redwoodjs/project-config', async (importOriginal) => { } }) +vi.mock('fs-extra', async () => { + const actualFs = await vi.importActual('fs-extra') + return { + default: { + ...actualFs, + // Mock the existence of the Prisma schema file + existsSync: (path) => { + if (path === '/mocked/project/api/db/schema.prisma') { + return true + } + return actualFs.existsSync(path) + }, + }, + } +}) + import { Listr } from 'listr2' import { vi, afterEach, test, expect } from 'vitest' diff --git a/packages/cli/src/commands/buildHandler.js b/packages/cli/src/commands/buildHandler.js index d75a6844fae8..0c4c84149954 100644 --- a/packages/cli/src/commands/buildHandler.js +++ b/packages/cli/src/commands/buildHandler.js @@ -63,10 +63,13 @@ export const handler = async ({ return } + const prismaSchemaExists = fs.existsSync(rwjsPaths.api.dbSchema) const prerenderRoutes = prerender && side.includes('web') ? detectPrerenderRoutes() : [] const shouldGeneratePrismaClient = - prisma && (side.includes('api') || prerenderRoutes.length > 0) + prisma && + prismaSchemaExists && + (side.includes('api') || prerenderRoutes.length > 0) const tasks = [ shouldGeneratePrismaClient && { @@ -208,7 +211,7 @@ export const handler = async ({ await timedTelemetry(process.argv, { type: 'build' }, async () => { await jobs.run() - if (side.includes('web') && prerender) { + if (side.includes('web') && prerender && prismaSchemaExists) { // This step is outside Listr so that it prints clearer, complete messages await triggerPrerender() } diff --git a/packages/cli/src/commands/serve.js b/packages/cli/src/commands/serve.js index 89b5e27bff7f..7b2ff5c9627a 100644 --- a/packages/cli/src/commands/serve.js +++ b/packages/cli/src/commands/serve.js @@ -113,30 +113,50 @@ export const builder = async (yargs) => { process.exit(1) } - if ( - positionalArgs.includes('api') && - !fs.existsSync(path.join(getPaths().api.dist)) - ) { - console.error( - c.error( - '\n Please run `yarn rw build api` before trying to serve api. \n', - ), - ) - process.exit(1) + const apiSideExists = fs.existsSync(getPaths().api.base) + if (positionalArgs.includes('api')) { + if (!apiSideExists) { + console.error( + c.error( + '\n Unable to serve the api side as no `api` folder exists. \n', + ), + ) + process.exit(1) + } + + if (!fs.existsSync(path.join(getPaths().api.dist))) { + console.error( + c.error( + '\n Please run `yarn rw build api` before trying to serve api. \n', + ), + ) + process.exit(1) + } } - if ( - // serve both - positionalArgs.length === 1 && - (!fs.existsSync(path.join(getPaths().api.dist)) || - !fs.existsSync(path.join(getPaths().web.dist), 'index.html')) - ) { - console.error( - c.error( - '\n Please run `yarn rw build` before trying to serve your redwood app. \n', - ), - ) - process.exit(1) + // serve both + if (positionalArgs.length === 1) { + if (!apiSideExists) { + console.error( + c.error( + '\n Unable to serve the both sides as no `api` folder exists. Please use `yarn rw serve web` instead. \n', + ), + ) + process.exit(1) + } + + // We need the web side to have been built + if ( + !fs.existsSync(path.join(getPaths().api.dist)) || + !fs.existsSync(path.join(getPaths().web.dist), 'index.html') + ) { + console.error( + c.error( + '\n Please run `yarn rw build` before trying to serve your redwood app. \n', + ), + ) + process.exit(1) + } } // Set NODE_ENV to production, if not set diff --git a/packages/vite/src/index.ts b/packages/vite/src/index.ts index aeb447e96a7d..7b5836d270da 100644 --- a/packages/vite/src/index.ts +++ b/packages/vite/src/index.ts @@ -32,9 +32,10 @@ export default function redwoodPluginVite(): PluginOption[] { // If realtime is enabled, we want to include the sseLink in the bundle. // Right now the only way we have of telling is if the package is installed on the api side. - const realtimeEnabled = fs - .readFileSync(path.join(rwPaths.api.base, 'package.json'), 'utf-8') - .includes('@redwoodjs/realtime') + const apiPackageJsonPath = path.join(rwPaths.api.base, 'package.json') + const realtimeEnabled = + fs.existsSync(apiPackageJsonPath) && + fs.readFileSync(apiPackageJsonPath, 'utf-8').includes('@redwoodjs/realtime') const streamingEnabled = rwConfig.experimental.streamingSsr.enabled