From 49872182cec51bfdba245089e7d8929086beaadb Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Tue, 28 Nov 2023 08:23:06 -0500 Subject: [PATCH 1/8] Implements build.format: 'preserve' --- .changeset/tame-flies-confess.md | 14 ++++++ packages/astro/src/@types/astro.ts | 6 ++- packages/astro/src/core/app/types.ts | 2 +- packages/astro/src/core/build/common.ts | 28 +++++++++-- packages/astro/src/core/build/generate.ts | 6 +-- .../src/core/build/plugins/plugin-manifest.ts | 4 +- packages/astro/src/core/build/util.ts | 1 + packages/astro/src/core/config/schema.ts | 4 +- .../astro/src/core/routing/manifest/create.ts | 18 +++---- .../core/routing/manifest/serialization.ts | 1 + .../src/vite-plugin-astro-server/route.ts | 1 + .../astro/test/astro-pageDirectoryUrl.test.js | 48 ++++++++++++++----- .../page-format/src/pages/nested/index.astro | 8 ++++ packages/astro/test/page-format.test.js | 6 +++ 14 files changed, 111 insertions(+), 36 deletions(-) create mode 100644 .changeset/tame-flies-confess.md create mode 100644 packages/astro/test/fixtures/page-format/src/pages/nested/index.astro diff --git a/.changeset/tame-flies-confess.md b/.changeset/tame-flies-confess.md new file mode 100644 index 000000000000..b096ac8458cd --- /dev/null +++ b/.changeset/tame-flies-confess.md @@ -0,0 +1,14 @@ +--- +'astro': minor +--- + +build.format: 'preserve' to preserve source structure in final build + +Using `build.format: 'file'`, a method to produce HTML files that are *not* all within folders, it will only produce `index.html` for the base path of `/`. This meant that even if you create explicit index pages with, for example, `page/index.astro`, it would write these out as `page.html`. + +This is a bit unexpected, but rather than make a breaking change to `build.format: 'file'` we decided to create a new `build.format: 'preserve'`. + +The new format will preserve how the filesystem is structured and make sure that is mirrored over to production. Using this option: + +- `page.astro` becomes `page.html` +- `page/index.astro` becomes `page/index.html` diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 49d3ab991305..114c495a5b6c 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -733,12 +733,13 @@ export interface AstroUserConfig { * Control the output file format of each page. This value may be set by an adapter for you. * - If `'file'`, Astro will generate an HTML file (ex: "/foo.html") for each page. * - If `'directory'`, Astro will generate a directory with a nested `index.html` file (ex: "/foo/index.html") for each page. + * - If `'preserve'`, Astro will generate HTML files exactly as they appear in your source folder (ex: "foo/index.astro" becomes "foo/index.html" but "foo.astro" does not) * * ```js * { * build: { * // Example: Generate `page.html` instead of `page/index.html` during build. - * format: 'file' + * format: 'preserve' * } * } * ``` @@ -756,7 +757,7 @@ export interface AstroUserConfig { * - `directory` - Set `trailingSlash: 'always'` * - `file` - Set `trailingSlash: 'never'` */ - format?: 'file' | 'directory'; + format?: 'file' | 'directory' | 'preserve'; /** * @docs * @name build.client @@ -2553,6 +2554,7 @@ export interface RouteData { redirect?: RedirectConfig; redirectRoute?: RouteData; fallbackRoutes: RouteData[]; + isIndex: boolean; } export type RedirectRouteData = RouteData & { diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts index b38f51d64f72..d479bb3f0c13 100644 --- a/packages/astro/src/core/app/types.ts +++ b/packages/astro/src/core/app/types.ts @@ -40,7 +40,7 @@ export type SSRManifest = { site?: string; base: string; trailingSlash: 'always' | 'never' | 'ignore'; - buildFormat: 'file' | 'directory'; + buildFormat: 'file' | 'directory' | 'preserve'; compressHTML: boolean; assetsPrefix?: string; renderers: SSRLoadedRenderer[]; diff --git a/packages/astro/src/core/build/common.ts b/packages/astro/src/core/build/common.ts index e7efc6439e4e..daa719a3e089 100644 --- a/packages/astro/src/core/build/common.ts +++ b/packages/astro/src/core/build/common.ts @@ -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']); @@ -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) { @@ -39,6 +40,17 @@ export function getOutFolder( const d = pathname === '' ? pathname : npath.dirname(pathname); return new URL('.' + appendForwardSlash(d), outRoot); } + case 'preserve': { + 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.isIndex) { + dir = pathname; + } else { + dir = npath.dirname(pathname); + } + return new URL('.' + appendForwardSlash(dir), outRoot); + } } } } @@ -47,8 +59,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); @@ -67,6 +80,15 @@ export function getOutFile( const baseName = npath.basename(pathname); return new URL('./' + (baseName || 'index') + '.html', outFolder); } + case 'preserve': { + 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.isIndex) { + baseName = 'index'; + } + return new URL(`./${baseName}.html`, outFolder); + } } } } diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index a7f6425cd7e2..fa1d595d2d87 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -448,7 +448,7 @@ function getUrlForPath( pathname: string, base: string, origin: string, - format: 'directory' | 'file', + format: 'directory' | 'file' | 'preserve', routeType: RouteType ): URL { /** @@ -601,8 +601,8 @@ async function generatePath( 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 }); diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index 09408e23af36..80c57e62340b 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -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, diff --git a/packages/astro/src/core/build/util.ts b/packages/astro/src/core/build/util.ts index fde296a6d246..96a5ec2f2888 100644 --- a/packages/astro/src/core/build/util.ts +++ b/packages/astro/src/core/build/util.ts @@ -23,6 +23,7 @@ export function shouldAppendForwardSlash( switch (buildFormat) { case 'directory': return true; + case 'preserve': case 'file': return false; } diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 655db8ed8f5f..434b7d4f713e 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -123,7 +123,7 @@ export const AstroConfigSchema = z.object({ build: z .object({ format: z - .union([z.literal('file'), z.literal('directory')]) + .union([z.literal('file'), z.literal('directory'), z.literal('preserve')]) .optional() .default(ASTRO_CONFIG_DEFAULTS.build.format), client: z @@ -464,7 +464,7 @@ export function createRelativeSchema(cmd: string, fileProtocolRoot: string) { build: z .object({ format: z - .union([z.literal('file'), z.literal('directory')]) + .union([z.literal('file'), z.literal('directory'), z.literal('preserve')]) .optional() .default(ASTRO_CONFIG_DEFAULTS.build.format), client: z diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index 6ab297a5ee22..9b3d69cefc2a 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -33,10 +33,6 @@ interface Item { routeSuffix: string; } -interface ManifestRouteData extends RouteData { - isIndex: boolean; -} - function countOccurrences(needle: string, haystack: string) { let count = 0; for (const hay of haystack) { @@ -193,7 +189,7 @@ function isSemanticallyEqualSegment(segmentA: RoutePart[], segmentB: RoutePart[] * For example, `/bar` is sorted before `/foo`. * The definition of "alphabetically" is dependent on the default locale of the running system. */ -function routeComparator(a: ManifestRouteData, b: ManifestRouteData) { +function routeComparator(a: RouteData, b: RouteData) { // For sorting purposes, an index route is considered to have one more segment than the URL it represents. const aLength = a.isIndex ? a.segments.length + 1 : a.segments.length; const bLength = b.isIndex ? b.segments.length + 1 : b.segments.length; @@ -250,9 +246,9 @@ export interface CreateRouteManifestParams { function createFileBasedRoutes( { settings, cwd, fsMod }: CreateRouteManifestParams, logger: Logger -): ManifestRouteData[] { +): RouteData[] { const components: string[] = []; - const routes: ManifestRouteData[] = []; + const routes: RouteData[] = []; const validPageExtensions = new Set([ '.astro', ...SUPPORTED_MARKDOWN_FILE_EXTENSIONS, @@ -393,7 +389,7 @@ function createFileBasedRoutes( return routes; } -type PrioritizedRoutesData = Record; +type PrioritizedRoutesData = Record; function createInjectedRoutes({ settings, cwd }: CreateRouteManifestParams): PrioritizedRoutesData { const { config } = settings; @@ -639,7 +635,7 @@ export function createRouteManifest( const redirectRoutes = createRedirectRoutes(params, routeMap, logger); - const routes: ManifestRouteData[] = [ + const routes: RouteData[] = [ ...injectedRoutes['legacy'].sort(routeComparator), ...[...fileBasedRoutes, ...injectedRoutes['normal'], ...redirectRoutes['normal']].sort( routeComparator @@ -675,8 +671,8 @@ export function createRouteManifest( // In this block of code we group routes based on their locale - // A map like: locale => ManifestRouteData[] - const routesByLocale = new Map(); + // A map like: locale => RouteData[] + const routesByLocale = new Map(); // This type is here only as a helper. We copy the routes and make them unique, so we don't "process" the same route twice. // The assumption is that a route in the file system belongs to only one locale. const setRoutes = new Set(routes.filter((route) => route.type === 'page')); diff --git a/packages/astro/src/core/routing/manifest/serialization.ts b/packages/astro/src/core/routing/manifest/serialization.ts index f70aa84dd0ac..431febcb80f6 100644 --- a/packages/astro/src/core/routing/manifest/serialization.ts +++ b/packages/astro/src/core/routing/manifest/serialization.ts @@ -38,5 +38,6 @@ export function deserializeRouteData(rawRouteData: SerializedRouteData): RouteDa fallbackRoutes: rawRouteData.fallbackRoutes.map((fallback) => { return deserializeRouteData(fallback); }), + isIndex: rawRouteData.isIndex, }; } diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index 67a2a4baa3af..65d9a6c92539 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -234,6 +234,7 @@ export async function handleRoute({ type: 'fallback', route: '', fallbackRoutes: [], + isIndex: false, }; renderContext = await createRenderContext({ request, diff --git a/packages/astro/test/astro-pageDirectoryUrl.test.js b/packages/astro/test/astro-pageDirectoryUrl.test.js index 978db056aebc..19b75e222951 100644 --- a/packages/astro/test/astro-pageDirectoryUrl.test.js +++ b/packages/astro/test/astro-pageDirectoryUrl.test.js @@ -2,21 +2,45 @@ import { expect } from 'chai'; import { loadFixture } from './test-utils.js'; describe('build format', () => { - let fixture; + describe('build.format: file', () => { + /** @type {import('./test-utils.js').Fixture} */ + let fixture; - before(async () => { - fixture = await loadFixture({ - root: './fixtures/astro-page-directory-url', - build: { - format: 'file', - }, + before(async () => { + fixture = await loadFixture({ + root: './fixtures/astro-page-directory-url', + build: { + format: 'file', + }, + }); + await fixture.build(); + }); + + 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; }); - await fixture.build(); }); - 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; + describe('build.format: preserve', () => { + /** @type {import('./test-utils.js').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/astro-page-directory-url', + build: { + format: 'preserve', + }, + }); + await fixture.build(); + }); + + it('outputs', async () => { + expect(await fixture.readFile('/client.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; + }); }); }); diff --git a/packages/astro/test/fixtures/page-format/src/pages/nested/index.astro b/packages/astro/test/fixtures/page-format/src/pages/nested/index.astro new file mode 100644 index 000000000000..9c077e2a381b --- /dev/null +++ b/packages/astro/test/fixtures/page-format/src/pages/nested/index.astro @@ -0,0 +1,8 @@ + + + Testing + + +

Testing

+ + diff --git a/packages/astro/test/page-format.test.js b/packages/astro/test/page-format.test.js index 2143bf09b263..5c99da7ef6d9 100644 --- a/packages/astro/test/page-format.test.js +++ b/packages/astro/test/page-format.test.js @@ -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'); + }); }); }); }); From 1eda830564e2e916f48be0f2db5ef94d19c3f8fd Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Mon, 22 Jan 2024 12:23:57 -0500 Subject: [PATCH 2/8] Restructure test --- packages/astro/test/page-format.test.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/astro/test/page-format.test.js b/packages/astro/test/page-format.test.js index 5c99da7ef6d9..3315b6da82a9 100644 --- a/packages/astro/test/page-format.test.js +++ b/packages/astro/test/page-format.test.js @@ -37,6 +37,31 @@ describe('build.format', () => { }); }); + describe('Build', () => { + before(async () => { + await fixture.build(); + }); + + it('relative urls created point to sibling folders', async () => { + let html = await fixture.readFile('/nested/page.html'); + let $ = cheerio.load(html); + expect($('#another').attr('href')).to.equal('/nested/another/'); + }); + }); + }); + + describe('preserve', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + before(async () => { + fixture = await loadFixture({ + root: './fixtures/page-format/', + build: { + format: 'preserve', + }, + }); + }); + describe('Build', () => { before(async () => { await fixture.build(); From 6b0f1e83a0e62d97ef992b58ab753108a4063f9f Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Wed, 24 Jan 2024 09:36:00 -0500 Subject: [PATCH 3/8] Add a test for base --- packages/astro/test/page-format.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/astro/test/page-format.test.js b/packages/astro/test/page-format.test.js index 3315b6da82a9..a022326134d0 100644 --- a/packages/astro/test/page-format.test.js +++ b/packages/astro/test/page-format.test.js @@ -55,6 +55,7 @@ describe('build.format', () => { let fixture; before(async () => { fixture = await loadFixture({ + base: '/test', root: './fixtures/page-format/', build: { format: 'preserve', @@ -70,7 +71,7 @@ describe('build.format', () => { it('relative urls created point to sibling folders', async () => { let html = await fixture.readFile('/nested/page.html'); let $ = cheerio.load(html); - expect($('#another').attr('href')).to.equal('/nested/another/'); + expect($('#another').attr('href')).to.equal('/test/nested/another/'); }); it('index files are written as index.html', async () => { From e8b0f1b8a126b60f148cd0441ac50866e279939e Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Wed, 24 Jan 2024 12:57:47 -0500 Subject: [PATCH 4/8] Update .changeset/tame-flies-confess.md Co-authored-by: Florian Lefebvre --- .changeset/tame-flies-confess.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/tame-flies-confess.md b/.changeset/tame-flies-confess.md index b096ac8458cd..ed6d946f6e2f 100644 --- a/.changeset/tame-flies-confess.md +++ b/.changeset/tame-flies-confess.md @@ -2,7 +2,7 @@ 'astro': minor --- -build.format: 'preserve' to preserve source structure in final build +Adds a new possible value to the `build.format` configuration: 'preserve'. It will preserve your source structure in the final build Using `build.format: 'file'`, a method to produce HTML files that are *not* all within folders, it will only produce `index.html` for the base path of `/`. This meant that even if you create explicit index pages with, for example, `page/index.astro`, it would write these out as `page.html`. From a01552c43ff166db65d6109817757367d05cbd96 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Thu, 25 Jan 2024 10:17:08 -0500 Subject: [PATCH 5/8] Add trailing slash + i18n testing --- .../fixtures/page-format/src/pages/en/index.astro | 6 ++++++ .../page-format/src/pages/en/nested/index.astro | 8 ++++++++ .../page-format/src/pages/en/nested/page.astro | 4 ++++ .../fixtures/page-format/src/pages/index.astro | 6 ++++++ packages/astro/test/page-format.test.js | 15 ++++++++++++--- 5 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 packages/astro/test/fixtures/page-format/src/pages/en/index.astro create mode 100644 packages/astro/test/fixtures/page-format/src/pages/en/nested/index.astro create mode 100644 packages/astro/test/fixtures/page-format/src/pages/en/nested/page.astro create mode 100644 packages/astro/test/fixtures/page-format/src/pages/index.astro diff --git a/packages/astro/test/fixtures/page-format/src/pages/en/index.astro b/packages/astro/test/fixtures/page-format/src/pages/en/index.astro new file mode 100644 index 000000000000..bcd4c7539a7c --- /dev/null +++ b/packages/astro/test/fixtures/page-format/src/pages/en/index.astro @@ -0,0 +1,6 @@ +--- +--- + + testing +

testing

+ diff --git a/packages/astro/test/fixtures/page-format/src/pages/en/nested/index.astro b/packages/astro/test/fixtures/page-format/src/pages/en/nested/index.astro new file mode 100644 index 000000000000..9c077e2a381b --- /dev/null +++ b/packages/astro/test/fixtures/page-format/src/pages/en/nested/index.astro @@ -0,0 +1,8 @@ + + + Testing + + +

Testing

+ + diff --git a/packages/astro/test/fixtures/page-format/src/pages/en/nested/page.astro b/packages/astro/test/fixtures/page-format/src/pages/en/nested/page.astro new file mode 100644 index 000000000000..eb67508a7365 --- /dev/null +++ b/packages/astro/test/fixtures/page-format/src/pages/en/nested/page.astro @@ -0,0 +1,4 @@ +--- +const another = new URL('./another/', Astro.url); +--- + diff --git a/packages/astro/test/fixtures/page-format/src/pages/index.astro b/packages/astro/test/fixtures/page-format/src/pages/index.astro new file mode 100644 index 000000000000..bcd4c7539a7c --- /dev/null +++ b/packages/astro/test/fixtures/page-format/src/pages/index.astro @@ -0,0 +1,6 @@ +--- +--- + + testing +

testing

+ diff --git a/packages/astro/test/page-format.test.js b/packages/astro/test/page-format.test.js index a022326134d0..63e5dae833d9 100644 --- a/packages/astro/test/page-format.test.js +++ b/packages/astro/test/page-format.test.js @@ -57,9 +57,18 @@ describe('build.format', () => { fixture = await loadFixture({ base: '/test', root: './fixtures/page-format/', + trailingSlash: 'always', build: { format: 'preserve', }, + i18n: { + locales: ['en'], + defaultLocale: 'en', + routing: { + prefixDefaultLocale: true, + redirectToDefaultLocale: true, + } + } }); }); @@ -69,13 +78,13 @@ describe('build.format', () => { }); it('relative urls created point to sibling folders', async () => { - let html = await fixture.readFile('/nested/page.html'); + let html = await fixture.readFile('/en/nested/page.html'); let $ = cheerio.load(html); - expect($('#another').attr('href')).to.equal('/test/nested/another/'); + expect($('#another').attr('href')).to.equal('/test/en/nested/another/'); }); it('index files are written as index.html', async () => { - let html = await fixture.readFile('/nested/index.html'); + let html = await fixture.readFile('/en/nested/index.html'); let $ = cheerio.load(html); expect($('h1').text()).to.equal('Testing'); }); From a712247e06399424c0dc07a54669a86929798578 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 30 Jan 2024 09:17:14 +0000 Subject: [PATCH 6/8] Update packages/astro/src/@types/astro.ts Co-authored-by: Sarah Rainsberger --- packages/astro/src/@types/astro.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 32be50746030..a87aba351fea 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -731,9 +731,9 @@ export interface AstroUserConfig { * @default `'directory'` * @description * Control the output file format of each page. This value may be set by an adapter for you. - * - If `'file'`, Astro will generate an HTML file (ex: "/foo.html") for each page. - * - If `'directory'`, Astro will generate a directory with a nested `index.html` file (ex: "/foo/index.html") for each page. - * - If `'preserve'`, Astro will generate HTML files exactly as they appear in your source folder (ex: "foo/index.astro" becomes "foo/index.html" but "foo.astro" does not) + * - `'file'`: Astro will generate an HTML file named for each page route. (e.g. `src/pages/about.astro` and `src/pages/about/index.astro` both build the file `/about.html`) + * - `'directory'`: Astro will generate a directory with a nested `index.html` file for each page. (e.g. `src/pages/about.astro` and `src/pages/about/index.astro` both build the file `/about/index.html`) + * - `'preserve'`: Astro will generate HTML files exactly as they appear in your source folder. (e.g. `src/pages/about.astro` builds `/about.html` but `src/pages/about/index.astro` builds the file `/about/index.html`) * * ```js * { From 85b24bd707b833762d7aab904308e79a1b1cc89f Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 30 Jan 2024 09:18:05 +0000 Subject: [PATCH 7/8] Update .changeset/tame-flies-confess.md Co-authored-by: Sarah Rainsberger --- .changeset/tame-flies-confess.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.changeset/tame-flies-confess.md b/.changeset/tame-flies-confess.md index ed6d946f6e2f..f257d283be8e 100644 --- a/.changeset/tame-flies-confess.md +++ b/.changeset/tame-flies-confess.md @@ -2,13 +2,17 @@ 'astro': minor --- -Adds a new possible value to the `build.format` configuration: 'preserve'. It will preserve your source structure in the final build +Adds a new `build.format` configuration option: 'preserve'. This option will preserve your source structure in the final build. -Using `build.format: 'file'`, a method to produce HTML files that are *not* all within folders, it will only produce `index.html` for the base path of `/`. This meant that even if you create explicit index pages with, for example, `page/index.astro`, it would write these out as `page.html`. +The existing configuration options, `file` and `directory`, either build all of your HTML pages as files matching the route name (e.g. `/about.html`) or build all your files as `index.html` within a nested directory structure (e.g. `/about/index.html), respectively. It was not previously possible to control the HTML file built on a per-file basis. -This is a bit unexpected, but rather than make a breaking change to `build.format: 'file'` we decided to create a new `build.format: 'preserve'`. +One limitation of `build.format: 'file'` is that it cannot create `index.html` files for any individual routes (other than the base path of `/`) while otherwise building named files. Creating explicit index pages within your file structure still generates a file named for the page route (e.g. `src/pages/about/index.astro` builds `/about.html`) when using the `file` configuration option. + +Rather than make a breaking change to allow `build.format: 'file'` to be more flexible, we decided to create a new `build.format: 'preserve'`. The new format will preserve how the filesystem is structured and make sure that is mirrored over to production. Using this option: -- `page.astro` becomes `page.html` -- `page/index.astro` becomes `page/index.html` +- `about.astro` becomes `about.html` +- `about/index.astro` becomes `about/index.html` + +See the [`build.format` configuration options reference] for more details From 8ae668c49fc0bd3cf01b442742b2130a95e49f43 Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger Date: Tue, 30 Jan 2024 11:00:00 -0400 Subject: [PATCH 8/8] tiny punctuation/conjunction nit fixes --- .changeset/tame-flies-confess.md | 4 ++-- packages/astro/src/@types/astro.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/tame-flies-confess.md b/.changeset/tame-flies-confess.md index f257d283be8e..7b10c23580f8 100644 --- a/.changeset/tame-flies-confess.md +++ b/.changeset/tame-flies-confess.md @@ -4,7 +4,7 @@ Adds a new `build.format` configuration option: 'preserve'. This option will preserve your source structure in the final build. -The existing configuration options, `file` and `directory`, either build all of your HTML pages as files matching the route name (e.g. `/about.html`) or build all your files as `index.html` within a nested directory structure (e.g. `/about/index.html), respectively. It was not previously possible to control the HTML file built on a per-file basis. +The existing configuration options, `file` and `directory`, either build all of your HTML pages as files matching the route name (e.g. `/about.html`) or build all your files as `index.html` within a nested directory structure (e.g. `/about/index.html`), respectively. It was not previously possible to control the HTML file built on a per-file basis. One limitation of `build.format: 'file'` is that it cannot create `index.html` files for any individual routes (other than the base path of `/`) while otherwise building named files. Creating explicit index pages within your file structure still generates a file named for the page route (e.g. `src/pages/about/index.astro` builds `/about.html`) when using the `file` configuration option. @@ -15,4 +15,4 @@ The new format will preserve how the filesystem is structured and make sure that - `about.astro` becomes `about.html` - `about/index.astro` becomes `about/index.html` -See the [`build.format` configuration options reference] for more details +See the [`build.format` configuration options reference] for more details. diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index e06ba735f0a4..88220405b308 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -790,7 +790,7 @@ export interface AstroUserConfig { * Control the output file format of each page. This value may be set by an adapter for you. * - `'file'`: Astro will generate an HTML file named for each page route. (e.g. `src/pages/about.astro` and `src/pages/about/index.astro` both build the file `/about.html`) * - `'directory'`: Astro will generate a directory with a nested `index.html` file for each page. (e.g. `src/pages/about.astro` and `src/pages/about/index.astro` both build the file `/about/index.html`) - * - `'preserve'`: Astro will generate HTML files exactly as they appear in your source folder. (e.g. `src/pages/about.astro` builds `/about.html` but `src/pages/about/index.astro` builds the file `/about/index.html`) + * - `'preserve'`: Astro will generate HTML files exactly as they appear in your source folder. (e.g. `src/pages/about.astro` builds `/about.html` and `src/pages/about/index.astro` builds the file `/about/index.html`) * * ```js * {