diff --git a/packages/vite/src/buildFeServer.ts b/packages/vite/src/buildFeServer.ts index bdff87e4812f..bfa139469e53 100644 --- a/packages/vite/src/buildFeServer.ts +++ b/packages/vite/src/buildFeServer.ts @@ -1,9 +1,5 @@ -import fs from 'fs/promises' -import path from 'path' - import type { PluginBuild } from 'esbuild' import { build as esbuildBuild } from 'esbuild' -import type { Manifest as ViteBuildManifest } from 'vite' import { build as viteBuild } from 'vite' import { @@ -12,11 +8,10 @@ import { } from '@redwoodjs/babel-config' import { buildWeb } from '@redwoodjs/internal/dist/build/web' import { findRouteHooksSrc } from '@redwoodjs/internal/dist/files' -import { getProjectRoutes } from '@redwoodjs/internal/dist/routes' -import { getAppRouteHook, getConfig, getPaths } from '@redwoodjs/project-config' +import { getConfig, getPaths } from '@redwoodjs/project-config' +import { buildRouteManifest } from './buildRouteManifest' import { buildRscFeServer } from './buildRscFeServer' -import type { RWRouteManifest } from './types' import { ensureProcessDirWeb } from './utils' export interface BuildOptions { @@ -51,7 +46,7 @@ export const buildFeServer = async ({ verbose, webDir }: BuildOptions = {}) => { throw new Error('RSC entries file not found') } - return await buildRscFeServer({ + await buildRscFeServer({ viteConfigPath, webSrc: rwPaths.web.src, webHtml: rwPaths.web.html, @@ -59,8 +54,10 @@ export const buildFeServer = async ({ verbose, webDir }: BuildOptions = {}) => { webDist: rwPaths.web.dist, webDistServer: rwPaths.web.distServer, webDistServerEntries: rwPaths.web.distServerEntries, - webRouteManifest: rwPaths.web.routeManifest, }) + + // Write a route manifest + return await buildRouteManifest() } // Step 1A: Generate the client bundle @@ -118,77 +115,6 @@ export const buildFeServer = async ({ verbose, webDir }: BuildOptions = {}) => { outdir: rwPaths.web.distRouteHooks, }) - // Step 3: Generate route-manifest.json - - // TODO When https://github.com/tc39/proposal-import-attributes and - // https://github.com/microsoft/TypeScript/issues/53656 have both landed we - // should try to do this instead: - // const clientBuildManifest: ViteBuildManifest = await import( - // path.join(getPaths().web.dist, 'client-build-manifest.json'), - // { with: { type: 'json' } } - // ) - // NOTES: - // * There's a related babel plugin here - // https://babeljs.io/docs/babel-plugin-syntax-import-attributes - // * Included in `preset-env` if you set `shippedProposals: true` - // * We had this before, but with `assert` instead of `with`. We really - // should be using `with`. See motivation in issues linked above. - // * With `assert` and `@babel/plugin-syntax-import-assertions` the - // code compiled and ran properly, but Jest tests failed, complaining - // about the syntax. - const manifestPath = path.join( - getPaths().web.dist, - 'client-build-manifest.json' - ) - const buildManifestStr = await fs.readFile(manifestPath, 'utf-8') - const clientBuildManifest: ViteBuildManifest = JSON.parse(buildManifestStr) - - const routesList = getProjectRoutes() - - const routeManifest = routesList.reduce((acc, route) => { - acc[route.pathDefinition] = { - name: route.name, - bundle: route.relativeFilePath - ? clientBuildManifest[route.relativeFilePath]?.file ?? null - : null, - matchRegexString: route.matchRegexString, - // @NOTE this is the path definition, not the actual path - // E.g. /blog/post/{id:Int} - pathDefinition: route.pathDefinition, - hasParams: route.hasParams, - routeHooks: FIXME_constructRouteHookPath(route.routeHooks), - redirect: route.redirect - ? { - to: route.redirect?.to, - permanent: false, - } - : null, - renderMode: route.renderMode, - } - - return acc - }, {}) - - await fs.writeFile( - rwPaths.web.routeManifest, - JSON.stringify(routeManifest, null, 2) - ) -} - -// TODO (STREAMING) Hacky work around because when you don't have a App.routeHook, esbuild doesn't create -// the pages folder in the dist/server/routeHooks directory. -// @MARK need to change to .mjs here if we use esm -const FIXME_constructRouteHookPath = (rhSrcPath: string | null | undefined) => { - const rwPaths = getPaths() - if (!rhSrcPath) { - return null - } - - if (getAppRouteHook()) { - return path.relative(rwPaths.web.src, rhSrcPath).replace('.ts', '.js') - } else { - return path - .relative(path.join(rwPaths.web.src, 'pages'), rhSrcPath) - .replace('.ts', '.js') - } + // Write a route manifest + await buildRouteManifest() } diff --git a/packages/vite/src/buildRouteManifest.ts b/packages/vite/src/buildRouteManifest.ts new file mode 100644 index 000000000000..98dc23e136e1 --- /dev/null +++ b/packages/vite/src/buildRouteManifest.ts @@ -0,0 +1,92 @@ +import fs from 'fs/promises' +import path from 'path' + +import type { Manifest as ViteBuildManifest } from 'vite' + +import { getProjectRoutes } from '@redwoodjs/internal/dist/routes' +import { getAppRouteHook, getPaths } from '@redwoodjs/project-config' + +import type { RWRouteManifest } from './types' + +/** + * RSC build. Step 6. + * Generate a route manifest file for the web server side. + */ +export async function buildRouteManifest() { + const webRouteManifest = getPaths().web.routeManifest + + // TODO When https://github.com/tc39/proposal-import-attributes and + // https://github.com/microsoft/TypeScript/issues/53656 have both landed we + // should try to do this instead: + // const clientBuildManifest: ViteBuildManifest = await import( + // path.join(getPaths().web.dist, 'client-build-manifest.json'), + // { with: { type: 'json' } } + // ) + // NOTES: + // * There's a related babel plugin here + // https://babeljs.io/docs/babel-plugin-syntax-import-attributes + // * Included in `preset-env` if you set `shippedProposals: true` + // * We had this before, but with `assert` instead of `with`. We really + // should be using `with`. See motivation in issues linked above. + // * With `assert` and `@babel/plugin-syntax-import-assertions` the + // code compiled and ran properly, but Jest tests failed, complaining + // about the syntax. + const manifestPath = path.join( + getPaths().web.dist, + 'client-build-manifest.json' + ) + const buildManifestStr = await fs.readFile(manifestPath, 'utf-8') + const clientBuildManifest: ViteBuildManifest = JSON.parse(buildManifestStr) + + const routesList = getProjectRoutes() + + const routeManifest = routesList.reduce((acc, route) => { + acc[route.pathDefinition] = { + name: route.name, + bundle: route.relativeFilePath + ? clientBuildManifest[route.relativeFilePath]?.file ?? null + : null, + matchRegexString: route.matchRegexString, + // NOTE this is the path definition, not the actual path + // E.g. /blog/post/{id:Int} + pathDefinition: route.pathDefinition, + hasParams: route.hasParams, + routeHooks: FIXME_constructRouteHookPath(route.routeHooks), + redirect: route.redirect + ? { + to: route.redirect?.to, + permanent: false, + } + : null, + renderMode: route.renderMode, + } + + return acc + }, {}) + + console.log('routeManifest', JSON.stringify(routeManifest, null, 2)) + + return fs.writeFile(webRouteManifest, JSON.stringify(routeManifest, null, 2)) +} + +// TODO (STREAMING) Hacky work around because when you don't have a App.routeHook, esbuild doesn't create +// the pages folder in the dist/server/routeHooks directory. +// @MARK need to change to .mjs here if we use esm +const FIXME_constructRouteHookPath = ( + routeHookSrcPath: string | null | undefined +) => { + const rwPaths = getPaths() + if (!routeHookSrcPath) { + return null + } + + if (getAppRouteHook()) { + return path + .relative(rwPaths.web.src, routeHookSrcPath) + .replace('.ts', '.js') + } else { + return path + .relative(path.join(rwPaths.web.src, 'pages'), routeHookSrcPath) + .replace('.ts', '.js') + } +} diff --git a/packages/vite/src/buildRscFeServer.ts b/packages/vite/src/buildRscFeServer.ts index 1fdd6e191ecc..f07fa98385e3 100644 --- a/packages/vite/src/buildRscFeServer.ts +++ b/packages/vite/src/buildRscFeServer.ts @@ -2,7 +2,6 @@ import { rscBuildAnalyze } from './rsc/rscBuildAnalyze' import { rscBuildClient } from './rsc/rscBuildClient' import { rscBuildClientEntriesMappings } from './rsc/rscBuildClientEntriesFile' import { rscBuildCopyCssAssets } from './rsc/rscBuildCopyCssAssets' -import { rscBuildRouteManifest } from './rsc/rscBuildRouteManifest' import { rscBuildServer } from './rsc/rscBuildServer' interface Args { @@ -13,7 +12,6 @@ interface Args { webDist: string webDistServer: string webDistServerEntries: string - webRouteManifest: string } export const buildRscFeServer = async ({ @@ -24,7 +22,6 @@ export const buildRscFeServer = async ({ webDist, webDistServer, webDistServerEntries, - webRouteManifest, }: Args) => { // Analyze all files and generate a list of RSCs and RSFs const { clientEntryFiles, serverEntryFiles } = await rscBuildAnalyze( @@ -57,7 +54,4 @@ export const buildRscFeServer = async ({ clientEntryFiles, webDistServerEntries ) - - // Write a route manifest - await rscBuildRouteManifest(webRouteManifest) } diff --git a/packages/vite/src/rsc/rscBuildRouteManifest.ts b/packages/vite/src/rsc/rscBuildRouteManifest.ts deleted file mode 100644 index db2e82f57a0e..000000000000 --- a/packages/vite/src/rsc/rscBuildRouteManifest.ts +++ /dev/null @@ -1,52 +0,0 @@ -import fs from 'fs/promises' -import path from 'path' - -import type { Manifest as ViteBuildManifest } from 'vite' - -import { getProjectRoutes } from '@redwoodjs/internal/dist/routes' -import { getPaths } from '@redwoodjs/project-config' - -import type { RWRouteManifest } from '../types' - -/** - * RSC build. Step 6. - * Generate a route manifest file for the web server side. - */ -export async function rscBuildRouteManifest(webRouteManifest: string) { - const manifestPath = path.join( - getPaths().web.dist, - 'client-build-manifest.json' - ) - const buildManifestStr = await fs.readFile(manifestPath, 'utf-8') - const clientBuildManifest: ViteBuildManifest = JSON.parse(buildManifestStr) - - const routesList = getProjectRoutes() - - const routeManifest = routesList.reduce((acc, route) => { - acc[route.pathDefinition] = { - name: route.name, - bundle: route.relativeFilePath - ? clientBuildManifest[route.relativeFilePath]?.file ?? null - : null, - matchRegexString: route.matchRegexString, - // NOTE this is the path definition, not the actual path - // E.g. /blog/post/{id:Int} - pathDefinition: route.pathDefinition, - hasParams: route.hasParams, - routeHooks: null, - redirect: route.redirect - ? { - to: route.redirect?.to, - permanent: false, - } - : null, - renderMode: route.renderMode, - } - - return acc - }, {}) - - console.log('routeManifest', JSON.stringify(routeManifest, null, 2)) - - return fs.writeFile(webRouteManifest, JSON.stringify(routeManifest, null, 2)) -}