From 688f8e4bc1d8a284ee3d29f6122dbdebc02310ff Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Tue, 8 Nov 2022 17:30:09 -0500 Subject: [PATCH] Allow dynamic segments in injected routes (#5331) * Allow dynamic segments in injected routes * Little better * Fallback for resolveId too --- .changeset/good-ghosts-attack.md | 5 +++ .../astro/src/core/routing/manifest/create.ts | 23 ++++------ .../src/vite-plugin-load-fallback/index.ts | 9 +++- packages/astro/test/units/dev/dev.test.js | 45 +++++++++++++++++++ packages/astro/test/units/test-utils.js | 2 + 5 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 .changeset/good-ghosts-attack.md diff --git a/.changeset/good-ghosts-attack.md b/.changeset/good-ghosts-attack.md new file mode 100644 index 000000000..c4a8404b2 --- /dev/null +++ b/.changeset/good-ghosts-attack.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Allow dynamic segments in injected routes diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index aa4a1ea68..4e1fddb7d 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -352,27 +352,20 @@ export function createRouteManifest( ) .reverse() // prepend to the routes array from lowest to highest priority .forEach(({ pattern: name, entryPoint }) => { - const resolved = require.resolve(entryPoint, { paths: [cwd || fileURLToPath(config.root)] }); + let resolved: string; + try { + resolved = require.resolve(entryPoint, { paths: [cwd || fileURLToPath(config.root)] }); + } catch(e) { + resolved = fileURLToPath(new URL(entryPoint, config.root)); + } const component = slash(path.relative(cwd || fileURLToPath(config.root), resolved)); - const isDynamic = (str: string) => str?.[0] === '['; - const normalize = (str: string) => str?.substring(1, str?.length - 1); - const segments = removeLeadingForwardSlash(name) - .split(path.sep) + .split(path.posix.sep) .filter(Boolean) .map((s: string) => { validateSegment(s); - - const dynamic = isDynamic(s); - const content = dynamic ? normalize(s) : s; - return [ - { - content, - dynamic, - spread: isSpread(s), - }, - ]; + return getParts(s, component); }); const type = resolved.endsWith('.astro') ? 'page' : 'endpoint'; diff --git a/packages/astro/src/vite-plugin-load-fallback/index.ts b/packages/astro/src/vite-plugin-load-fallback/index.ts index 372ca2d9d..7bfe4224a 100644 --- a/packages/astro/src/vite-plugin-load-fallback/index.ts +++ b/packages/astro/src/vite-plugin-load-fallback/index.ts @@ -1,5 +1,6 @@ import nodeFs from 'fs'; import npath from 'path'; +import slashify from 'slash'; import type * as vite from 'vite'; import type { AstroSettings } from '../@types/astro'; @@ -41,9 +42,15 @@ export default function loadFallbackPlugin({ { name: 'astro:load-fallback', enforce: 'post', - resolveId(id, parent) { + async resolveId(id, parent) { if (id.startsWith('.') && parent && fs.existsSync(parent)) { return npath.posix.join(npath.posix.dirname(parent), id); + } else { + let resolved = await this.resolve(id, parent, { skipSelf: true }); + if(resolved) { + return resolved.id; + } + return slashify(id); } }, async load(id) { diff --git a/packages/astro/test/units/dev/dev.test.js b/packages/astro/test/units/dev/dev.test.js index b8159e5b7..d19f7971f 100644 --- a/packages/astro/test/units/dev/dev.test.js +++ b/packages/astro/test/units/dev/dev.test.js @@ -106,4 +106,49 @@ describe('dev container', () => { expect($('body.two')).to.have.a.lengthOf(1); }); }); + + it('Allows dynamic segments in injected routes', async () => { + const fs = createFs({ + '/src/components/test.astro': `

{Astro.params.slug}

`, + '/src/pages/test-[slug].astro': `

{Astro.params.slug}

`, + }, + root + ); + + await runInContainer({ + fs, + root, + userConfig: { + output: 'server', + integrations: [{ + name: '@astrojs/test-integration', + hooks: { + 'astro:config:setup': ({ injectRoute }) => { + injectRoute({ + pattern: '/another-[slug]', + entryPoint: './src/components/test.astro', + }); + }, + }, + }] + } + }, async (container) => { + let r = createRequestAndResponse({ + method: 'GET', + url: '/test-one', + }); + container.handle(r.req, r.res); + await r.done; + expect(r.res.statusCode).to.equal(200); + + // Try with the injected route + r = createRequestAndResponse({ + method: 'GET', + url: '/another-two', + }); + container.handle(r.req, r.res); + await r.done; + expect(r.res.statusCode).to.equal(200); + }); + }); }); diff --git a/packages/astro/test/units/test-utils.js b/packages/astro/test/units/test-utils.js index abf4486e3..61aea3129 100644 --- a/packages/astro/test/units/test-utils.js +++ b/packages/astro/test/units/test-utils.js @@ -15,6 +15,8 @@ class MyVolume extends Volume { #forcePath(p) { if (p instanceof URL) { p = unixify(fileURLToPath(p)); + } else { + p = unixify(p); } return p; }