diff --git a/gatsby-browser.tsx b/gatsby-browser.tsx index 1bbf32be586..97e54987d74 100644 --- a/gatsby-browser.tsx +++ b/gatsby-browser.tsx @@ -22,6 +22,7 @@ import { defaultLanguage, isLang, } from "./src/utils/languages" +import { IS_DEV } from "./src/utils/env" import { Context } from "./src/types" // Default languages included: @@ -42,7 +43,7 @@ export const wrapPageElement: GatsbyBrowser< // client side redirect on paths that don't have a locale in them. Most useful // on dev env where we don't have server redirects - if (!isLang(pathLocale)) { + if (IS_DEV && !isLang(pathLocale)) { let detected = window.localStorage.getItem("eth-org-language") || browserLang({ diff --git a/gatsby-config.ts b/gatsby-config.ts index dc347f2a265..df51dfec412 100644 --- a/gatsby-config.ts +++ b/gatsby-config.ts @@ -230,9 +230,19 @@ const config: GatsbyConfig = { }, }, // Needed for Gatsby Cloud redirect support - `gatsby-plugin-gatsby-cloud`, + { + resolve: `gatsby-plugin-gatsby-cloud`, + options: { + generateMatchPathRewrites: false, + }, + }, // Creates `_redirects` & `_headers` build files for Netlify - `gatsby-plugin-netlify`, + { + resolve: `gatsby-plugin-netlify`, + options: { + generateMatchPathRewrites: false, + }, + }, ], // https://www.gatsbyjs.com/docs/reference/release-notes/v2.28/#feature-flags-in-gatsby-configjs flags: { diff --git a/gatsby-node.ts b/gatsby-node.ts index 0e5dd4ce4f3..b0f63e1f29a 100644 --- a/gatsby-node.ts +++ b/gatsby-node.ts @@ -23,6 +23,12 @@ import redirects from "./redirects.json" const exec = util.promisify(child_process.exec) +const commonRedirectProps = { + isPermanent: true, + ignoreCase: true, + force: true, +} + /** * Markdown isOutdated check * Parse header ids in markdown file (both translated and english) and compare their info structure. @@ -190,13 +196,11 @@ export const createPages: GatsbyNode["createPages"] = async ({ }) => { const { createPage, createRedirect } = actions - // server side redirects + // custom redirects defined in `redirects.json` redirects.forEach((redirect) => { createRedirect({ + ...commonRedirectProps, ...redirect, - isPermanent: true, - ignoreCase: true, - force: true, }) }) @@ -260,6 +264,12 @@ export const createPages: GatsbyNode["createPages"] = async ({ // e.g. English file: "src/content/community/index.md" // e.g. corresponding German file: "src/content/translations/de/community/index.md" if (language === defaultLanguage) { + createRedirect({ + ...commonRedirectProps, + fromPath: slug.slice(3), + toPath: slug, + }) + for (const lang of supportedLanguages) { const splitPath = relativePath.split("/") splitPath.splice(2, 0, `translations/${lang}`) @@ -315,6 +325,14 @@ export const createPages: GatsbyNode["createPages"] = async ({ // we can remove this logic and the `/pages-conditional/` directory. const outdatedMarkdown = [`eth`, `dapps`, `wallets`, `what-is-ethereum`] outdatedMarkdown.forEach((page) => { + const originalPath = `/${page}/` + + createRedirect({ + ...commonRedirectProps, + fromPath: originalPath, + toPath: `/${defaultLanguage}${originalPath}`, + }) + supportedLanguages.forEach(async (lang) => { const markdownPath = path.resolve( `src/content/translations/${lang}/${page}/index.md` @@ -326,7 +344,7 @@ export const createPages: GatsbyNode["createPages"] = async ({ page, lang ) - const originalPath = `/${page}/` + const slug = `/${lang}${originalPath}` createPage({ @@ -356,14 +374,29 @@ export const onCreatePage: GatsbyNode["onCreatePage"] = async ({ page, actions, }) => { - const { createPage, deletePage } = actions + const { createPage, deletePage, createRedirect } = actions - // create routes without the lang prefix e.g. `/{path}` as our i18n plugin - // only creates `/{lang}/{path}` routes. This is useful on dev env to avoid - // getting a 404 since we don't have server side redirects - if (IS_DEV && page.path.startsWith(`/${defaultLanguage}`)) { + const isDefaultLang = page.path.startsWith(`/${defaultLanguage}`) + + if (isDefaultLang) { const path = page.path.slice(3) - createPage({ ...page, path }) + + if (IS_DEV) { + // create routes without the lang prefix e.g. `/{path}` as our i18n plugin + // only creates `/{lang}/{path}` routes. This is useful on dev env to avoid + // getting a 404 since we don't have server side redirects + createPage({ ...page, path }) + } + + if (!IS_DEV && !path.match(/^\/404(\/|.html)$/)) { + // on prod, indicate our servers to redirect the root paths to the + // `/{defaultLang}/{path}` + createRedirect({ + ...commonRedirectProps, + fromPath: path, + toPath: page.path, + }) + } } const isTranslated = page.context.locale !== defaultLanguage @@ -387,6 +420,20 @@ export const onCreatePage: GatsbyNode["onCreatePage"] = async ({ } } +export const onPostBootstrap: GatsbyNode["onPostBootstrap"] = ({ actions }) => { + const { createRedirect } = actions + + supportedLanguages.forEach((lang) => { + createRedirect({ + ...commonRedirectProps, + fromPath: `/${lang}/*`, + toPath: `/${lang}/404`, + statusCode: 404, + force: false, + }) + }) +} + export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] = ({ actions, schema }) => { const { createTypes } = actions diff --git a/redirects.json b/redirects.json index 09c65ee3256..065fbc836a3 100644 --- a/redirects.json +++ b/redirects.json @@ -47,94 +47,14 @@ "fromPath": "/beginners", "toPath": "/en/what-is-ethereum/" }, - { - "fromPath": "/", - "toPath": "/en/" - }, - { - "fromPath": "/what-is-ethereum/", - "toPath": "/en/what-is-ethereum/" - }, - { - "fromPath": "/eth/", - "toPath": "/en/eth/" - }, - { - "fromPath": "/dapps/", - "toPath": "/en/dapps/" - }, - { - "fromPath": "/wallets/", - "toPath": "/en/wallets/" - }, { "fromPath": "/eth2/", "toPath": "/en/upgrades/" }, - { - "fromPath": "/upgrades/", - "toPath": "/en/upgrades/" - }, - { - "fromPath": "/staking/", - "toPath": "/en/staking/" - }, - { - "fromPath": "/learn/", - "toPath": "/en/learn/" - }, - { - "fromPath": "/community/", - "toPath": "/en/community/" - }, { "fromPath": "/build/", "toPath": "/en/developers/learning-tools/" }, - { - "fromPath": "/developers/", - "toPath": "/en/developers/" - }, - { - "fromPath": "/enterprise/", - "toPath": "/en/enterprise/" - }, - { - "fromPath": "/whitepaper/", - "toPath": "/en/whitepaper/" - }, - { - "fromPath": "/foundation/", - "toPath": "/en/foundation/" - }, - { - "fromPath": "/eips/", - "toPath": "/en/eips/" - }, - { - "fromPath": "/about/", - "toPath": "/en/about/" - }, - { - "fromPath": "/privacy-policy/", - "toPath": "/en/privacy-policy/" - }, - { - "fromPath": "/terms-of-use/", - "toPath": "/en/terms-of-use/" - }, - { - "fromPath": "/cookie-policy/", - "toPath": "/en/cookie-policy/" - }, - { - "fromPath": "/languages/", - "toPath": "/en/languages/" - }, - { - "fromPath": "/enterprise/", - "toPath": "/en/enterprise/" - }, { "fromPath": "/java/", "toPath": "/en/developers/docs/programming-languages/java/" @@ -167,26 +87,14 @@ "fromPath": "/dart/", "toPath": "/en/developers/docs/programming-languages/dart/" }, - { - "fromPath": "/nft/", - "toPath": "/en/nft/" - }, { "fromPath": "/nfts/", "toPath": "/en/nft/" }, - { - "fromPath": "/dao/", - "toPath": "/en/dao/" - }, { "fromPath": "/daos/", "toPath": "/en/dao/" }, - { - "fromPath": "/defi/", - "toPath": "/en/defi/" - }, { "fromPath": "/layer2/", "toPath": "/en/layer-2/"