Skip to content

Commit c658e2c

Browse files
committed
address comments
1 parent f4b045d commit c658e2c

File tree

4 files changed

+96
-51
lines changed

4 files changed

+96
-51
lines changed

packages/@apphosting/adapter-nextjs/src/bin/build.spec.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import fs from "fs";
44
import yaml from "yaml";
55
import path from "path";
66
import os from "os";
7-
import { OutputBundleOptions } from "../interfaces.js";
7+
import { OutputBundleOptions, AdapterMetadata } from "../interfaces.js";
88

99
describe("build commands", () => {
1010
let tmpDir: string;
1111
let outputBundleOptions: OutputBundleOptions;
1212
let defaultNextVersion: string;
13+
let adapterMetadata: AdapterMetadata;
14+
1315
beforeEach(() => {
1416
tmpDir = generateTmpDir();
1517
outputBundleOptions = {
@@ -21,10 +23,14 @@ describe("build commands", () => {
2123
serverFilePath: path.join(tmpDir, ".next", "standalone", "server.js"),
2224
};
2325
defaultNextVersion = "14.0.3";
26+
adapterMetadata = {
27+
adapterPackageName: "@apphosting/adapter-nextjs",
28+
adapterVersion: "14.0.1",
29+
};
2430
});
2531

2632
it("expects all output bundle files to be generated", async () => {
27-
const { generateBuildOutput, validateOutputDirectory, getAdapterMetadata } = await importUtils;
33+
const { generateBuildOutput, validateOutputDirectory } = await importUtils;
2834
const files = {
2935
".next/standalone/server.js": "",
3036
".next/static/staticfile": "",
@@ -34,7 +40,6 @@ describe("build commands", () => {
3440
"redirects":[]
3541
}`,
3642
};
37-
const adapterMetadata = getAdapterMetadata();
3843
generateTestFiles(tmpDir, files);
3944
await generateBuildOutput(
4045
tmpDir,
@@ -98,10 +103,7 @@ metadata:
98103
},
99104
path.join(tmpDir, ".next"),
100105
defaultNextVersion,
101-
{
102-
adapterPackageName: "@apphosting/adapter-nextjs",
103-
adapterVersion: "14.0.1",
104-
},
106+
adapterMetadata,
105107
);
106108

107109
const expectedFiles = {

packages/@apphosting/adapter-nextjs/src/interfaces.ts

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import type { RouteHas } from "next/dist/lib/load-custom-routes.js";
2+
import type { AssetBinding } from "next/dist/build/webpack/loaders/get-module-build-info.js";
3+
import type { MiddlewareMatcher } from "next/dist/build//analysis/get-page-static-info.js";
24

35
export interface RoutesManifestRewriteObject {
46
beforeFiles?: RoutesManifestRewrite[];
@@ -113,23 +115,23 @@ export interface Metadata extends AdapterMetadata {
113115
frameworkVersion: string;
114116
}
115117

116-
// Metadata schema for asset bindings
117-
export interface AssetBinding {
118-
filePath: string;
119-
name: string;
120-
}
121-
122-
// Metadata schema for middleware matchers
123-
export interface MiddlewareMatcher {
124-
regexp: string;
125-
locale?: false;
126-
has?: RouteHas[];
127-
missing?: RouteHas[];
128-
originalSource: string;
118+
/*
119+
Next.js exposed internal interface for middleware manifest (middleware-manifest.json)
120+
https://github.com/vercel/next.js/blob/v15.2.0-canary.76/packages/next/src/build/webpack/plugins/middleware-plugin.ts#L54
121+
*/
122+
export interface MiddlewareManifest {
123+
version: 3;
124+
sortedMiddleware: string[];
125+
middleware: {
126+
[page: string]: EdgeFunctionDefinition;
127+
};
128+
functions: {
129+
[page: string]: EdgeFunctionDefinition;
130+
};
129131
}
130132

131-
// Metadata schema for edge function definitions
132-
export interface EdgeFunctionDefinition {
133+
// Next.js exposed internal interface for edge function definitions
134+
interface EdgeFunctionDefinition {
133135
files: string[];
134136
name: string;
135137
page: string;
@@ -138,15 +140,3 @@ export interface EdgeFunctionDefinition {
138140
assets?: AssetBinding[];
139141
regions?: string[] | string;
140142
}
141-
142-
// Metadata schema for middleware manifest
143-
export interface MiddlewareManifest {
144-
version: number;
145-
sortedMiddleware: string[];
146-
middleware: {
147-
[page: string]: EdgeFunctionDefinition;
148-
};
149-
functions: {
150-
[page: string]: EdgeFunctionDefinition;
151-
};
152-
}

packages/@apphosting/adapter-nextjs/src/overrides.spec.ts

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,35 @@ describe("route overrides", () => {
5454
fs.readFileSync(routesManifestPath, "utf-8"),
5555
) as RoutesManifest;
5656

57-
assert.strictEqual(updatedManifest.headers.length, 2);
58-
assert.deepStrictEqual(updatedManifest.headers[0], initialManifest.headers[0]);
59-
60-
const firebaseHeaders = updatedManifest.headers[1];
61-
assert.strictEqual(firebaseHeaders.source, "/:path*");
62-
assert.strictEqual(firebaseHeaders.headers.length, 1);
63-
assert.strictEqual(firebaseHeaders.headers[0].key, "x-fah-adapter");
64-
assert.strictEqual(firebaseHeaders.headers[0].value, "nextjs-1.0.0");
57+
const expectedManifest: RoutesManifest = {
58+
version: 3,
59+
basePath: "",
60+
pages404: true,
61+
staticRoutes: [],
62+
dynamicRoutes: [],
63+
dataRoutes: [],
64+
redirects: [],
65+
rewrites: [],
66+
headers: [
67+
{
68+
source: "/existing",
69+
headers: [{ key: "X-Custom", value: "test" }],
70+
regex: "^/existing$",
71+
},
72+
{
73+
source: "/:path*",
74+
regex: "^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$",
75+
headers: [
76+
{
77+
key: "x-fah-adapter",
78+
value: "nextjs-1.0.0",
79+
},
80+
],
81+
},
82+
],
83+
};
84+
85+
assert.deepStrictEqual(updatedManifest, expectedManifest);
6586
});
6687

6788
it("should add middleware header when middleware exists", async () => {
@@ -79,7 +100,7 @@ describe("route overrides", () => {
79100
};
80101

81102
const middlewareManifest: MiddlewareManifest = {
82-
version: 1,
103+
version: 3,
83104
sortedMiddleware: ["/"],
84105
middleware: {
85106
"/": {
@@ -111,13 +132,31 @@ describe("route overrides", () => {
111132

112133
assert.strictEqual(updatedManifest.headers.length, 1);
113134

114-
const headers = updatedManifest.headers[0];
115-
assert.strictEqual(headers.source, "/:path*");
116-
assert.strictEqual(headers.headers.length, 2);
117-
assert.strictEqual(headers.headers[0].key, "x-fah-adapter");
118-
assert.strictEqual(headers.headers[0].value, "nextjs-1.0.0");
119-
assert.strictEqual(headers.headers[1].key, "x-fah-middleware");
120-
assert.strictEqual(headers.headers[1].value, "true");
135+
const expectedManifest: RoutesManifest = {
136+
version: 3,
137+
basePath: "",
138+
pages404: true,
139+
staticRoutes: [],
140+
dynamicRoutes: [],
141+
dataRoutes: [],
142+
rewrites: [],
143+
redirects: [],
144+
headers: [
145+
{
146+
source: "/:path*",
147+
regex: "^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$",
148+
headers: [
149+
{
150+
key: "x-fah-adapter",
151+
value: "nextjs-1.0.0",
152+
},
153+
{ key: "x-fah-middleware", value: "true" },
154+
],
155+
},
156+
],
157+
};
158+
159+
assert.deepStrictEqual(updatedManifest, expectedManifest);
121160
});
122161

123162
afterEach(() => {

packages/@apphosting/adapter-nextjs/src/overrides.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import { AdapterMetadata, MiddlewareManifest } from "./interfaces.js";
22
import { loadRouteManifest, writeRouteManifest, loadMiddlewareManifest } from "./utils.js";
33

44
/**
5-
* Adds the route overrides to the route manifest.
5+
* Modifies the app's route manifest (routes-manifest.json) to add Firebase App Hosting
6+
* specific overrides (i.e headers).
7+
*
8+
* This function adds the following headers to all routes:
9+
* - x-fah-adapter: The Firebase App Hosting adapter version used to build the app.
10+
* - x-fah-middleware: When middleware is enabled.
11+
*
612
* @param appPath The path to the app directory.
713
* @param distDir The path to the dist directory.
814
* @param adapterMetadata The adapter metadata.
@@ -30,6 +36,14 @@ export async function addRouteOverrides(
3036
]
3137
: []),
3238
],
39+
/*
40+
NextJs converts the source string to a regex using path-to-regexp (https://github.com/pillarjs/path-to-regexp) at
41+
build time: https://github.com/vercel/next.js/blob/canary/packages/next/src/build/index.ts#L1273.
42+
This regex is then used to match the route against the request path.
43+
44+
This regex was generated by building a sample NextJs app with the source string `/:path*` and then inspecting the
45+
routes-manifest.json file.
46+
*/
3347
regex: "^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$",
3448
});
3549

0 commit comments

Comments
 (0)