@angular/ssr/node not working as intended
I am using @angular/[email protected], and I have the following:
src/server.ts
import { AngularNodeAppEngine, createNodeRequestHandler, isMainModule, writeResponseToNodeResponse, } from "@angular/ssr/node";
import express from "express";
import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url";
const serverDistFolder = dirname(fileURLToPath(import.meta.url)); const browserDistFolder = resolve(serverDistFolder, "../browser");
const server = express(); const angularNodeAppEngine = new AngularNodeAppEngine();
server.use( express.static(browserDistFolder, { maxAge: "1y", index: false, redirect: false, }), );
server.use("/**", (serverRequest, serverResponse, serverNextFunction) => { angularNodeAppEngine .handle(serverRequest) .then((response) => { if (response) { return writeResponseToNodeResponse(response, serverResponse); } else { return serverNextFunction(); } }) .catch(serverNextFunction); });
if (isMainModule(import.meta.url)) { const port = process.env["PORT"] || 4000; server.listen(port, () => { console.log(
Node Express server listening on http://localhost:${port}); }); }export const reqHandler = createNodeRequestHandler(server);
src/app/app.routes.ts
import { Route } from "@angular/router";
import { ErrorComponent } from "./error/error.component"; import { errorResolver } from "./error/error.resolver"; import { HomeComponent } from "./home/home.component"; import { homeResolver } from "./home/home.resolver";
export const routes: Route[] = [ { path: "error", component: ErrorComponent, resolve: { error: errorResolver, }, }, { path: "", pathMatch: "full", component: HomeComponent, resolve: { home: homeResolver, }, }, { path: "**", redirectTo: "/error", }, ];
src/app/app.routes.server.ts
import { RenderMode, ServerRoute } from "@angular/ssr";
export const serverRoutes: ServerRoute[] = [ { path: "**", renderMode: RenderMode.Server, }, ];
src/app/app.config.ts
import { ApplicationConfig, provideExperimentalZonelessChangeDetection, } from "@angular/core"; import { initializeApp, provideFirebaseApp } from "@angular/fire/app"; import { getAnalytics, provideAnalytics } from "@angular/fire/analytics"; import { getFirestore, provideFirestore } from "@angular/fire/firestore"; import { getStorage, provideStorage } from "@angular/fire/storage"; import { provideClientHydration, withEventReplay, } from "@angular/platform-browser"; import { provideRouter, withEnabledBlockingInitialNavigation, withInMemoryScrolling, } from "@angular/router";
import { routes } from "./app.routes";
import { environment } from "../environments/environment.production";
export const appConfig: ApplicationConfig = { providers: [ provideExperimentalZonelessChangeDetection(), provideClientHydration(withEventReplay()), provideRouter( routes, withEnabledBlockingInitialNavigation(), withInMemoryScrolling({ anchorScrolling: "enabled", scrollPositionRestoration: "enabled", }), ), provideFirebaseApp(() => { return initializeApp(environment.firebase); }), provideAnalytics(() => { return getAnalytics(); }), provideFirestore(() => { return getFirestore(); }), provideStorage(() => { return getStorage(); }), ], };
src/app/app.config.server.ts
import { mergeApplicationConfig, ApplicationConfig } from "@angular/core"; import { provideServerRendering } from "@angular/platform-server"; import { provideServerRoutesConfig } from "@angular/ssr";
import { appConfig } from "./app.config"; import { serverRoutes } from "./app.routes.server";
const serverConfig: ApplicationConfig = { providers: [ provideServerRendering(), provideServerRoutesConfig(serverRoutes), ], };
export const config = mergeApplicationConfig(appConfig, serverConfig);
Now, I am not using ng deploy or firebase deploy since they require @angular-devkit/build-angular and the SSR function being deployed is not working. Instead, I created a separate Firebase Repo and initialised both hosting and functions.
firebase.json
{ "functions": [ { "source": "functions/ssr", "codebase": "ssr", "ignore": [...] } ], "hosting": { "public": "hosting", "ignore": [...], "rewrites": [ { "source": "**", "function": { "functionId": "ssr", "region": "europe-west1" } } ] } }
functions/ssr/index.js
import { onRequest } from "firebase-functions/v2/https";
import { reqHandler } from "./build/template/server/server.mjs";
export const ssr = onRequest( { region: "europe-west1", invoker: "public", memory: "256MiB", cpu: 1, timeoutSeconds: 60, concurrency: 80, minInstances: 1, maxInstances: 100, ingressSettings: "ALLOW_ALL", preserveExternalChanges: false, }, reqHandler, );
In the Firebase Repo, I am successfully deploying both hosting and functions using firebase deploy. The SSR function works, save for paths redirected to the ErrorComponent:
src/app/app.routes.ts
{ path: "**", redirectTo: "/error", },
When seeing the Google Cloud Console logs for the Cloud function, the express instance is giving a 302 response (which is what you'd expect from a redirect), however, instead of staying on port 80, the redirect URL is given on port 8080, which is the internal port being using by the express instance. I reckon that server.ts needs to be modified, however, I don't know how.
This issue does not seem to follow the issue template. Make sure you provide all the required information.
I'm having the same issue