From b60cc0538bc5c68dd411117780d20d892530789d Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Tue, 2 Aug 2022 14:07:17 -0500 Subject: [PATCH] Add generic plugin for `page-ssr` injection (#4049) * feat: add generic page-ssr plugin * refactor: remove page-specific logic from astro/markdown/mdx plugins * refactor: revert changes to vite-plugin-scripts * fix: handle injected `page` scripts in build * fix: prepend injected `page` scripts with `/@id/` in dev Co-authored-by: Nate Moore --- .changeset/plenty-hats-grow.md | 6 +++ packages/astro/src/core/build/generate.ts | 14 +++++- packages/astro/src/core/build/static-build.ts | 5 ++ .../astro/src/core/build/vite-plugin-ssr.ts | 10 +++- packages/astro/src/core/create-vite.ts | 2 + packages/astro/src/core/render/dev/index.ts | 7 +++ packages/astro/src/vite-plugin-astro/index.ts | 14 ------ .../astro/src/vite-plugin-markdown/index.ts | 8 +-- .../astro/src/vite-plugin-scripts/page-ssr.ts | 50 +++++++++++++++++++ packages/integrations/mdx/src/index.ts | 7 --- 10 files changed, 93 insertions(+), 30 deletions(-) create mode 100644 .changeset/plenty-hats-grow.md create mode 100644 packages/astro/src/vite-plugin-scripts/page-ssr.ts diff --git a/.changeset/plenty-hats-grow.md b/.changeset/plenty-hats-grow.md new file mode 100644 index 000000000..d7238f840 --- /dev/null +++ b/.changeset/plenty-hats-grow.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/mdx': patch +--- + +Improve `injectScript` handling for non-Astro pages diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index fb125dd28..cbd8e1c2e 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -18,7 +18,7 @@ import { removeTrailingForwardSlash, } from '../../core/path.js'; import type { RenderOptions } from '../../core/render/core'; -import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; +import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { call as callEndpoint } from '../endpoint/index.js'; import { debug, info } from '../logger/core.js'; import { render } from '../render/core.js'; @@ -272,6 +272,18 @@ async function generatePath( const links = createLinkStylesheetElementSet(linkIds.reverse(), site); const scripts = createModuleScriptsSet(hoistedScripts ? [hoistedScripts] : [], site); + if (astroConfig._ctx.scripts.some((script) => script.stage === 'page')) { + const hashedFilePath = internals.entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID); + if (typeof hashedFilePath !== 'string') { + throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`); + } + const src = prependForwardSlash(npath.posix.join(astroConfig.base, hashedFilePath)); + scripts.add({ + props: { type: 'module', src }, + children: '', + }) + } + // Add all injected scripts to the page. for (const script of astroConfig._ctx.scripts) { if (script.stage === 'head-inline') { diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index 99b58318d..19778ae4b 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -8,6 +8,7 @@ import { prependForwardSlash } from '../../core/path.js'; import { emptyDir, isModeServerWithNoAdapter, removeDir } from '../../core/util.js'; import { runHookBuildSetup } from '../../integrations/index.js'; import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js'; +import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import type { ViteConfigWithSSR } from '../create-vite'; import { info } from '../logger/core.js'; import { generatePages } from './generate.js'; @@ -85,6 +86,10 @@ Example: ...internals.discoveredScripts, ]); + if (astroConfig._ctx.scripts.some((script) => script.stage === 'page')) { + clientInput.add(PAGE_SCRIPT_ID); + } + // Run client build first, so the assets can be fed into the SSR rendered version. timer.clientBuild = performance.now(); await clientBuild(opts, internals, clientInput); diff --git a/packages/astro/src/core/build/vite-plugin-ssr.ts b/packages/astro/src/core/build/vite-plugin-ssr.ts index 5ce5640a2..e7fbfd995 100644 --- a/packages/astro/src/core/build/vite-plugin-ssr.ts +++ b/packages/astro/src/core/build/vite-plugin-ssr.ts @@ -8,7 +8,7 @@ import glob from 'fast-glob'; import * as fs from 'fs'; import { fileURLToPath } from 'url'; import { runHookBuildSsr } from '../../integrations/index.js'; -import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; +import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { pagesVirtualModuleId } from '../app/index.js'; import { serializeRouteData } from '../routing/index.js'; import { addRollupInput } from './add-rollup-input.js'; @@ -123,12 +123,19 @@ function buildManifest( const { astroConfig } = opts; const routes: SerializedRouteInfo[] = []; + const entryModules = Object.fromEntries(internals.entrySpecifierToBundleMap.entries()); + if (astroConfig._ctx.scripts.some((script) => script.stage === 'page')) { + staticFiles.push(entryModules[PAGE_SCRIPT_ID]); + } for (const pageData of eachPageData(internals)) { const scripts: SerializedRouteInfo['scripts'] = []; if (pageData.hoistedScript) { scripts.unshift(pageData.hoistedScript); } + if (astroConfig._ctx.scripts.some((script) => script.stage === 'page')) { + scripts.push({ type: 'external', value: entryModules[PAGE_SCRIPT_ID] }); + } routes.push({ file: '', @@ -144,7 +151,6 @@ function buildManifest( } // HACK! Patch this special one. - const entryModules = Object.fromEntries(internals.entrySpecifierToBundleMap.entries()); if (!(BEFORE_HYDRATION_SCRIPT_ID in entryModules)) { entryModules[BEFORE_HYDRATION_SCRIPT_ID] = 'data:text/javascript;charset=utf-8,//[no before-hydration script]'; diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 7b3a8070f..631c1dc2b 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -14,6 +14,7 @@ import astroIntegrationsContainerPlugin from '../vite-plugin-integrations-contai import jsxVitePlugin from '../vite-plugin-jsx/index.js'; import markdownVitePlugin from '../vite-plugin-markdown/index.js'; import astroScriptsPlugin from '../vite-plugin-scripts/index.js'; +import astroScriptsPageSSRPlugin from '../vite-plugin-scripts/page-ssr.js'; import { createCustomViteLogger } from './errors.js'; import { resolveDependency } from './util.js'; @@ -80,6 +81,7 @@ export async function createVite( jsxVitePlugin({ config: astroConfig, logging }), astroPostprocessVitePlugin({ config: astroConfig }), astroIntegrationsContainerPlugin({ config: astroConfig }), + astroScriptsPageSSRPlugin({ config: astroConfig }), ], publicDir: fileURLToPath(astroConfig.publicDir), root: fileURLToPath(astroConfig.root), diff --git a/packages/astro/src/core/render/dev/index.ts b/packages/astro/src/core/render/dev/index.ts index a6643fc35..6cf75a6cc 100644 --- a/packages/astro/src/core/render/dev/index.ts +++ b/packages/astro/src/core/render/dev/index.ts @@ -9,6 +9,7 @@ import type { SSRElement, SSRLoadedRenderer, } from '../../../@types/astro'; +import { PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js'; import { prependForwardSlash } from '../../../core/path.js'; import { LogOptions } from '../../logger/core.js'; import { isPage } from '../../util.js'; @@ -124,6 +125,7 @@ export async function render( children: '', }); } + // TODO: We should allow adding generic HTML elements to the head, not just scripts for (const script of astroConfig._ctx.scripts) { if (script.stage === 'head-inline') { @@ -131,6 +133,11 @@ export async function render( props: {}, children: script.content, }); + } else if (script.stage === 'page' && isPage(filePath, astroConfig)) { + scripts.add({ + props: { type: 'module', src: `/@id/${PAGE_SCRIPT_ID}` }, + children: '', + }); } } diff --git a/packages/astro/src/vite-plugin-astro/index.ts b/packages/astro/src/vite-plugin-astro/index.ts index b4925d0fd..f38d5e5ca 100644 --- a/packages/astro/src/vite-plugin-astro/index.ts +++ b/packages/astro/src/vite-plugin-astro/index.ts @@ -9,8 +9,6 @@ import esbuild from 'esbuild'; import slash from 'slash'; import { fileURLToPath } from 'url'; import { isRelativePath, startsWithForwardSlash } from '../core/path.js'; -import { resolvePages } from '../core/util.js'; -import { PAGE_SCRIPT_ID, PAGE_SSR_SCRIPT_ID } from '../vite-plugin-scripts/index.js'; import { getFileInfo } from '../vite-plugin-utils/index.js'; import { cachedCompilation, CompileProps, getCachedSource } from './compile.js'; import { handleHotUpdate, trackCSSDependencies } from './hmr.js'; @@ -215,14 +213,6 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu } const filename = normalizeFilename(parsedId.filename); - let isPage = false; - try { - const fileUrl = new URL(`file://${filename}`); - isPage = fileUrl.pathname.startsWith(resolvePages(config).pathname); - } catch {} - if (isPage && config._ctx.scripts.some((s) => s.stage === 'page')) { - source += `\n