summaryrefslogtreecommitdiff
path: root/packages/integrations/netlify/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/netlify/src')
-rw-r--r--packages/integrations/netlify/src/integration-edge-functions.ts2
-rw-r--r--packages/integrations/netlify/src/integration-functions.ts2
-rw-r--r--packages/integrations/netlify/src/shared.ts116
3 files changed, 104 insertions, 16 deletions
diff --git a/packages/integrations/netlify/src/integration-edge-functions.ts b/packages/integrations/netlify/src/integration-edge-functions.ts
index d443e1c0b..0d036be93 100644
--- a/packages/integrations/netlify/src/integration-edge-functions.ts
+++ b/packages/integrations/netlify/src/integration-edge-functions.ts
@@ -163,7 +163,7 @@ export function netlifyEdgeFunctions({ dist }: NetlifyEdgeFunctionsOptions = {})
'astro:build:done': async ({ routes, dir }) => {
await bundleServerEntry(_buildConfig, _vite);
await createEdgeManifest(routes, entryFile, _config.root);
- await createRedirects(routes, dir, entryFile, true);
+ await createRedirects(_config, routes, dir, entryFile, true);
},
},
};
diff --git a/packages/integrations/netlify/src/integration-functions.ts b/packages/integrations/netlify/src/integration-functions.ts
index e8ff4bd1f..f75b6d1f8 100644
--- a/packages/integrations/netlify/src/integration-functions.ts
+++ b/packages/integrations/netlify/src/integration-functions.ts
@@ -48,7 +48,7 @@ function netlifyFunctions({
}
},
'astro:build:done': async ({ routes, dir }) => {
- await createRedirects(routes, dir, entryFile, false);
+ await createRedirects(_config, routes, dir, entryFile, false);
},
},
};
diff --git a/packages/integrations/netlify/src/shared.ts b/packages/integrations/netlify/src/shared.ts
index 2c648984a..c87d946f5 100644
--- a/packages/integrations/netlify/src/shared.ts
+++ b/packages/integrations/netlify/src/shared.ts
@@ -1,7 +1,16 @@
-import type { RouteData } from 'astro';
+import type { AstroConfig, RouteData } from 'astro';
import fs from 'fs';
+type RedirectDefinition = {
+ dynamic: boolean;
+ input: string;
+ target: string;
+ weight: 0 | 1;
+ status: 200 | 404;
+};
+
export async function createRedirects(
+ config: AstroConfig,
routes: RouteData[],
dir: URL,
entryFile: string,
@@ -10,37 +19,116 @@ export async function createRedirects(
const _redirectsURL = new URL('./_redirects', dir);
const kind = edge ? 'edge-functions' : 'functions';
- // Create the redirects file that is used for routing.
- let _redirects = '';
+ const definitions: RedirectDefinition[] = [];
+
for (const route of routes) {
if (route.pathname) {
if (route.distURL) {
- _redirects += `
- ${route.pathname} /${route.distURL.toString().replace(dir.toString(), '')} 200`;
+ definitions.push({
+ dynamic: false,
+ input: route.pathname,
+ target: prependForwardSlash(route.distURL.toString().replace(dir.toString(), '')),
+ status: 200,
+ weight: 1
+ });
} else {
- _redirects += `
- ${route.pathname} /.netlify/${kind}/${entryFile} 200`;
+ definitions.push({
+ dynamic: false,
+ input: route.pathname,
+ target: `/.netlify/${kind}/${entryFile}`,
+ status: 200,
+ weight: 1,
+ });
if (route.route === '/404') {
- _redirects += `
- /* /.netlify/${kind}/${entryFile} 404`;
+ definitions.push({
+ dynamic: true,
+ input: '/*',
+ target: `/.netlify/${kind}/${entryFile}`,
+ status: 404,
+ weight: 0
+ });
}
}
} else {
const pattern =
- '/' + route.segments.map(([part]) => (part.dynamic ? '*' : part.content)).join('/');
+ '/' + route.segments.map(([part]) => {
+ //(part.dynamic ? '*' : part.content)
+ if(part.dynamic) {
+ if(part.spread) {
+ return '*';
+ } else {
+ return ':' + part.content;
+ }
+ } else {
+ return part.content;
+ }
+ }).join('/');
+
if (route.distURL) {
- _redirects += `
- ${pattern} /${route.distURL.toString().replace(dir.toString(), '')} 200`;
+ const target = `${pattern}` + (config.build.format === 'directory' ? '/index.html' : '.html');
+ definitions.push({
+ dynamic: true,
+ input: pattern,
+ target,
+ status: 200,
+ weight: 1
+ });
} else {
- _redirects += `
- ${pattern} /.netlify/${kind}/${entryFile} 200`;
+ definitions.push({
+ dynamic: true,
+ input: pattern,
+ target: `/.netlify/${kind}/${entryFile}`,
+ status: 200,
+ weight: 1
+ });
}
}
}
+ let _redirects = prettify(definitions);
+
// Always use appendFile() because the redirects file could already exist,
// e.g. due to a `/public/_redirects` file that got copied to the output dir.
// If the file does not exist yet, appendFile() automatically creates it.
await fs.promises.appendFile(_redirectsURL, _redirects, 'utf-8');
}
+
+function prettify(definitions: RedirectDefinition[]) {
+ let minInputLength = 0, minTargetLength = 0;
+ definitions.sort((a, b) => {
+ // Find the longest input, so we can format things nicely
+ if(a.input.length > minInputLength) {
+ minInputLength = a.input.length;
+ }
+ if(b.input.length > minInputLength) {
+ minInputLength = b.input.length;
+ }
+
+ // Same for the target
+ if(a.target.length > minTargetLength) {
+ minTargetLength = a.target.length;
+ }
+ if(b.target.length > minTargetLength) {
+ minTargetLength = b.target.length;
+ }
+
+ // Sort dynamic routes on top
+ return b.weight - a.weight;
+ });
+
+ let _redirects = '';
+ // Loop over the definitions
+ definitions.forEach((defn, i) => {
+ // Figure out the number of spaces to add. We want at least 4 spaces
+ // after the input. This ensure that all targets line up together.
+ let inputSpaces = (minInputLength - defn.input.length) + 4;
+ let targetSpaces = (minTargetLength - defn.target.length) + 4;
+ _redirects += (i === 0 ? '' : '\n') + defn.input + ' '.repeat(inputSpaces) + defn.target + ' '.repeat(Math.abs(targetSpaces)) + defn.status;
+ });
+ return _redirects;
+}
+
+function prependForwardSlash(str: string) {
+ return str[0] === '/' ? str : '/' + str;
+}