Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write index routes as index.html with build.format: 'file' #9209

Closed
wants to merge 4 commits into from
Closed
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
11 changes: 11 additions & 0 deletions .changeset/tame-flies-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'astro': major
---

build.format: 'file' now honors index routes

Prior to Astro 4, using `build.format: 'file'`, a method to produce HTML files that are *not* all within folders, would only produce `index.html` for the base path of `/`. This meant that even if you created explicit index pages with, for example, `page/index.astro`, it would write these out as `page.html`.

This was unexpected behavior as `build.format: 'file'` is intended to match the file system routing exactly. Now in Astro 4 it does, with index routes being written just as they are in your source directly. `page/index.astro` becomes `page/index.html`.

This change only affects SSG when using `build.format: 'file'`.
1 change: 1 addition & 0 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2363,6 +2363,7 @@ export interface RouteData {
redirect?: RedirectConfig;
redirectRoute?: RouteData;
fallbackRoutes: RouteData[];
index: boolean;
}

export type RedirectRouteData = RouteData & {
Expand Down
28 changes: 21 additions & 7 deletions packages/astro/src/core/build/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import npath from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import type { AstroConfig, RouteType } from '../../@types/astro.js';
import type { AstroConfig, RouteData } from '../../@types/astro.js';
import { appendForwardSlash } from '../../core/path.js';

const STATUS_CODE_PAGES = new Set(['/404', '/500']);
Expand All @@ -17,9 +17,10 @@ function getOutRoot(astroConfig: AstroConfig): URL {
export function getOutFolder(
astroConfig: AstroConfig,
pathname: string,
routeType: RouteType
routeData: RouteData
): URL {
const outRoot = getOutRoot(astroConfig);
const routeType = routeData.type;

// This is the root folder to write to.
switch (routeType) {
Expand All @@ -36,8 +37,15 @@ export function getOutFolder(
return new URL('.' + appendForwardSlash(pathname), outRoot);
}
case 'file': {
const d = pathname === '' ? pathname : npath.dirname(pathname);
return new URL('.' + appendForwardSlash(d), outRoot);
let dir;
// If the pathname is '' then this is the root index.html
// If this is an index route, the folder should be the pathname, not the parent
if(pathname === '' || routeData.index) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Maybe we could omit the check for an empty pathname since, in this scenario, it's guaranteed to represent an index route, isn't it?

dir = pathname;
} else {
dir = npath.dirname(pathname);
}
return new URL('.' + appendForwardSlash(dir), outRoot);
}
}
}
Expand All @@ -47,8 +55,9 @@ export function getOutFile(
astroConfig: AstroConfig,
outFolder: URL,
pathname: string,
routeType: RouteType
routeData: RouteData
): URL {
const routeType = routeData.type;
switch (routeType) {
case 'endpoint':
return new URL(npath.basename(pathname), outFolder);
Expand All @@ -64,8 +73,13 @@ export function getOutFile(
return new URL('./index.html', outFolder);
}
case 'file': {
const baseName = npath.basename(pathname);
return new URL('./' + (baseName || 'index') + '.html', outFolder);
let baseName = npath.basename(pathname);
// If there is no base name this is the root route.
// If this is an index route, the name should be `index.html`.
if(!baseName || routeData.index) {
baseName = 'index';
}
return new URL(`./${baseName}.html`, outFolder);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,8 +601,8 @@ async function generatePath(pathname: string, gopts: GeneratePathOptions, pipeli
body = Buffer.from(await response.arrayBuffer());
}

const outFolder = getOutFolder(pipeline.getConfig(), pathname, route.type);
const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, route.type);
const outFolder = getOutFolder(pipeline.getConfig(), pathname, route);
const outFile = getOutFile(pipeline.getConfig(), outFolder, pathname, route);
route.distURL = outFile;

await fs.promises.mkdir(outFolder, { recursive: true });
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/build/plugins/plugin-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ function buildManifest(
if (!route.prerender) continue;
if (!route.pathname) continue;

const outFolder = getOutFolder(opts.settings.config, route.pathname, route.type);
const outFile = getOutFile(opts.settings.config, outFolder, route.pathname, route.type);
const outFolder = getOutFolder(opts.settings.config, route.pathname, route);
const outFile = getOutFile(opts.settings.config, outFolder, route.pathname, route);
const file = outFile.toString().replace(opts.settings.config.build.client.toString(), '');
routes.push({
file,
Expand Down
3 changes: 3 additions & 0 deletions packages/astro/src/core/routing/manifest/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ export function createRouteManifest(
generate,
pathname: pathname || undefined,
prerender,
index: item.isIndex,
fallbackRoutes: [],
});
}
Expand Down Expand Up @@ -424,6 +425,7 @@ export function createRouteManifest(
pathname: pathname || void 0,
prerender: prerenderInjected ?? prerender,
fallbackRoutes: [],
index: false,
});
});

Expand Down Expand Up @@ -464,6 +466,7 @@ export function createRouteManifest(
redirect: to,
redirectRoute: routes.find((r) => r.route === to),
fallbackRoutes: [],
index: false,
};

const lastSegmentIsDynamic = (r: RouteData) => !!r.segments.at(-1)?.at(-1)?.dynamic;
Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/core/routing/manifest/serialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ export function deserializeRouteData(rawRouteData: SerializedRouteData): RouteDa
fallbackRoutes: rawRouteData.fallbackRoutes.map((fallback) => {
return deserializeRouteData(fallback);
}),
index: rawRouteData.index,
};
}
1 change: 1 addition & 0 deletions packages/astro/src/vite-plugin-astro-server/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ export async function handleRoute({
type: 'fallback',
route: '',
fallbackRoutes: [],
index: false,
};
renderContext = await createRenderContext({
request,
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/test/astro-pageDirectoryUrl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('build format', () => {

it('outputs', async () => {
expect(await fixture.readFile('/client.html')).to.be.ok;
expect(await fixture.readFile('/nested-md.html')).to.be.ok;
expect(await fixture.readFile('/nested-astro.html')).to.be.ok;
expect(await fixture.readFile('/nested-md/index.html')).to.be.ok;
expect(await fixture.readFile('/nested-astro/index.html')).to.be.ok;
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
<title>Testing</title>
</head>
<body>
<h1>Testing</h1>
</body>
</html>
6 changes: 6 additions & 0 deletions packages/astro/test/page-format.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ describe('build.format', () => {
let $ = cheerio.load(html);
expect($('#another').attr('href')).to.equal('/nested/another/');
});

it('index files are written as index.html', async () => {
let html = await fixture.readFile('/nested/index.html');
let $ = cheerio.load(html);
expect($('h1').text()).to.equal('Testing');
});
});
});
});
Loading