From f3dafd33e79cfe26134a95f6cfbde3ceb40b1d11 Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" Date: Mon, 31 Jan 2022 13:27:59 -0800 Subject: [PATCH] Fix a regression in vite.build() base option (#2502) * Fixes subpath bugs * Remove trailing slash appending Co-authored-by: Matthew Phillips --- packages/astro/src/core/build/static-build.ts | 40 +++++++++++++++---- packages/astro/src/runtime/server/index.ts | 3 +- packages/astro/test/static-build.test.js | 23 ++++++----- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index ad2b512039..2ff7443a56 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -14,7 +14,7 @@ import { fileURLToPath } from 'url'; import glob from 'fast-glob'; import vite from '../vite.js'; import { debug, error } from '../../core/logger.js'; -import { prependForwardSlash } from '../../core/path.js'; +import { prependForwardSlash, appendForwardSlash } from '../../core/path.js'; import { createBuildInternals } from '../../core/build/internal.js'; import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js'; import { getParamsAndProps } from '../ssr/index.js'; @@ -162,7 +162,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp build: { emptyOutDir: false, minify: false, - outDir: fileURLToPath(astroConfig.dist), + outDir: fileURLToPath(getOutRoot(astroConfig)), ssr: true, rollupOptions: { input: Array.from(input), @@ -202,7 +202,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, build: { emptyOutDir: false, minify: 'esbuild', - outDir: fileURLToPath(astroConfig.dist), + outDir: fileURLToPath(getOutRoot(astroConfig)), rollupOptions: { input: Array.from(input), output: { @@ -224,7 +224,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, root: viteConfig.root, envPrefix: 'PUBLIC_', server: viteConfig.server, - base: astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/', + base: appendForwardSlash(astroConfig.buildOptions.site ? (new URL(astroConfig.buildOptions.site)).pathname : '/'), }); } @@ -273,7 +273,7 @@ async function generatePages(result: RollupOutput, opts: StaticBuildOptions, int async function generatePage(output: OutputChunk, opts: StaticBuildOptions, internals: BuildInternals, facadeIdToPageDataMap: Map, renderers: Renderer[]) { const { astroConfig } = opts; - let url = new URL('./' + output.fileName, astroConfig.dist); + let url = new URL('./' + output.fileName, getOutRoot(astroConfig)); const facadeId: string = output.facadeModuleId as string; let pageData = getByFacadeId(facadeId, facadeIdToPageDataMap); @@ -336,7 +336,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G debug('build', `Generating: ${pathname}`); - const rootpath = new URL(astroConfig.buildOptions.site || 'http://localhost/').pathname; + const rootpath = appendForwardSlash(new URL(astroConfig.buildOptions.site || 'http://localhost/').pathname); const links = new Set( linkIds.map((href) => ({ props: { @@ -372,8 +372,9 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G }; let html = await renderPage(result, Component, pageProps, null); - const outFolder = new URL('.' + pathname + '/', astroConfig.dist); - const outFile = new URL('./index.html', outFolder); + + const outFolder = getOutFolder(astroConfig, pathname); + const outFile = getOutFile(astroConfig, outFolder, pathname); await fs.promises.mkdir(outFolder, { recursive: true }); await fs.promises.writeFile(outFile, html, 'utf-8'); } catch (err) { @@ -381,6 +382,29 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G } } +function getOutRoot(astroConfig: AstroConfig): URL { + const rootPathname = appendForwardSlash(astroConfig.buildOptions.site ? + new URL(astroConfig.buildOptions.site).pathname : '/'); + return new URL('.' + rootPathname, astroConfig.dist); +} + +function getOutFolder(astroConfig: AstroConfig, pathname: string): URL { + const outRoot = getOutRoot(astroConfig); + + // This is the root folder to write to. + switch(astroConfig.buildOptions.pageUrlFormat) { + case 'directory': return new URL('.' + appendForwardSlash(pathname), outRoot); + case 'file': return outRoot; + } +} + +function getOutFile(astroConfig: AstroConfig, outFolder: URL, pathname: string): URL { + switch(astroConfig.buildOptions.pageUrlFormat) { + case 'directory': return new URL('./index.html', outFolder); + case 'file': return new URL('.' + pathname + '.html', outFolder); + } +} + async function cleanSsrOutput(opts: StaticBuildOptions) { // The SSR output is all .mjs files, the client output is not. const files = await glob('**/*.mjs', { diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts index 894f9867d8..859cc78573 100644 --- a/packages/astro/src/runtime/server/index.ts +++ b/packages/astro/src/runtime/server/index.ts @@ -263,6 +263,7 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr /** Create the Astro.fetchContent() runtime function. */ function createFetchContentFn(url: URL, site: URL) { + let sitePathname = site.pathname; const fetchContent = (importMetaGlobResult: Record) => { let allEntries = [...Object.entries(importMetaGlobResult)]; if (allEntries.length === 0) { @@ -280,7 +281,7 @@ function createFetchContentFn(url: URL, site: URL) { Content: mod.default, content: mod.metadata, file: new URL(spec, url), - url: urlSpec.includes('/pages/') ? urlSpec.replace(/^.*\/pages\//, site.pathname).replace(/(\/index)?\.md$/, '') : undefined, + url: urlSpec.includes('/pages/') ? urlSpec.replace(/^.*\/pages\//, sitePathname).replace(/(\/index)?\.md$/, '') : undefined, }; }) .filter(Boolean); diff --git a/packages/astro/test/static-build.test.js b/packages/astro/test/static-build.test.js index 6645bb2b6e..9accc4a66d 100644 --- a/packages/astro/test/static-build.test.js +++ b/packages/astro/test/static-build.test.js @@ -15,6 +15,7 @@ describe('Static build', () => { renderers: ['@astrojs/renderer-preact'], buildOptions: { experimentalStaticBuild: true, + site: 'http://example.com/subpath/', }, ssr: { noExternal: ['@astrojs/test-static-build-pkg'], @@ -24,20 +25,20 @@ describe('Static build', () => { }); it('Builds out .astro pages', async () => { - const html = await fixture.readFile('/index.html'); + const html = await fixture.readFile('/subpath/index.html'); expect(html).to.be.a('string'); }); it('can build pages using fetchContent', async () => { - const html = await fixture.readFile('/index.html'); + const html = await fixture.readFile('/subpath/index.html'); const $ = cheerio.load(html); const link = $('.posts a'); const href = link.attr('href'); - expect(href).to.be.equal('/posts/thoughts'); + expect(href).to.be.equal('/subpath/posts/thoughts'); }); it('Builds out .md pages', async () => { - const html = await fixture.readFile('/posts/thoughts/index.html'); + const html = await fixture.readFile('/subpath/posts/thoughts/index.html'); expect(html).to.be.a('string'); }); @@ -62,12 +63,12 @@ describe('Static build', () => { const findEvidence = createFindEvidence(/var\(--c\)/); it('Included on the index page', async () => { - const found = await findEvidence('/index.html'); + const found = await findEvidence('/subpath/index.html'); expect(found).to.equal(true, 'Did not find shared CSS on this page'); }); it('Included on a md page', async () => { - const found = await findEvidence('/posts/thoughts/index.html'); + const found = await findEvidence('/subpath/posts/thoughts/index.html'); expect(found).to.equal(true, 'Did not find shared CSS on this page'); }); }); @@ -76,30 +77,30 @@ describe('Static build', () => { const findEvidence = createFindEvidence(/var\(--c-black\)/); it('Is included in the index CSS', async () => { - const found = await findEvidence('/index.html'); + const found = await findEvidence('/subpath/index.html'); expect(found).to.equal(true, 'Did not find shared CSS module code'); }); }); describe('Hoisted scripts', () => { it('Get bundled together on the page', async () => { - const html = await fixture.readFile('/hoisted/index.html'); + const html = await fixture.readFile('/subpath/hoisted/index.html'); const $ = cheerio.load(html); expect($('script[type="module"]').length).to.equal(1, 'hoisted script added'); }); it('Do not get added to the wrong page', async () => { - const hoistedHTML = await fixture.readFile('/hoisted/index.html'); + const hoistedHTML = await fixture.readFile('/subpath/hoisted/index.html'); const $ = cheerio.load(hoistedHTML); const href = $('script[type="module"]').attr('src'); - const indexHTML = await fixture.readFile('/index.html'); + const indexHTML = await fixture.readFile('/subpath/index.html'); const $$ = cheerio.load(indexHTML); expect($$(`script[src="${href}"]`).length).to.equal(0, 'no script added to different page'); }); }); it('honors ssr config', async () => { - const html = await fixture.readFile('/index.html'); + const html = await fixture.readFile('/subpath/index.html'); const $ = cheerio.load(html); expect($('#ssr-config').text()).to.equal('testing'); });