Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/@google-cloud/adapter-nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Runs only during `phase-production-build`:
- **Standalone output**: Sets `output: 'standalone'` when `config.output` is unset (preserves `output: 'export'` and explicit `output: 'standalone'`).
- **Build cache**: Always sets `experimental.turbopackFileSystemCacheForBuild = false`. Cloud Run never restores `.next/cache`, so this avoids ~48 MiB of unused cache in container layers.
- **Image optimization**: Sets `images.unoptimized: true`, so Next.js image optimization is off by default. Apps with a custom image loader, and builds that set `GOOGLE_NEXTJS_IMAGE_OPTIMIZATION=true`, keep it on. See [Image Optimization](#image-optimization).
- **Browser source maps**: Always sets `productionBrowserSourceMaps: true` when `CRASHLYTICS_UPLOAD_MAPPING=true` (or `"1"`), regardless of any user value in `next.config`.
- **Browser source maps**: Never changes `productionBrowserSourceMaps`. `CRASHLYTICS_UPLOAD_MAPPING=true` (or `"1"`) is ignored for now and logs a warning: Crashlytics source-map upload isn't available on Cloud Run yet, and turning on browser source maps would serve the app's source publicly from `/_next/static`.

### `onBuildComplete(ctx)`

Expand Down Expand Up @@ -102,7 +102,7 @@ outputFiles:
| :--------------------------------- | :------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NEXT_ADAPTER_PATH` | Build (`next build`) | Absolute path to `@google-cloud/adapter-nextjs` (`dist/index.js`) used by Next.js to load the adapter. |
| `NEXT_PRIVATE_OUTPUT_TRACE_ROOT` | Build (`next build`) | Repository/workspace root (`/workspace` on Cloud Run). Used as `repoRoot` for relative paths and `.cloudrun/` output placement. |
| `CRASHLYTICS_UPLOAD_MAPPING` | Build (`next build`) | When set to `"true"` (or `"1"`), sets `productionBrowserSourceMaps: true` in `next.config`. |
| `CRASHLYTICS_UPLOAD_MAPPING` | Build (`next build`) | Ignored for now (logs a warning). It doesn't turn on `productionBrowserSourceMaps`; see **Browser source maps** above. |
| `GOOGLE_NEXTJS_IMAGE_OPTIMIZATION` | Build (`next build`) | When set to `"true"` (or `"1"`), keeps Next.js image optimization on instead of setting `images.unoptimized: true`. See [Image Optimization](#image-optimization). |
| `PORT` | Runtime (`serve.js`) | HTTP port for the server. Cloud Run always sets it; defaults to `3000` when unset. |
| `KEEP_ALIVE_TIMEOUT` | Runtime (`serve.js`) | Optional HTTP server `keepAliveTimeout` in milliseconds. |
42 changes: 33 additions & 9 deletions packages/@google-cloud/adapter-nextjs/src/adapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,18 +256,42 @@ describe("@google-cloud/adapter-nextjs", () => {
assert.ok(infoLogs.some((l) => l.includes('already has output: "standalone"; preserving')));
});

it("enables productionBrowserSourceMaps only when CRASHLYTICS_UPLOAD_MAPPING=true", () => {
process.env.CRASHLYTICS_UPLOAD_MAPPING = "true";
const inputConfig = deepFreeze({});
const result = modifyConfig(inputConfig, {
it("ignores CRASHLYTICS_UPLOAD_MAPPING and never changes productionBrowserSourceMaps", () => {
const ctx: ModifyConfigContext = {
phase: "phase-production-build",
nextVersion: "16.4.3",
projectDir: tempDir,
});
assert.strictEqual(result.productionBrowserSourceMaps, true);
assert.ok(
infoLogs.some((l) => l.includes("Enabling NextConfig productionBrowserSourceMaps=true")),
);
};
const ignoredLogs = (): string[] =>
warnLogs.filter((w) => w.includes("Ignoring CRASHLYTICS_UPLOAD_MAPPING=true"));

for (const value of ["true", "1"]) {
process.env.CRASHLYTICS_UPLOAD_MAPPING = value;
warnLogs = [];
const result = modifyConfig<NextConfig>(deepFreeze({}), ctx);
assert.strictEqual(result.productionBrowserSourceMaps, undefined);
assert.strictEqual(ignoredLogs().length, 1);
assert.ok(ignoredLogs()[0].includes("would serve the app's source publicly"));
}
Comment on lines +265 to +275

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the test assertions to match the dynamic warning message and verify that the actual value of CRASHLYTICS_UPLOAD_MAPPING is correctly reflected in the logs.

      const ignoredLogs = (): string[] =>\n        warnLogs.filter((w) => w.includes("Ignoring CRASHLYTICS_UPLOAD_MAPPING"));\n\n      for (const value of ["true", "1"]) {\n        process.env.CRASHLYTICS_UPLOAD_MAPPING = value;\n        warnLogs = [];\n        const result = modifyConfig<NextConfig>(deepFreeze({}), ctx);\n        assert.strictEqual(result.productionBrowserSourceMaps, undefined);\n        assert.strictEqual(ignoredLogs().length, 1);\n        assert.ok(ignoredLogs()[0].includes("Ignoring CRASHLYTICS_UPLOAD_MAPPING=" + value));\n        assert.ok(ignoredLogs()[0].includes("would serve the app's source publicly"));\n      }


// A user's own setting is left as is, whether or not the env var is set.
for (const userValue of [true, false]) {
for (const envValue of ["true", undefined]) {
if (envValue === undefined) {
delete process.env.CRASHLYTICS_UPLOAD_MAPPING;
} else {
process.env.CRASHLYTICS_UPLOAD_MAPPING = envValue;
}
const result = modifyConfig(deepFreeze({ productionBrowserSourceMaps: userValue }), ctx);
assert.strictEqual(result.productionBrowserSourceMaps, userValue);
}
}

warnLogs = [];
delete process.env.CRASHLYTICS_UPLOAD_MAPPING;
modifyConfig(deepFreeze({}), ctx);
assert.strictEqual(ignoredLogs().length, 0);
assert.ok(!infoLogs.some((l) => l.includes("productionBrowserSourceMaps")));
});

it("logs security warnings for 16.3.5 and 16.3.7 without blocking", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ function isEnvFlagEnabled(name: string): boolean {
* - Sets `images.unoptimized: true` (image optimization off by default) unless the config uses a
* custom image loader (`images.loader` / `images.loaderFile`) or
* `GOOGLE_NEXTJS_IMAGE_OPTIMIZATION=true`, and logs which case applied.
* - Enables `productionBrowserSourceMaps: true` only when `CRASHLYTICS_UPLOAD_MAPPING=true`.
* - Never changes `productionBrowserSourceMaps`. `CRASHLYTICS_UPLOAD_MAPPING=true` is ignored with a
* warning until Crashlytics source-map upload is available on Cloud Run.
* - Never mutates the input `config` object in place, and never throws.
*/
export function modifyConfig<T extends NextConfig = NextConfig>(
Expand Down Expand Up @@ -137,18 +138,14 @@ export function modifyConfig<T extends NextConfig = NextConfig>(
);
}

// TODO(b/578288818): Turn productionBrowserSourceMaps back on for CRASHLYTICS_UPLOAD_MAPPING once
// the Cloud Run source-map buildpack uploads and strips the maps (e.g. only when a build signal
// says the uploader will run). Until then, enabling them would serve the app's source publicly
// from /_next/static, so the env var is ignored and a user's own setting is left as is.
if (isEnvFlagEnabled("CRASHLYTICS_UPLOAD_MAPPING")) {
if (config.productionBrowserSourceMaps !== true) {
const target = ensureCopy();
target.productionBrowserSourceMaps = true;
console.log(
"[adapter-nextjs] Enabling NextConfig productionBrowserSourceMaps=true because CRASHLYTICS_UPLOAD_MAPPING=true.",
);
} else {
console.log(
"[adapter-nextjs] NextConfig productionBrowserSourceMaps is already true (CRASHLYTICS_UPLOAD_MAPPING=true).",
);
}
console.warn(
"[adapter-nextjs] Warning: Ignoring CRASHLYTICS_UPLOAD_MAPPING=true: Crashlytics source-map upload isn't available on Cloud Run yet, and enabling browser source maps would serve the app's source publicly. NextConfig productionBrowserSourceMaps is left unchanged.",
);
Comment on lines +146 to +148

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When CRASHLYTICS_UPLOAD_MAPPING is set to "1", the warning message still hardcodes CRASHLYTICS_UPLOAD_MAPPING=true, which can be confusing to users who configured it with "1".\n\nConsider dynamically including the actual value of the environment variable in the warning message to improve clarity.

      console.warn(\n        "[adapter-nextjs] Warning: Ignoring CRASHLYTICS_UPLOAD_MAPPING=" + process.env.CRASHLYTICS_UPLOAD_MAPPING + ": Crashlytics source-map upload isn't available on Cloud Run yet, and enabling browser source maps would serve the app's source publicly. NextConfig productionBrowserSourceMaps is left unchanged."\n      );

}

return modified ?? config;
Expand Down
Loading