diff --git a/apps/cms/gatsby-node.mjs b/apps/cms/gatsby-node.mjs index 02e0027ff..cc024b3c4 100644 --- a/apps/cms/gatsby-node.mjs +++ b/apps/cms/gatsby-node.mjs @@ -38,12 +38,21 @@ export const createPages = async ({ actions }) => { }); // Proxy Drupal webforms. + const netlifyUrl = new URL( + process.env.NETLIFY_URL || 'http://127.0.0.1:8000', + ); Object.values(Locale).forEach((locale) => { - actions.createRedirect({ - fromPath: `/${locale}/form/*`, - toPath: `${process.env.GATSBY_DRUPAL_URL}/${locale}/form/:splat`, - statusCode: 200, - }); + global.netlifyTomlParts.push(` + [[redirects]] + from = "/${locale}/form/*" + to = "${process.env.GATSBY_DRUPAL_URL}/${locale}/form/:splat" + status = 200 + force = true + [redirects.headers] + SLB-Forwarded-Proto = "${netlifyUrl.protocol.slice(0, -1)}" + SLB-Forwarded-Host = "${netlifyUrl.host}" + SLB-Forwarded-Port = "${netlifyUrl.port}" + `); }); // Additionally proxy themes and modules as they can have additional diff --git a/apps/website/.gitignore b/apps/website/.gitignore index 1cf0b3875..366977664 100644 --- a/apps/website/.gitignore +++ b/apps/website/.gitignore @@ -8,3 +8,6 @@ persisted-store # Deno comes with "netlify dev". We don't need its lock file. /deno.lock + +# Created by gatsby-node.mjs +netlify.toml diff --git a/apps/website/gatsby-node.mjs b/apps/website/gatsby-node.mjs index ffce8e751..67ea7a871 100644 --- a/apps/website/gatsby-node.mjs +++ b/apps/website/gatsby-node.mjs @@ -5,8 +5,12 @@ import { Locale, NotFoundPageQuery, } from '@custom/schema'; +import fs from 'fs'; import { resolve } from 'path'; +// @ts-expect-error Not typed. +global.netlifyTomlParts ??= []; + /** * @type {import('gatsby').GatsbyNode['onCreateWebpackConfig']} */ @@ -109,9 +113,56 @@ export const createPages = async ({ actions }) => { // Any unhandled requests are handed to strangler, which will try to pass // them to all registered legacy systems and return 404 if none of them // respond. - actions.createRedirect({ - fromPath: '/*', - toPath: `/.netlify/functions/strangler`, - statusCode: 200, - }); + // We put it into netlify.toml because it should be really the last one. + // See https://docs.netlify.com/routing/redirects/#rule-processing-order + // @ts-expect-error Not typed. + global.netlifyTomlParts.push(` + [[redirects]] + from = "/*" + to = "/.netlify/functions/strangler" + status = 200 + `); +}; + +/** + * @type {import('gatsby').GatsbyNode['onPostBuild']} + */ +export const onPostBuild = async () => { + prepareNetlifyToml(); }; + +/** + * @returns {void} + */ +function prepareNetlifyToml() { + const netlifyTomlBase = fs + .readFileSync(resolve('./netlify-base.toml'), 'utf8') + .trim(); + /** @type {Array} */ + const netlifyTomlParts = + // @ts-expect-error Not typed. + global.netlifyTomlParts; + fs.writeFileSync( + resolve('./netlify.toml'), + [netlifyTomlBase] + .concat(netlifyTomlParts.map(removeIndentation)) + .join('\n\n'), + ); +} + +/** + * @param {string} str + * @returns {string} + */ +function removeIndentation(str) { + const lines = str.split('\n'); + const minIndent = Math.min( + ...lines + .filter((line) => line.trim().length > 0) + .map((line) => (line.match(/^\s*/) || [''])[0].length), + ); + return lines + .map((line) => line.slice(minIndent)) + .join('\n') + .trim(); +} diff --git a/apps/website/netlify.toml b/apps/website/netlify-base.toml similarity index 100% rename from apps/website/netlify.toml rename to apps/website/netlify-base.toml