From 2421f908c3ed71cb95be6e0fc57fbccb7d03d184 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Thu, 3 Aug 2023 17:25:33 -0500 Subject: [PATCH 1/8] fix: inject route! hack! --- .../astro/src/vite-plugin-scripts/page-ssr.ts | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/vite-plugin-scripts/page-ssr.ts b/packages/astro/src/vite-plugin-scripts/page-ssr.ts index 1a02ca13fc16..ac6511f7cc90 100644 --- a/packages/astro/src/vite-plugin-scripts/page-ssr.ts +++ b/packages/astro/src/vite-plugin-scripts/page-ssr.ts @@ -4,6 +4,8 @@ import type { AstroSettings } from '../@types/astro.js'; import { isPage } from '../core/util.js'; import { PAGE_SSR_SCRIPT_ID } from './index.js'; +const RESOLVED_ENTRYPOINT_SYMBOL = Symbol('astro:resolved-entrypoint'); + export default function astroScriptsPostPlugin({ settings, }: { @@ -12,7 +14,7 @@ export default function astroScriptsPostPlugin({ return { name: 'astro:scripts:page-ssr', enforce: 'post', - transform(this, code, id, options) { + async transform(this, code, id, options) { if (!options?.ssr) return; const hasInjectedScript = settings.scripts.some((s) => s.stage === 'page-ssr'); @@ -27,8 +29,23 @@ export default function astroScriptsPostPlugin({ return; } + await Promise.all(settings.injectedRoutes.map(async route => { + if ((route as any)[RESOLVED_ENTRYPOINT_SYMBOL]) return route; + const resolvedId = await this.resolve(route.entryPoint); + (route as any)[RESOLVED_ENTRYPOINT_SYMBOL] = resolvedId?.id; + return route; + })) + const fileIsPage = isPage(fileURL, settings); - if (!fileIsPage) return; + let fileIsInjectedRoute = false; + for (const route of settings.injectedRoutes) { + console.log((route as any)[RESOLVED_ENTRYPOINT_SYMBOL]) + if ((route as any)[RESOLVED_ENTRYPOINT_SYMBOL] === id) { + fileIsInjectedRoute = true; + break; + } + } + if (!(fileIsPage || fileIsInjectedRoute)) return; const s = new MagicString(code, { filename }); s.prepend(`import '${PAGE_SSR_SCRIPT_ID}';\n`); From a17fbdf16dc182561dcf4a4e1aa2943d1b07f8b0 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Fri, 4 Aug 2023 13:39:52 -0400 Subject: [PATCH 2/8] refactor: use integration container to resolve all injected routes --- packages/astro/src/@types/astro.ts | 15 +++++++++----- packages/astro/src/core/config/settings.ts | 1 + packages/astro/src/core/util.ts | 5 +++-- .../index.ts | 20 ++++++++++++++++++- .../astro/src/vite-plugin-scripts/page-ssr.ts | 19 +----------------- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 1c7152fec261..6bcb011bb274 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1316,16 +1316,20 @@ export interface AstroUserConfig { */ export type InjectedScriptStage = 'before-hydration' | 'head-inline' | 'page' | 'page-ssr'; -/** - * Resolved Astro Config - * Config with user settings along with all defaults filled in. - */ - export interface InjectedRoute { pattern: string; entryPoint: string; prerender?: boolean; } + +export interface ResolvedInjectedRoute extends InjectedRoute { + resolvedEntryPoint?: URL; +} + +/** + * Resolved Astro Config + * Config with user settings along with all defaults filled in. + */ export interface AstroConfig extends z.output { // Public: // This is a more detailed type than zod validation gives us. @@ -1414,6 +1418,7 @@ export interface AstroSettings { config: AstroConfig; adapter: AstroAdapter | undefined; injectedRoutes: InjectedRoute[]; + resolvedInjectedRoutes: ResolvedInjectedRoute[]; pageExtensions: string[]; contentEntryTypes: ContentEntryType[]; dataEntryTypes: DataEntryType[]; diff --git a/packages/astro/src/core/config/settings.ts b/packages/astro/src/core/config/settings.ts index b15961e5076c..c0274f60293f 100644 --- a/packages/astro/src/core/config/settings.ts +++ b/packages/astro/src/core/config/settings.ts @@ -21,6 +21,7 @@ export function createBaseSettings(config: AstroConfig): AstroSettings { adapter: undefined, injectedRoutes: [], + resolvedInjectedRoutes: [], pageExtensions: ['.astro', '.html', ...SUPPORTED_MARKDOWN_FILE_EXTENSIONS], contentEntryTypes: [markdownContentEntryType], dataEntryTypes: [ diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index c3f537243183..ff41a5ed6d6a 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -113,8 +113,9 @@ function isInPagesDir(file: URL, config: AstroConfig): boolean { } function isInjectedRoute(file: URL, settings: AstroSettings) { - for (const route of settings.injectedRoutes) { - if (file.toString().endsWith(route.entryPoint)) return true; + let fileURL = file.toString(); + for (const route of settings.resolvedInjectedRoutes) { + if (route.resolvedEntryPoint && fileURL === route.resolvedEntryPoint.toString()) return true; } return false; } diff --git a/packages/astro/src/vite-plugin-integrations-container/index.ts b/packages/astro/src/vite-plugin-integrations-container/index.ts index 0169a6f71560..7643fe0e1cc7 100644 --- a/packages/astro/src/vite-plugin-integrations-container/index.ts +++ b/packages/astro/src/vite-plugin-integrations-container/index.ts @@ -1,4 +1,4 @@ -import type { Plugin as VitePlugin } from 'vite'; +import { normalizePath, type Plugin as VitePlugin } from 'vite'; import type { AstroSettings } from '../@types/astro.js'; import type { LogOptions } from '../core/logger/core.js'; import { runHookServerSetup } from '../integrations/index.js'; @@ -11,10 +11,28 @@ export default function astroIntegrationsContainerPlugin({ settings: AstroSettings; logging: LogOptions; }): VitePlugin { + let hasResolvedInjectedRoutes = false; return { name: 'astro:integration-container', configureServer(server) { runHookServerSetup({ config: settings.config, server, logging }); }, + // Run `load` hook once just to get access to `PluginContext.resolve` + // which allows us to resolve each injectedRoute entryPoint to a real file URL on disk + async load() { + if (hasResolvedInjectedRoutes) return; + // Ensure the injectedRoutes are all resolved to their final paths through Rollup + settings.resolvedInjectedRoutes = await Promise.all(settings.injectedRoutes.map(async injectedRoute => { + let resolvedEntryPoint: URL | undefined; + try { + const resolvedId = await this.resolve(injectedRoute.entryPoint).then(res => res?.id ?? injectedRoute.entryPoint) + const filename = normalizePath(resolvedId); + resolvedEntryPoint = new URL(`file://${filename}`); + } catch {} + return { ...injectedRoute, resolvedEntryPoint } + })) + hasResolvedInjectedRoutes = true; + return; + }, }; } diff --git a/packages/astro/src/vite-plugin-scripts/page-ssr.ts b/packages/astro/src/vite-plugin-scripts/page-ssr.ts index ac6511f7cc90..f88c6b1db0d1 100644 --- a/packages/astro/src/vite-plugin-scripts/page-ssr.ts +++ b/packages/astro/src/vite-plugin-scripts/page-ssr.ts @@ -4,8 +4,6 @@ import type { AstroSettings } from '../@types/astro.js'; import { isPage } from '../core/util.js'; import { PAGE_SSR_SCRIPT_ID } from './index.js'; -const RESOLVED_ENTRYPOINT_SYMBOL = Symbol('astro:resolved-entrypoint'); - export default function astroScriptsPostPlugin({ settings, }: { @@ -29,23 +27,8 @@ export default function astroScriptsPostPlugin({ return; } - await Promise.all(settings.injectedRoutes.map(async route => { - if ((route as any)[RESOLVED_ENTRYPOINT_SYMBOL]) return route; - const resolvedId = await this.resolve(route.entryPoint); - (route as any)[RESOLVED_ENTRYPOINT_SYMBOL] = resolvedId?.id; - return route; - })) - const fileIsPage = isPage(fileURL, settings); - let fileIsInjectedRoute = false; - for (const route of settings.injectedRoutes) { - console.log((route as any)[RESOLVED_ENTRYPOINT_SYMBOL]) - if ((route as any)[RESOLVED_ENTRYPOINT_SYMBOL] === id) { - fileIsInjectedRoute = true; - break; - } - } - if (!(fileIsPage || fileIsInjectedRoute)) return; + if (!fileIsPage) return; const s = new MagicString(code, { filename }); s.prepend(`import '${PAGE_SSR_SCRIPT_ID}';\n`); From 90e19f8c700a767ea9fda6170153d82066e77adf Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Fri, 4 Aug 2023 13:40:47 -0400 Subject: [PATCH 3/8] chore: add changeset --- .changeset/stupid-pants-press.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/stupid-pants-press.md diff --git a/.changeset/stupid-pants-press.md b/.changeset/stupid-pants-press.md new file mode 100644 index 000000000000..61fc33f0d43a --- /dev/null +++ b/.changeset/stupid-pants-press.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Ensure that `injectRoute` is properly detected in monorepos and from node_modules From 3082c7c26976f8fe38e5aef6f9771426077898ba Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Fri, 4 Aug 2023 20:04:41 +0200 Subject: [PATCH 4/8] Fix pnpm workspace injectRoute bug See https://github.com/withastro/astro/issues/7561#issuecomment-1620063634 Closes #7561 --- packages/astro/src/core/build/static-build.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index 8e3cf8fa8802..a182b7bf1814 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -449,7 +449,7 @@ export function makeAstroPageEntryPointFileName( .replace(prefix, '') .replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.'); let route = routes.find((routeData) => { - return routeData.route === pageModuleId; + return routeData.route === pageModuleId || routeData.component === pageModuleId; }); let name = pageModuleId; if (route) { @@ -457,7 +457,7 @@ export function makeAstroPageEntryPointFileName( } if (name.endsWith('/')) name += 'index'; const fileName = `${name.replaceAll('[', '_').replaceAll(']', '_').replaceAll('...', '---')}.mjs`; - if (name.startsWith('..')) { + if (pageModuleId.startsWith('..')) { return `pages${fileName}`; } return fileName; From 6f3af2b85196c39b3cdc5b0954e8651130bc8b60 Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Fri, 4 Aug 2023 20:24:49 +0200 Subject: [PATCH 5/8] Revert "Fix pnpm workspace injectRoute bug" This reverts commit 3082c7c26976f8fe38e5aef6f9771426077898ba. --- packages/astro/src/core/build/static-build.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index a182b7bf1814..8e3cf8fa8802 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -449,7 +449,7 @@ export function makeAstroPageEntryPointFileName( .replace(prefix, '') .replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.'); let route = routes.find((routeData) => { - return routeData.route === pageModuleId || routeData.component === pageModuleId; + return routeData.route === pageModuleId; }); let name = pageModuleId; if (route) { @@ -457,7 +457,7 @@ export function makeAstroPageEntryPointFileName( } if (name.endsWith('/')) name += 'index'; const fileName = `${name.replaceAll('[', '_').replaceAll(']', '_').replaceAll('...', '---')}.mjs`; - if (pageModuleId.startsWith('..')) { + if (name.startsWith('..')) { return `pages${fileName}`; } return fileName; From 3c2671619903611ba8d007fe4b11b76369812411 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Mon, 7 Aug 2023 08:00:47 -0500 Subject: [PATCH 6/8] Update .changeset/stupid-pants-press.md Co-authored-by: Chris Swithinbank --- .changeset/stupid-pants-press.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/stupid-pants-press.md b/.changeset/stupid-pants-press.md index 61fc33f0d43a..c5807d9923ef 100644 --- a/.changeset/stupid-pants-press.md +++ b/.changeset/stupid-pants-press.md @@ -2,4 +2,4 @@ 'astro': patch --- -Ensure that `injectRoute` is properly detected in monorepos and from node_modules +Ensure that injected routes from `node_modules` are properly detected From bd0eadad4745fec24ca8248fa8318eec408bda9d Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Mon, 7 Aug 2023 08:01:44 -0500 Subject: [PATCH 7/8] Update packages/astro/src/vite-plugin-scripts/page-ssr.ts Co-authored-by: Chris Swithinbank --- packages/astro/src/vite-plugin-scripts/page-ssr.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/vite-plugin-scripts/page-ssr.ts b/packages/astro/src/vite-plugin-scripts/page-ssr.ts index f88c6b1db0d1..1a02ca13fc16 100644 --- a/packages/astro/src/vite-plugin-scripts/page-ssr.ts +++ b/packages/astro/src/vite-plugin-scripts/page-ssr.ts @@ -12,7 +12,7 @@ export default function astroScriptsPostPlugin({ return { name: 'astro:scripts:page-ssr', enforce: 'post', - async transform(this, code, id, options) { + transform(this, code, id, options) { if (!options?.ssr) return; const hasInjectedScript = settings.scripts.some((s) => s.stage === 'page-ssr'); From d828b7bcab1683efd7631370abe9203f8d1520b8 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Mon, 7 Aug 2023 11:46:06 -0400 Subject: [PATCH 8/8] refactor: cleanup injectedRoute resolution logic --- .../index.ts | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/packages/astro/src/vite-plugin-integrations-container/index.ts b/packages/astro/src/vite-plugin-integrations-container/index.ts index 7643fe0e1cc7..54c4d5ee3431 100644 --- a/packages/astro/src/vite-plugin-integrations-container/index.ts +++ b/packages/astro/src/vite-plugin-integrations-container/index.ts @@ -1,6 +1,9 @@ -import { normalizePath, type Plugin as VitePlugin } from 'vite'; -import type { AstroSettings } from '../@types/astro.js'; +import type { Plugin as VitePlugin } from 'vite'; +import type { PluginContext } from 'rollup'; +import type { AstroSettings, InjectedRoute, ResolvedInjectedRoute } from '../@types/astro.js'; import type { LogOptions } from '../core/logger/core.js'; + +import { normalizePath } from 'vite'; import { runHookServerSetup } from '../integrations/index.js'; /** Connect Astro integrations into Vite, as needed. */ @@ -11,28 +14,24 @@ export default function astroIntegrationsContainerPlugin({ settings: AstroSettings; logging: LogOptions; }): VitePlugin { - let hasResolvedInjectedRoutes = false; return { name: 'astro:integration-container', configureServer(server) { runHookServerSetup({ config: settings.config, server, logging }); }, - // Run `load` hook once just to get access to `PluginContext.resolve` - // which allows us to resolve each injectedRoute entryPoint to a real file URL on disk - async load() { - if (hasResolvedInjectedRoutes) return; + async buildStart() { // Ensure the injectedRoutes are all resolved to their final paths through Rollup - settings.resolvedInjectedRoutes = await Promise.all(settings.injectedRoutes.map(async injectedRoute => { - let resolvedEntryPoint: URL | undefined; - try { - const resolvedId = await this.resolve(injectedRoute.entryPoint).then(res => res?.id ?? injectedRoute.entryPoint) - const filename = normalizePath(resolvedId); - resolvedEntryPoint = new URL(`file://${filename}`); - } catch {} - return { ...injectedRoute, resolvedEntryPoint } - })) - hasResolvedInjectedRoutes = true; - return; + settings.resolvedInjectedRoutes = await Promise.all(settings.injectedRoutes.map(route => resolveEntryPoint.call(this, route))) }, }; } + +async function resolveEntryPoint(this: PluginContext, route: InjectedRoute): Promise { + const resolvedId = await this.resolve(route.entryPoint) + .then(res => res?.id) + .catch(() => undefined); + if (!resolvedId) return route; + + const resolvedEntryPoint = new URL(`file://${normalizePath(resolvedId)}`); + return { ...route, resolvedEntryPoint }; +}