angular / angular/angularfire

@angular/ssr/node not working as intended

オープン
#3,596 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
TypeScript
スター
7.8k
フォーク
2.2k
平均マージ
22時間 28分
マージ済み PR(30日)
6

説明

I am using @angular/fire@19.0.0-rc.4, 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.

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

src/server.ts と functions/ssr/index.js から始め、次に src/app/app.routes.ts の /error ルートからのリダイレクトを、デプロイされた Firebase Hosting のリクエストと比較します。Cloud Function の 302 Location レスポンスを調査し、完了した動作によってポート 8080 が公開されるのではなく、公開 Hosting URL が維持されることを確認します。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
angular, express, firebase, node.js, typescript
領域
backend, cloud, web-dev
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
38/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。