angularfire icon indicating copy to clipboard operation
angularfire copied to clipboard

@angular/ssr/node not working as intended

Open davidbusuttil opened this issue 1 year ago • 2 comments

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.

davidbusuttil avatar Dec 20 '24 20:12 davidbusuttil

This issue does not seem to follow the issue template. Make sure you provide all the required information.

google-oss-bot avatar Dec 20 '24 20:12 google-oss-bot

I'm having the same issue

brunostuani avatar Dec 30 '24 13:12 brunostuani