From 637919c8b63df1608e88d153742db098722265d8 Mon Sep 17 00:00:00 2001 From: Tony Sullivan Date: Thu, 21 Apr 2022 18:03:05 +0000 Subject: [PATCH] Improvements to build and dev when building for subpaths (#3156) * `astro build` should include the `base` provided in astro config * test: updating build test to expect the base path in links/scripts * ignore the default "base" value when building links/scripts * fix: handling config that provides a base but no site * fix: config.site was being ignored since it's a URL not a string * hack: handle base path in dev for /public assets * fix: dev redirect needs to ignore base default of ./ * fix: extra safety checks for the base path redirect * refactor: simplifying it to remove the regex * one last safety check - only redirect GET and use a 302 status * fix: lost the leading slash when redirecting * nit: adding comments to the test explaining how base is verified * Remove extra console.log * Adds a changeset Co-authored-by: unknown --- .changeset/chatty-peas-warn.md | 5 +++++ packages/astro/src/core/build/generate.ts | 8 ++++++-- packages/astro/src/core/path.ts | 8 ++++++++ .../src/vite-plugin-astro-server/index.ts | 18 ++++++++++++++++++ packages/astro/test/static-build.test.js | 15 ++++++++++++++- 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 .changeset/chatty-peas-warn.md diff --git a/.changeset/chatty-peas-warn.md b/.changeset/chatty-peas-warn.md new file mode 100644 index 000000000000..bda91dda0ba4 --- /dev/null +++ b/.changeset/chatty-peas-warn.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Adds subpath to assets/scripts when statically generating diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 36c25546ce9f..4bac5ae29cf3 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -11,7 +11,7 @@ import type { } from '../../@types/astro'; import type { BuildInternals } from '../../core/build/internal.js'; import { debug, info } from '../logger/core.js'; -import { prependForwardSlash, removeLeadingForwardSlash } from '../../core/path.js'; +import { joinPaths, prependForwardSlash, removeLeadingForwardSlash } from '../../core/path.js'; import type { RenderOptions } from '../../core/render/core'; import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { call as callEndpoint } from '../endpoint/index.js'; @@ -176,7 +176,11 @@ async function generatePath( debug('build', `Generating: ${pathname}`); - const site = astroConfig.site; + // If a base path was provided, append it to the site URL. This ensures that + // all injected scripts and links are referenced relative to the site and subpath. + const site = astroConfig.base && astroConfig.base !== './' + ? joinPaths(astroConfig.site?.toString() || 'http://localhost/', astroConfig.base) + : astroConfig.site; const links = createLinkStylesheetElementSet(linkIds.reverse(), site); const scripts = createModuleScriptElementWithSrcSet(hoistedId ? [hoistedId] : [], site); diff --git a/packages/astro/src/core/path.ts b/packages/astro/src/core/path.ts index 177723177413..e499c8c5a6c5 100644 --- a/packages/astro/src/core/path.ts +++ b/packages/astro/src/core/path.ts @@ -38,3 +38,11 @@ export function startsWithDotSlash(path: string) { export function isRelativePath(path: string) { return startsWithDotDotSlash(path) || startsWithDotSlash(path); } + +function isString(path: unknown): path is string { + return typeof path === 'string' || path instanceof String; +} + +export function joinPaths(...paths: (string | undefined)[]) { + return paths.filter(isString).map(trimSlashes).join('/'); +} \ No newline at end of file diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts index 485f16282cd1..3d8529fee5f2 100644 --- a/packages/astro/src/vite-plugin-astro-server/index.ts +++ b/packages/astro/src/vite-plugin-astro-server/index.ts @@ -111,6 +111,24 @@ async function handle404Response( if (pathname === '/' && !pathname.startsWith(devRoot)) { html = subpathNotUsedTemplate(devRoot, pathname); } else { + // HACK: redirect without the base path for assets in publicDir + const redirectTo = + req.method === 'GET' + && config.base && config.base !== './' + && pathname.startsWith(config.base) + && pathname.replace(config.base, '/'); + + if (redirectTo && redirectTo !== '/') { + const response = new Response(null, { + status: 302, + headers: { + Location: redirectTo, + }, + }); + await writeWebResponse(res, response); + return; + } + html = notFoundTemplate({ statusCode: 404, title: 'Not found', diff --git a/packages/astro/test/static-build.test.js b/packages/astro/test/static-build.test.js index 3ed593acec2f..b2c9d9d47977 100644 --- a/packages/astro/test/static-build.test.js +++ b/packages/astro/test/static-build.test.js @@ -6,6 +6,11 @@ function addLeadingSlash(path) { return path.startsWith('/') ? path : '/' + path; } +function removeBasePath(path) { + // `/subpath` is defined in the test fixture's Astro config + return path.replace('/subpath', '') +} + /** * @typedef {import('../src/core/logger/core').LogMessage} LogMessage */ @@ -90,7 +95,15 @@ describe('Static build', () => { const links = $('link[rel=stylesheet]'); for (const link of links) { const href = $(link).attr('href'); - const data = await fixture.readFile(addLeadingSlash(href)); + + /** + * The link should be built with the config's `base` included + * as a subpath. + * + * The test needs to verify that the file will be found once the `/dist` + * output is deployed to a subpath in production by ignoring the subpath here. + */ + const data = await fixture.readFile(removeBasePath(addLeadingSlash(href))); if (expected.test(data)) { return true; }