Fix a regression in vite.build() base option (#2502)

* Fixes subpath bugs

* Remove trailing slash appending

Co-authored-by: Matthew Phillips <matthew@skypack.dev>
This commit is contained in:
Fred K. Schott 2022-01-31 13:27:59 -08:00 committed by GitHub
parent 4e43ae5d76
commit f3dafd33e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 20 deletions

View file

@ -14,7 +14,7 @@ import { fileURLToPath } from 'url';
import glob from 'fast-glob'; import glob from 'fast-glob';
import vite from '../vite.js'; import vite from '../vite.js';
import { debug, error } from '../../core/logger.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 { createBuildInternals } from '../../core/build/internal.js';
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js'; import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
import { getParamsAndProps } from '../ssr/index.js'; import { getParamsAndProps } from '../ssr/index.js';
@ -162,7 +162,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
build: { build: {
emptyOutDir: false, emptyOutDir: false,
minify: false, minify: false,
outDir: fileURLToPath(astroConfig.dist), outDir: fileURLToPath(getOutRoot(astroConfig)),
ssr: true, ssr: true,
rollupOptions: { rollupOptions: {
input: Array.from(input), input: Array.from(input),
@ -202,7 +202,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
build: { build: {
emptyOutDir: false, emptyOutDir: false,
minify: 'esbuild', minify: 'esbuild',
outDir: fileURLToPath(astroConfig.dist), outDir: fileURLToPath(getOutRoot(astroConfig)),
rollupOptions: { rollupOptions: {
input: Array.from(input), input: Array.from(input),
output: { output: {
@ -224,7 +224,7 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
root: viteConfig.root, root: viteConfig.root,
envPrefix: 'PUBLIC_', envPrefix: 'PUBLIC_',
server: viteConfig.server, 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<string, PageBuildData>, renderers: Renderer[]) { async function generatePage(output: OutputChunk, opts: StaticBuildOptions, internals: BuildInternals, facadeIdToPageDataMap: Map<string, PageBuildData>, renderers: Renderer[]) {
const { astroConfig } = opts; 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; const facadeId: string = output.facadeModuleId as string;
let pageData = getByFacadeId<PageBuildData>(facadeId, facadeIdToPageDataMap); let pageData = getByFacadeId<PageBuildData>(facadeId, facadeIdToPageDataMap);
@ -336,7 +336,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
debug('build', `Generating: ${pathname}`); 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<SSRElement>( const links = new Set<SSRElement>(
linkIds.map((href) => ({ linkIds.map((href) => ({
props: { props: {
@ -372,8 +372,9 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
}; };
let html = await renderPage(result, Component, pageProps, null); 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.mkdir(outFolder, { recursive: true });
await fs.promises.writeFile(outFile, html, 'utf-8'); await fs.promises.writeFile(outFile, html, 'utf-8');
} catch (err) { } 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) { async function cleanSsrOutput(opts: StaticBuildOptions) {
// The SSR output is all .mjs files, the client output is not. // The SSR output is all .mjs files, the client output is not.
const files = await glob('**/*.mjs', { const files = await glob('**/*.mjs', {

View file

@ -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. */ /** Create the Astro.fetchContent() runtime function. */
function createFetchContentFn(url: URL, site: URL) { function createFetchContentFn(url: URL, site: URL) {
let sitePathname = site.pathname;
const fetchContent = (importMetaGlobResult: Record<string, any>) => { const fetchContent = (importMetaGlobResult: Record<string, any>) => {
let allEntries = [...Object.entries(importMetaGlobResult)]; let allEntries = [...Object.entries(importMetaGlobResult)];
if (allEntries.length === 0) { if (allEntries.length === 0) {
@ -280,7 +281,7 @@ function createFetchContentFn(url: URL, site: URL) {
Content: mod.default, Content: mod.default,
content: mod.metadata, content: mod.metadata,
file: new URL(spec, url), 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); .filter(Boolean);

View file

@ -15,6 +15,7 @@ describe('Static build', () => {
renderers: ['@astrojs/renderer-preact'], renderers: ['@astrojs/renderer-preact'],
buildOptions: { buildOptions: {
experimentalStaticBuild: true, experimentalStaticBuild: true,
site: 'http://example.com/subpath/',
}, },
ssr: { ssr: {
noExternal: ['@astrojs/test-static-build-pkg'], noExternal: ['@astrojs/test-static-build-pkg'],
@ -24,20 +25,20 @@ describe('Static build', () => {
}); });
it('Builds out .astro pages', async () => { 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'); expect(html).to.be.a('string');
}); });
it('can build pages using fetchContent', async () => { 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 $ = cheerio.load(html);
const link = $('.posts a'); const link = $('.posts a');
const href = link.attr('href'); 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 () => { 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'); expect(html).to.be.a('string');
}); });
@ -62,12 +63,12 @@ describe('Static build', () => {
const findEvidence = createFindEvidence(/var\(--c\)/); const findEvidence = createFindEvidence(/var\(--c\)/);
it('Included on the index page', async () => { 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'); expect(found).to.equal(true, 'Did not find shared CSS on this page');
}); });
it('Included on a md page', async () => { 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'); 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\)/); const findEvidence = createFindEvidence(/var\(--c-black\)/);
it('Is included in the index CSS', async () => { 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'); expect(found).to.equal(true, 'Did not find shared CSS module code');
}); });
}); });
describe('Hoisted scripts', () => { describe('Hoisted scripts', () => {
it('Get bundled together on the page', async () => { 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); const $ = cheerio.load(html);
expect($('script[type="module"]').length).to.equal(1, 'hoisted script added'); expect($('script[type="module"]').length).to.equal(1, 'hoisted script added');
}); });
it('Do not get added to the wrong page', async () => { 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 $ = cheerio.load(hoistedHTML);
const href = $('script[type="module"]').attr('src'); 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); const $$ = cheerio.load(indexHTML);
expect($$(`script[src="${href}"]`).length).to.equal(0, 'no script added to different page'); expect($$(`script[src="${href}"]`).length).to.equal(0, 'no script added to different page');
}); });
}); });
it('honors ssr config', async () => { it('honors ssr config', async () => {
const html = await fixture.readFile('/index.html'); const html = await fixture.readFile('/subpath/index.html');
const $ = cheerio.load(html); const $ = cheerio.load(html);
expect($('#ssr-config').text()).to.equal('testing'); expect($('#ssr-config').text()).to.equal('testing');
}); });