diff --git a/.changeset/strange-students-shake.md b/.changeset/strange-students-shake.md new file mode 100644 index 000000000000..9e5bd382bf3e --- /dev/null +++ b/.changeset/strange-students-shake.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fixes environment variables replacement for `export const prerender` diff --git a/packages/astro/src/vite-plugin-env/index.ts b/packages/astro/src/vite-plugin-env/index.ts index 7d91b3552491..2e16cc5bf337 100644 --- a/packages/astro/src/vite-plugin-env/index.ts +++ b/packages/astro/src/vite-plugin-env/index.ts @@ -14,6 +14,9 @@ const importMetaEnvOnlyRe = /\bimport\.meta\.env\b(?!\.)/; // Match valid JS variable names (identifiers), which accepts most alphanumeric characters, // except that the first character cannot be a number. const isValidIdentifierRe = /^[_$a-zA-Z][_$a-zA-Z0-9]*$/; +// Match `export const prerender = import.meta.env.*` since `vite=plugin-scanner` requires +// the `import.meta.env.*` to always be replaced. +const exportConstPrerenderRe = /\bexport\s+const\s+prerender\s*=\s*import\.meta\.env\.(.+?)\b/; function getPrivateEnv( viteConfig: vite.ResolvedConfig, @@ -156,6 +159,7 @@ export default function envVitePlugin({ settings }: EnvPluginOptions): vite.Plug // In dev, we can assign the private env vars to `import.meta.env` directly for performance if (isDev) { const s = new MagicString(source); + if (!devImportMetaEnvPrepend) { devImportMetaEnvPrepend = `Object.assign(import.meta.env,{`; for (const key in privateEnv) { @@ -164,6 +168,16 @@ export default function envVitePlugin({ settings }: EnvPluginOptions): vite.Plug devImportMetaEnvPrepend += '});'; } s.prepend(devImportMetaEnvPrepend); + + // EDGE CASE: We need to do a static replacement for `export const prerender` for `vite-plugin-scanner` + s.replace(exportConstPrerenderRe, (m, key) => { + if (privateEnv[key] != null) { + return `export const prerender = ${privateEnv[key]}`; + } else { + return m; + } + }); + return { code: s.toString(), map: s.generateMap({ hires: 'boundary' }), diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 0d87e77110f3..84f599bcdac0 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -140,6 +140,44 @@ describe('Prerendering', () => { expect($('h1').text()).to.equal('Two'); }); }); + + describe('Dev', () => { + let devServer; + + before(async () => { + process.env.PRERENDER = true; + + fixture = await loadFixture({ + root: './fixtures/prerender/', + output: 'server', + adapter: nodejs({ mode: 'standalone' }), + }); + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + delete process.env.PRERENDER; + }); + + it('Can render SSR route', async () => { + const res = await fixture.fetch(`/one`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('One'); + }); + + it('Can render prerendered route', async () => { + const res = await fixture.fetch(`/two`); + const html = await res.text(); + const $ = cheerio.load(html); + + expect(res.status).to.equal(200); + expect($('h1').text()).to.equal('Two'); + }); + }); }); describe('Hybrid rendering', () => {