diff --git a/app/robots.ts b/app/robots.ts index 41482c55da6..9dd25ad0814 100644 --- a/app/robots.ts +++ b/app/robots.ts @@ -1,18 +1,9 @@ import type { MetadataRoute } from "next" -import { SITE_URL } from "@/lib/constants" +import { IS_PRODUCTION_DEPLOY, SITE_URL } from "@/lib/constants" export default function robots(): MetadataRoute.Robots { - let hostname = "" - try { - hostname = new URL(SITE_URL).hostname - } catch (error) { - console.error("Error getting hostname", error) - } - - const isProduction = hostname === "ethereum.org" - - if (!isProduction) { + if (!IS_PRODUCTION_DEPLOY) { return { rules: [{ userAgent: "*", disallow: "/" }], sitemap: [], diff --git a/netlify.toml b/netlify.toml index 536b8948275..989cabe5b16 100644 --- a/netlify.toml +++ b/netlify.toml @@ -40,3 +40,11 @@ [functions] included_files = ["i18n.config.json", "src/intl/**/*", "src/data-layer/mocks/**/*"] + +# Override SITE_URL for named branches with custom subdomains so canonical +# URLs and OG metadata use the custom domain instead of *.netlify.app. +[context.dev.environment] + NEXT_PUBLIC_SITE_URL = "https://dev.ethereum.org" + +[context.staging.environment] + NEXT_PUBLIC_SITE_URL = "https://staging.ethereum.org" diff --git a/next.config.js b/next.config.js index bb6ef6dfcc9..f102893b170 100644 --- a/next.config.js +++ b/next.config.js @@ -35,9 +35,18 @@ module.exports = (phase, { defaultConfig }) => { ...defaultConfig, reactStrictMode: true, env: { - // Context is used to determine the environment for Sentry + // Netlify build-time vars inlined so they're available at SSR runtime. // ref. https://docs.netlify.com/configure-builds/environment-variables/#build-metadata NEXT_PUBLIC_CONTEXT: process.env.CONTEXT, + // Resolve site URL once at build time. NEXT_PUBLIC_SITE_URL (set in + // netlify.toml for dev/staging) takes precedence, then Netlify's + // deploy-specific URLs, falling back to the production domain. + NEXT_PUBLIC_SITE_URL: + process.env.NEXT_PUBLIC_SITE_URL || + process.env.DEPLOY_PRIME_URL || + process.env.DEPLOY_URL || + process.env.URL || + "https://ethereum.org", }, webpack: (config) => { config.module.rules.push({ diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 7a2e7cd4df7..5068bb7a207 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -24,13 +24,12 @@ export const LOCALES_CODES = BUILD_LOCALES ? BUILD_LOCALES.split(",") : i18nConfig.map(({ code }) => code) -// Site urls - auto-detect from Netlify deploy context +// Site URL - resolved at build time in next.config.js from Netlify deploy context export const SITE_URL = - process.env.NEXT_PUBLIC_SITE_URL || - process.env.DEPLOY_PRIME_URL || // Branch/PR deploys - process.env.DEPLOY_URL || // Unique deploy URL - process.env.URL || // Primary site URL - "https://ethereum.org" + process.env.NEXT_PUBLIC_SITE_URL || "https://ethereum.org" + +export const IS_PRODUCTION_DEPLOY = + process.env.NEXT_PUBLIC_CONTEXT === "production" export const DISCORD_PATH = "https://discord.gg/ethereum-org/" export const ENTERPRISE_ETHEREUM_URL = "https://institutions.ethereum.org/" export const GITHUB_REPO_URL = diff --git a/src/lib/utils/metadata.ts b/src/lib/utils/metadata.ts index ebc12e94c64..89ebc04740f 100644 --- a/src/lib/utils/metadata.ts +++ b/src/lib/utils/metadata.ts @@ -1,7 +1,11 @@ import type { Metadata } from "next" import { getTranslations } from "next-intl/server" -import { DEFAULT_OG_IMAGE, SITE_URL } from "@/lib/constants" +import { + DEFAULT_OG_IMAGE, + IS_PRODUCTION_DEPLOY, + SITE_URL, +} from "@/lib/constants" import { getTranslatedLocales } from "../i18n/translationRegistry" @@ -9,6 +13,7 @@ import { isLocaleValidISO639_1 } from "./translations" import { getFullUrl } from "./url" import { routing } from "@/i18n/routing" + /** * List of default og images for different sections */ @@ -136,7 +141,7 @@ export const getMetadata = async ({ }, } - if (SITE_URL !== "https://ethereum.org") { + if (!IS_PRODUCTION_DEPLOY) { return { ...base, robots: { index: false, follow: false } } }