Skip to content

Commit 09be6f9

Browse files
committed
fix: apply headers for prerendered routes
1 parent c64b969 commit 09be6f9

File tree

5 files changed

+83
-35
lines changed

5 files changed

+83
-35
lines changed

demo/src/app/app.routes.server.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
import { RenderMode, ServerRoute } from '@angular/ssr'
22

33
export const serverRoutes: ServerRoute[] = [
4+
// redirects don't seem to work with Prerender mode
5+
// { path: '', renderMode: RenderMode.Prerender },
46
// dashboard component demonstrates "netlify.request" and "netlify.context" injection injection
57
// which only really work for SSR, so we are forcing SSR mode here
6-
{ path: 'dashboard', renderMode: RenderMode.Server },
8+
{
9+
path: 'dashboard',
10+
renderMode: RenderMode.Server,
11+
headers: {
12+
foo: 'bar',
13+
},
14+
},
715
{ path: 'detail/:id', renderMode: RenderMode.Server },
816
{
9-
path: '**',
17+
path: 'heroes',
1018
renderMode: RenderMode.Prerender,
19+
headers: {
20+
foo: 'baz',
21+
},
22+
},
23+
// fallback
24+
{
25+
path: '**',
26+
renderMode: RenderMode.Server,
1127
},
1228
]

src/helpers/getPrerenderedRoutes.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const { existsSync } = require('node:fs')
2+
const { join } = require('node:path')
3+
4+
const { readJson } = require('fs-extra')
5+
6+
/**
7+
* @param {string} outputDir
8+
* @returns {Promise<Record<string, { headers?: Record<string, string> }>>}
9+
*/
10+
const getPrerenderedRoutes = async (outputDir) => {
11+
const file = join(outputDir, 'prerendered-routes.json')
12+
if (!existsSync(file)) return {}
13+
const { routes: prerenderedRoutes } = await readJson(file)
14+
15+
if (Array.isArray(prerenderedRoutes)) {
16+
// Before Angular@19 prerendered-routes is an array of strings
17+
return prerenderedRoutes.reduce((acc, route) => {
18+
acc[route] = {}
19+
return acc
20+
}, {})
21+
}
22+
23+
return prerenderedRoutes
24+
}
25+
26+
module.exports = getPrerenderedRoutes

src/helpers/setUpEdgeFunction.js

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ const { writeFile, mkdir, readFile } = require('node:fs/promises')
55
const { join, relative, sep, posix } = require('node:path')
66
const process = require('node:process')
77

8-
const { readJson } = require('fs-extra')
9-
108
const packageJson = require('../../package.json')
119

10+
const getPrerenderedRoutes = require('./getPrerenderedRoutes')
11+
1212
/**
1313
* Recursively lists all files in a directory.
1414
*/
@@ -47,35 +47,8 @@ const getProject = (angularJson, failBuild) => {
4747

4848
module.exports.getProject = getProject
4949

50-
/**
51-
* @param {string} outputDir
52-
* @returns {Promise<string[]>}
53-
*/
54-
const getPrerenderedRoutes = async (outputDir) => {
55-
const file = join(outputDir, 'prerendered-routes.json')
56-
if (!existsSync(file)) return []
57-
const { routes: prerenderedRoutes } = await readJson(file)
58-
59-
if (!Array.isArray(prerenderedRoutes)) {
60-
// Angular@19 changes shape of prerendered-routes from array of strings to object with routes as keys
61-
return Object.keys(prerenderedRoutes)
62-
}
63-
64-
// Before Angular@19 prerendered-routes is an array of strings
65-
return prerenderedRoutes
66-
}
67-
6850
// eslint-disable-next-line max-lines-per-function
69-
const setUpEdgeFunction = async ({ angularJson, constants, failBuild, usedEngine }) => {
70-
const project = getProject(angularJson)
71-
const {
72-
architect: { build },
73-
} = project
74-
const outputDir = build?.options?.outputPath
75-
if (!outputDir || !existsSync(outputDir)) {
76-
return failBuild('Could not find build output directory')
77-
}
78-
51+
const setUpEdgeFunction = async ({ outputDir, constants, failBuild, usedEngine }) => {
7952
const serverDistRoot = join(outputDir, 'server')
8053
if (!existsSync(serverDistRoot)) {
8154
console.log('No server output generated, skipping SSR setup.')
@@ -92,7 +65,9 @@ const setUpEdgeFunction = async ({ angularJson, constants, failBuild, usedEngine
9265
(path) => `/${relative(join(outputDir, 'browser'), path)}`,
9366
)
9467

95-
const excludedPaths = ['/.netlify/*', ...staticFiles, ...(await getPrerenderedRoutes(outputDir))].map(toPosix)
68+
const excludedPaths = ['/.netlify/*', ...staticFiles, ...Object.keys(await getPrerenderedRoutes(outputDir))].map(
69+
toPosix,
70+
)
9671

9772
// buy putting this into a separate module that's imported first,
9873
// we ensure this is initialised before any other module

src/helpers/setUpHeaders.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const getPrerenderedRoutes = require('./getPrerenderedRoutes')
2+
3+
const setUpHeaders = async ({ outputDir, netlifyConfig }) => {
4+
const prerenderRoutes = await getPrerenderedRoutes(outputDir)
5+
6+
for (const [route, routeConfig] of Object.entries(prerenderRoutes)) {
7+
if (routeConfig.headers) {
8+
netlifyConfig.headers = netlifyConfig.headers ?? []
9+
netlifyConfig.headers.push({
10+
for: route,
11+
values: routeConfig.headers,
12+
})
13+
}
14+
}
15+
}
16+
17+
module.exports = setUpHeaders

src/index.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
const { existsSync } = require('node:fs')
2+
13
const ensureNoCompetingPlugin = require('./helpers/ensureNoCompetingPlugin')
24
const fixOutputDir = require('./helpers/fixOutputDir')
35
const getAngularJson = require('./helpers/getAngularJson')
46
const getAngularRoot = require('./helpers/getAngularRoot')
57
const getAngularVersion = require('./helpers/getAngularVersion')
68
const { fixServerTs, revertServerTsFix } = require('./helpers/serverModuleHelpers')
7-
const { setUpEdgeFunction } = require('./helpers/setUpEdgeFunction')
9+
const { getProject, setUpEdgeFunction } = require('./helpers/setUpEdgeFunction')
10+
const setUpHeaders = require('./helpers/setUpHeaders')
811
const validateAngularVersion = require('./helpers/validateAngularVersion')
912

1013
let isValidAngularProject = true
@@ -48,8 +51,19 @@ module.exports = {
4851
const siteRoot = getAngularRoot({ failBuild, netlifyConfig })
4952
const angularJson = getAngularJson({ failPlugin, siteRoot })
5053

54+
const project = getProject(angularJson)
55+
const {
56+
architect: { build },
57+
} = project
58+
const outputDir = build?.options?.outputPath
59+
if (!outputDir || !existsSync(outputDir)) {
60+
return failBuild('Could not find build output directory')
61+
}
62+
63+
await setUpHeaders({ outputDir, netlifyConfig })
64+
5165
await setUpEdgeFunction({
52-
angularJson,
66+
outputDir,
5367
constants,
5468
failBuild,
5569
usedEngine,

0 commit comments

Comments
 (0)