@angular/ssr/node not working as intended
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 38/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 停滞
- 技術スタック
- angular, express, firebase, node.js, typescript
調査の方向性
src/server.ts と functions/ssr/index.js から始め、次に src/app/app.routes.ts の /error ルートからのリダイレクトを、デプロイされた Firebase Hosting のリクエストと比較します。Cloud Function の 302 Location レスポンスを調査し、完了した動作によってポート 8080 が公開されるのではなく、公開 Hosting URL が維持されることを確認します。
索引モデルが issue の本文から書いたものです。
説明
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.
- 主要言語
- TypeScript
- スター
- 7.8k
- フォーク
- 2.2k
- 平均マージ
- 3日 6時間
- マージ済み PR(30日)
- 5
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
angular/angularfire のほかの issue
-
comp: build/pipeline type: bug version: current (v17+)
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
angular/angularfire#3766 ·
-
comp: schematics type: bug version: current (v17+)
難易度 3/5 1〜2日 初心者へのやさしさ 76/100
angular/angularfire#3768 ·
-
comp: docs type: chore version: current (v17+)
難易度 4/5 3〜5日 初心者へのやさしさ 58/100
angular/angularfire#3764 ·
-
comp: firestore comp: ssr priority: P0 (critical) type: feature version: current (v17+)
angular/angularfire#3757 · 担当者 1 名 ·
-
Six `firebase` entry points have no `@angular/fire` equivalent, so their exports are unreachable オープンcomp: core type: feature
angular/angularfire#3755 · 担当者 1 名 ·
angular/angularfire の issue をすべて見る
似ている issue
-
blocklist removal
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
MetaMask/eth-phishing-detect#296544 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
pastelsky/bundlephobia#1122 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
-
category/development priority/P2 scope/file-operations scope/testing type/enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
Enatega Customer and Rider app: Add-ons price is not visible to customer after order is placed. オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100