diff --git a/ponyracer/angular.json b/ponyracer/angular.json index 282d0ea..cd9187b 100644 --- a/ponyracer/angular.json +++ b/ponyracer/angular.json @@ -31,9 +31,9 @@ ], "scripts": [], "server": "src/main.server.ts", - "prerender": true, + "outputMode": "server", "ssr": { - "entry": "server.ts" + "entry": "src/server.ts" } }, "configurations": { diff --git a/ponyracer/package.json b/ponyracer/package.json index 5bfc242..f706411 100644 --- a/ponyracer/package.json +++ b/ponyracer/package.json @@ -20,15 +20,15 @@ "@angular/platform-browser-dynamic": "^19.0.0-next.0", "@angular/platform-server": "^19.0.0-next.0", "@angular/router": "^19.0.0-next.0", - "@angular/ssr": "^19.0.0-next.9", + "@angular/ssr": "^19.0.0-next.10", "express": "^4.18.2", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" }, "devDependencies": { - "@angular-devkit/build-angular": "^19.0.0-next.9", - "@angular/cli": "^19.0.0-next.9", + "@angular-devkit/build-angular": "^19.0.0-next.10", + "@angular/cli": "^19.0.0-next.10", "@angular/compiler-cli": "^19.0.0-next.0", "@types/express": "^4.17.17", "@types/jasmine": "~5.1.0", diff --git a/ponyracer/server.ts b/ponyracer/server.ts deleted file mode 100644 index 72747d1..0000000 --- a/ponyracer/server.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { APP_BASE_HREF } from '@angular/common'; -import { CommonEngine } from '@angular/ssr/node'; -import express from 'express'; -import { fileURLToPath } from 'node:url'; -import { dirname, join, resolve } from 'node:path'; -import bootstrap from './src/main.server'; - -// The Express app is exported so that it can be used by serverless Functions. -export function app(): express.Express { - const server = express(); - const serverDistFolder = dirname(fileURLToPath(import.meta.url)); - const browserDistFolder = resolve(serverDistFolder, '../browser'); - const indexHtml = join(serverDistFolder, 'index.server.html'); - - const commonEngine = new CommonEngine(); - - server.set('view engine', 'html'); - server.set('views', browserDistFolder); - - // Example Express Rest API endpoints - // server.get('/api/**', (req, res) => { }); - // Serve static files from /browser - server.get('**', express.static(browserDistFolder, { - maxAge: '1y', - index: 'index.html', - })); - - // All regular routes use the Angular engine - server.get('**', (req, res, next) => { - const { protocol, originalUrl, baseUrl, headers } = req; - - commonEngine - .render({ - bootstrap, - documentFilePath: indexHtml, - url: `${protocol}://${headers.host}${originalUrl}`, - publicPath: browserDistFolder, - providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }], - }) - .then((html) => res.send(html)) - .catch((err) => next(err)); - }); - - return server; -} - -function run(): void { - const port = process.env['PORT'] || 4000; - - // Start up the Node server - const server = app(); - server.listen(port, () => { - console.log(`Node Express server listening on http://localhost:${port}`); - }); -} - -run(); diff --git a/ponyracer/src/app/app.config.server.ts b/ponyracer/src/app/app.config.server.ts index b4d57c9..1b7f650 100644 --- a/ponyracer/src/app/app.config.server.ts +++ b/ponyracer/src/app/app.config.server.ts @@ -1,10 +1,13 @@ 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() + provideServerRendering(), + provideServerRoutesConfig(serverRoutes) ] }; diff --git a/ponyracer/src/app/app.routes.server.ts b/ponyracer/src/app/app.routes.server.ts new file mode 100644 index 0000000..ffd37b1 --- /dev/null +++ b/ponyracer/src/app/app.routes.server.ts @@ -0,0 +1,8 @@ +import { RenderMode, ServerRoute } from '@angular/ssr'; + +export const serverRoutes: ServerRoute[] = [ + { + path: '**', + renderMode: RenderMode.Prerender + } +]; diff --git a/ponyracer/src/server.ts b/ponyracer/src/server.ts new file mode 100644 index 0000000..e3c883a --- /dev/null +++ b/ponyracer/src/server.ts @@ -0,0 +1,49 @@ +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 app = express(); +const angularApp = new AngularNodeAppEngine(); + +// Example Express Rest API endpoints +// app.get('/api/**', (req, res) => { }); + +// Serve static files from /browser +app.get( + '**', + express.static(browserDistFolder, { + maxAge: '1y', + index: 'index.html', + setHeaders: (res) => { + const headers = angularApp.getPrerenderHeaders(res.req); + for (const [key, value] of headers) { + res.setHeader(key, value); + } + }, + }), +); + +app.get('**', (req, res, next) => { + angularApp + .render(req) + .then((response) => (response ? writeResponseToNodeResponse(response, res) : next())) + .catch(next); +}); + +if (isMainModule(import.meta.url)) { + const port = process.env['PORT'] || 4000; + app.listen(port, () => { + console.log(`Node Express server listening on http://localhost:${port}`); + }); +} + +export default createNodeRequestHandler(app); diff --git a/ponyracer/tsconfig.app.json b/ponyracer/tsconfig.app.json index cdc0b28..9ab8527 100644 --- a/ponyracer/tsconfig.app.json +++ b/ponyracer/tsconfig.app.json @@ -11,7 +11,7 @@ "files": [ "src/main.ts", "src/main.server.ts", - "server.ts" + "src/server.ts" ], "include": [ "src/**/*.d.ts"