Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move remaining tests to the static build #2712

Merged
merged 4 commits into from
Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fresh-ladybugs-think.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes use of private .env variables with the static build
56 changes: 37 additions & 19 deletions packages/astro/src/vite-plugin-env/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type * as vite from 'vite';
import type { AstroConfig } from '../@types/astro';
import type { TransformPluginContext } from 'rollup';
import MagicString from 'magic-string';
import { fileURLToPath } from 'url';
import { loadEnv } from 'vite';
Expand Down Expand Up @@ -30,7 +31,7 @@ function getPrivateEnv(viteConfig: vite.ResolvedConfig, astroConfig: AstroConfig
if (privateKeys.length === 0) {
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>) {
Expand All @@ -43,39 +44,56 @@ function referencesPrivateKey(source: string, privateEnv: Record<string, any>) {
export default function envVitePlugin({ config: astroConfig }: EnvPluginOptions): vite.PluginOption {
let privateEnv: Record<string, any> | null;
let config: vite.ResolvedConfig;
let replacements: Record<string, string>;
let pattern: RegExp | undefined;
return {
name: 'astro:vite-plugin-env',
enforce: 'pre',

configResolved(resolvedConfig) {
config = resolvedConfig;
if (config.envPrefix) {
}
},

async transform(source, id, options) {
const ssr = options?.ssr === true;
if (!ssr) return source;
if (!source.includes('import.meta')) return source;
if (!/\benv\b/.test(source)) return source;

if(!ssr) {
return source;
}

if(!source.includes('import.meta') || !/\benv\b/.test(source)) {
return source;
}

if (typeof privateEnv === 'undefined') {
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;

// Find matches for *private* env and do our own replacement.
const s = new MagicString(source);
// prettier-ignore
s.prepend(`import.meta.env = new Proxy(import.meta.env, {` +
`get(target, prop, reciever) {` +
`const PRIVATE = ${JSON.stringify(privateEnv)};` +
`if (typeof PRIVATE[prop] !== 'undefined') {` +
`return PRIVATE[prop];` +
`}` +
`return Reflect.get(target, prop, reciever);` +
`}` +
`});\n`);
let match: RegExpExecArray | null

while ((match = pattern.exec(source))) {
const start = match.index
const end = start + match[0].length
const replacement = '' + replacements[match[1]]
s.overwrite(start, end, replacement)
}

return s.toString();
},
Expand Down
9 changes: 4 additions & 5 deletions packages/astro/test/astro-envs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ describe('Environment Variables', () => {
before(async () => {
fixture = await loadFixture({
projectRoot: './fixtures/astro-envs/',
buildOptions: { legacyBuild: true } // TODO make this test work without legacyBuild
});

await fixture.build();
Expand All @@ -25,7 +24,7 @@ describe('Environment Variables', () => {
});

it('includes public env in client-side JS', async () => {
let dirs = await fixture.readdir('/assets');
let dirs = await fixture.readdir('/');
let found = false;

// Look in all of the .js files to see if the public env is inlined.
Expand All @@ -34,7 +33,7 @@ describe('Environment Variables', () => {
await Promise.all(
dirs.map(async (path) => {
if (path.endsWith('.js')) {
let js = await fixture.readFile(`/assets/${path}`);
let js = await fixture.readFile(`/${path}`);
if (js.includes('BLUE_BAYOU')) {
found = true;
}
Expand All @@ -46,7 +45,7 @@ describe('Environment Variables', () => {
});

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;

// Look in all of the .js files to see if the public env is inlined.
Expand All @@ -55,7 +54,7 @@ describe('Environment Variables', () => {
await Promise.all(
dirs.map(async (path) => {
if (path.endsWith('.js')) {
let js = await fixture.readFile(`/assets/${path}`);
let js = await fixture.readFile(`/${path}`);
if (js.includes('CLUB_33')) {
found = true;
}
Expand Down
3 changes: 0 additions & 3 deletions packages/astro/test/lit-element.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ describe('LitElement test', function () {
fixture = await loadFixture({
projectRoot: './fixtures/lit-element/',
renderers: ['@astrojs/renderer-lit'],
buildOptions: {
legacyBuild: true
}
});
await fixture.build();
});
Expand Down