0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-03-03 22:57:08 -05:00

Move remaining tests to the static build (#2712)

* Move lit test to the static build

* Migrate astro-env plugin to work in the static build

* Do not remove vite:define

* Adds a changeset
This commit is contained in:
Matthew Phillips 2022-03-03 16:12:21 -05:00 committed by Nate Moore
parent 556e51eecc
commit 28f54182e4
4 changed files with 46 additions and 27 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes use of private .env variables with the static build

View file

@ -1,5 +1,6 @@
import type * as vite from 'vite'; import type * as vite from 'vite';
import type { AstroConfig } from '../@types/astro'; import type { AstroConfig } from '../@types/astro';
import type { TransformPluginContext } from 'rollup';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { loadEnv } from 'vite'; import { loadEnv } from 'vite';
@ -30,7 +31,7 @@ function getPrivateEnv(viteConfig: vite.ResolvedConfig, astroConfig: AstroConfig
if (privateKeys.length === 0) { if (privateKeys.length === 0) {
return null; return null;
} }
return Object.fromEntries(privateKeys.map((key) => [key, fullEnv[key]])); return Object.fromEntries(privateKeys.map((key) => [key, JSON.stringify(fullEnv[key])]));
} }
function referencesPrivateKey(source: string, privateEnv: Record<string, any>) { function referencesPrivateKey(source: string, privateEnv: Record<string, any>) {
@ -43,39 +44,56 @@ function referencesPrivateKey(source: string, privateEnv: Record<string, any>) {
export default function envVitePlugin({ config: astroConfig }: EnvPluginOptions): vite.PluginOption { export default function envVitePlugin({ config: astroConfig }: EnvPluginOptions): vite.PluginOption {
let privateEnv: Record<string, any> | null; let privateEnv: Record<string, any> | null;
let config: vite.ResolvedConfig; let config: vite.ResolvedConfig;
let replacements: Record<string, string>;
let pattern: RegExp | undefined;
return { return {
name: 'astro:vite-plugin-env', name: 'astro:vite-plugin-env',
enforce: 'pre', enforce: 'pre',
configResolved(resolvedConfig) { configResolved(resolvedConfig) {
config = resolvedConfig; config = resolvedConfig;
if (config.envPrefix) {
}
}, },
async transform(source, id, options) { async transform(source, id, options) {
const ssr = options?.ssr === true; const ssr = options?.ssr === true;
if (!ssr) return source;
if (!source.includes('import.meta')) return source; if(!ssr) {
if (!/\benv\b/.test(source)) return source; return source;
}
if(!source.includes('import.meta') || !/\benv\b/.test(source)) {
return source;
}
if (typeof privateEnv === 'undefined') { if (typeof privateEnv === 'undefined') {
privateEnv = getPrivateEnv(config, astroConfig); privateEnv = getPrivateEnv(config, astroConfig);
if(privateEnv) {
const entries = Object.entries(privateEnv).map(([key, value]) => ([`import.meta.env.${key}`, value]));
replacements = Object.fromEntries(entries);
pattern = new RegExp(
// Do not allow preceding '.', but do allow preceding '...' for spread operations
'(?<!(?<!\\.\\.)\\.)\\b(' +
Object.keys(replacements)
.map((str) => {
return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
})
.join('|') +
// prevent trailing assignments
')\\b(?!\\s*?=[^=])', 'g');
}
} }
if (!privateEnv) return source;
if (!privateEnv || !pattern) return source;
if (!referencesPrivateKey(source, privateEnv)) return source; if (!referencesPrivateKey(source, privateEnv)) return source;
// Find matches for *private* env and do our own replacement.
const s = new MagicString(source); const s = new MagicString(source);
// prettier-ignore let match: RegExpExecArray | null
s.prepend(`import.meta.env = new Proxy(import.meta.env, {` +
`get(target, prop, reciever) {` + while ((match = pattern.exec(source))) {
`const PRIVATE = ${JSON.stringify(privateEnv)};` + const start = match.index
`if (typeof PRIVATE[prop] !== 'undefined') {` + const end = start + match[0].length
`return PRIVATE[prop];` + const replacement = '' + replacements[match[1]]
`}` + s.overwrite(start, end, replacement)
`return Reflect.get(target, prop, reciever);` + }
`}` +
`});\n`);
return s.toString(); return s.toString();
}, },

View file

@ -7,7 +7,6 @@ describe('Environment Variables', () => {
before(async () => { before(async () => {
fixture = await loadFixture({ fixture = await loadFixture({
projectRoot: './fixtures/astro-envs/', projectRoot: './fixtures/astro-envs/',
buildOptions: { legacyBuild: true } // TODO make this test work without legacyBuild
}); });
await fixture.build(); await fixture.build();
@ -25,7 +24,7 @@ describe('Environment Variables', () => {
}); });
it('includes public env in client-side JS', async () => { it('includes public env in client-side JS', async () => {
let dirs = await fixture.readdir('/assets'); let dirs = await fixture.readdir('/');
let found = false; let found = false;
// Look in all of the .js files to see if the public env is inlined. // Look in all of the .js files to see if the public env is inlined.
@ -34,7 +33,7 @@ describe('Environment Variables', () => {
await Promise.all( await Promise.all(
dirs.map(async (path) => { dirs.map(async (path) => {
if (path.endsWith('.js')) { if (path.endsWith('.js')) {
let js = await fixture.readFile(`/assets/${path}`); let js = await fixture.readFile(`/${path}`);
if (js.includes('BLUE_BAYOU')) { if (js.includes('BLUE_BAYOU')) {
found = true; found = true;
} }
@ -46,7 +45,7 @@ describe('Environment Variables', () => {
}); });
it('does not include private env in client-side JS', async () => { it('does not include private env in client-side JS', async () => {
let dirs = await fixture.readdir('/assets'); let dirs = await fixture.readdir('/');
let found = false; let found = false;
// Look in all of the .js files to see if the public env is inlined. // Look in all of the .js files to see if the public env is inlined.
@ -55,7 +54,7 @@ describe('Environment Variables', () => {
await Promise.all( await Promise.all(
dirs.map(async (path) => { dirs.map(async (path) => {
if (path.endsWith('.js')) { if (path.endsWith('.js')) {
let js = await fixture.readFile(`/assets/${path}`); let js = await fixture.readFile(`/${path}`);
if (js.includes('CLUB_33')) { if (js.includes('CLUB_33')) {
found = true; found = true;
} }

View file

@ -18,9 +18,6 @@ describe('LitElement test', function () {
fixture = await loadFixture({ fixture = await loadFixture({
projectRoot: './fixtures/lit-element/', projectRoot: './fixtures/lit-element/',
renderers: ['@astrojs/renderer-lit'], renderers: ['@astrojs/renderer-lit'],
buildOptions: {
legacyBuild: true
}
}); });
await fixture.build(); await fixture.build();
}); });