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

feat(env): server/public variables #10881

Merged
merged 48 commits into from May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c7fffe0
feat: add schema, types and envField
florian-lefebvre Apr 17, 2024
0e90c5d
feat: move things around
florian-lefebvre Apr 18, 2024
94d6ffc
feat: add validators
florian-lefebvre Apr 19, 2024
d717361
feat: rework everything
florian-lefebvre Apr 20, 2024
d9ce895
feat: default
florian-lefebvre Apr 20, 2024
f136b1b
chore: space
florian-lefebvre Apr 20, 2024
0260bbb
Merge branch 'feat/astro-env-config' into feat/astro-env-validators
florian-lefebvre Apr 20, 2024
b84cea9
feat: reuse types
florian-lefebvre Apr 20, 2024
3f32ea6
feat: work on test
florian-lefebvre Apr 20, 2024
ff99f0d
feat: write test
florian-lefebvre Apr 20, 2024
8896fa7
feat: add test
florian-lefebvre Apr 20, 2024
9d8d425
Merge branch 'feat/astro-env-config' into feat/astro-env-validators
florian-lefebvre Apr 20, 2024
07f586e
feat: add vite plugin
florian-lefebvre Apr 20, 2024
5063b1f
feat: update zod custom validation
florian-lefebvre Apr 21, 2024
b23233c
feat: validation logic
florian-lefebvre Apr 21, 2024
e02b722
feat: work on types injection
florian-lefebvre Apr 21, 2024
e9d99a1
Merge branch 'feat/astro-env' into feat/astro-env-vite-plugin
florian-lefebvre Apr 22, 2024
bff9024
fix: test
florian-lefebvre Apr 22, 2024
fc983d1
Merge branch 'feat/astro-env-vite-plugin' into feat/astro-env-client-…
florian-lefebvre Apr 22, 2024
518fd15
fix: test
florian-lefebvre Apr 22, 2024
eeda833
fix: test
florian-lefebvre Apr 22, 2024
9516c2c
fix: cli tests
florian-lefebvre Apr 22, 2024
f23296d
feat: make things work
florian-lefebvre Apr 22, 2024
37ec524
feat: address todos
florian-lefebvre Apr 22, 2024
ae92463
Discard changes to examples/basics/astro.config.mjs
florian-lefebvre Apr 22, 2024
dc92fb6
Discard changes to examples/basics/src/env.d.ts
florian-lefebvre Apr 22, 2024
4496bc9
Merge branch 'feat/astro-env' into feat/astro-env-client-public
florian-lefebvre Apr 23, 2024
f6a993a
fix: test
florian-lefebvre Apr 23, 2024
1384136
feat: refactor astro sync test
florian-lefebvre Apr 23, 2024
26e2b82
feat: update test to check env types
florian-lefebvre Apr 23, 2024
f4b09b8
fix: fixture
florian-lefebvre Apr 23, 2024
c1539ed
feat: simplify injected types
florian-lefebvre Apr 24, 2024
4b5c28c
feat: move plugin
florian-lefebvre Apr 24, 2024
0c99784
fix: imports
florian-lefebvre Apr 24, 2024
20875e7
feat: add tests for getType
florian-lefebvre Apr 24, 2024
82db951
feat: add test
florian-lefebvre Apr 24, 2024
e093397
Update index.ts
florian-lefebvre Apr 25, 2024
770b806
fix: variable name conflict
florian-lefebvre Apr 25, 2024
e29e48d
Apply suggestions from code review
florian-lefebvre Apr 25, 2024
aa0312d
feat: harcode constants
florian-lefebvre Apr 25, 2024
353446e
feat: rename condition to meetsCondition
florian-lefebvre Apr 25, 2024
82a3142
feat: rename function
florian-lefebvre Apr 25, 2024
4e37b39
feat: simplify content/dts computation
florian-lefebvre Apr 25, 2024
5cb7e59
feat: throw one error with all invalid variables
florian-lefebvre Apr 25, 2024
5f12f8d
feat: refactor for clarity and prepare server/public
florian-lefebvre Apr 25, 2024
e519f82
feat: use more vite hooks
florian-lefebvre Apr 25, 2024
0c1f180
feat: add support for server/public variables
florian-lefebvre Apr 25, 2024
fccfc35
Merge branch 'feat/astro-env' into feat/astro-env-server-public
florian-lefebvre Apr 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion packages/astro/src/core/errors/errors-data.ts
Expand Up @@ -1164,7 +1164,19 @@ export const i18nNotEnabled = {
export const EnvInvalidVariables = {
name: 'EnvInvalidVariable',
title: 'Invalid Environment variable',
message: (variables: string) => `The following environment variable does not match the type and constraints defined in \`experimental.env.schema\`:\n\n${variables}\n`,
message: (variables: string) =>
`The following environment variable does not match the type and constraints defined in \`experimental.env.schema\`:\n\n${variables}\n`,
} satisfies ErrorData;

/**
* @docs
* @description
* Module is only available server-side
*/
export const EnvServerOnlyModule = {
name: 'EnvServerOnlyModule',
title: 'Module is only available server-side',
message: (name: string) => `The "${name}" module is only available server-side.`,
Comment on lines +1171 to +1179
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some thoughts for myself: I know we have a few virtual modules that currently only meant to work in the server-side only. Maybe we can consider making this more generic later. We don't have to change this now.

} satisfies ErrorData;

/**
Expand Down
32 changes: 25 additions & 7 deletions packages/astro/src/env/vite-plugin-env-virtual-mod.ts
Expand Up @@ -4,7 +4,9 @@ import type { Logger } from '../core/logger/core.js';
import {
ENV_TYPES_FILE,
RESOLVED_VIRTUAL_CLIENT_MODULE_ID,
RESOLVED_VIRTUAL_SERVER_MODULE_ID,
VIRTUAL_CLIENT_MODULE_ID,
VIRTUAL_SERVER_MODULE_ID,
} from './constants.js';
import type { EnvSchema } from './schema.js';
import { validateEnvVariable } from './validators.js';
Expand All @@ -29,7 +31,8 @@ export function astroEnvVirtualModPlugin({
return;
}

let clientTemplates: ReturnType<typeof getClientTemplates> | null = null;
let clientTemplates: ReturnType<typeof getTemplates> | null = null;
let serverTemplates: ReturnType<typeof getTemplates> | null = null;

logger.warn('env', 'This feature is experimental. TODO:');

Expand All @@ -47,8 +50,9 @@ export function astroEnvVirtualModPlugin({
''
);
const validatedVariables = validatePublicVariables({ schema, loadedEnv });
clientTemplates = getClientTemplates({ validatedVariables });
generateDts({ settings, fs, content: clientTemplates.dts });
clientTemplates = getTemplates({ validatedVariables, context: 'client' });
serverTemplates = getTemplates({ validatedVariables, context: 'server' });
generateDts({ settings, fs, content: `${clientTemplates.dts}\n\n${serverTemplates.dts}` });
},
buildEnd() {
clientTemplates = null;
Expand All @@ -57,11 +61,23 @@ export function astroEnvVirtualModPlugin({
if (id === VIRTUAL_CLIENT_MODULE_ID) {
return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;
}
if (id === VIRTUAL_SERVER_MODULE_ID) {
return RESOLVED_VIRTUAL_SERVER_MODULE_ID
}
},
load(id) {
load(id, options) {
if (id === RESOLVED_VIRTUAL_CLIENT_MODULE_ID) {
return clientTemplates!.content;
}
if (id === RESOLVED_VIRTUAL_SERVER_MODULE_ID) {
if (options?.ssr) {
ematipico marked this conversation as resolved.
Show resolved Hide resolved
return serverTemplates!.content;
}
throw new AstroError({
...AstroErrorData.EnvServerOnlyModule,
message: AstroErrorData.EnvServerOnlyModule.message(VIRTUAL_SERVER_MODULE_ID),
});
}
},
};
}
Expand Down Expand Up @@ -111,22 +127,24 @@ function validatePublicVariables({
return valid;
}

function getClientTemplates({
function getTemplates({
validatedVariables,
context,
}: {
validatedVariables: ReturnType<typeof validatePublicVariables>;
context: 'server' | 'client';
}) {
const contentParts: Array<string> = [];
const dtsParts: Array<string> = [];

for (const { key, type, value } of validatedVariables.filter((e) => e.context === 'client')) {
for (const { key, type, value } of validatedVariables.filter((e) => e.context === context)) {
contentParts.push(`export const ${key} = ${JSON.stringify(value)};`);
dtsParts.push(`export const ${key}: ${type};`);
}

const content = contentParts.join('\n');

const dts = `declare module "astro:env/client" {
const dts = `declare module "astro:env/${context}" {
${dtsParts.join('\n ')}
}`;

Expand Down
@@ -0,0 +1,12 @@
import { defineConfig, envField } from 'astro/config';

// https://astro.build/config
export default defineConfig({
experimental: {
env: {
schema: {
PUBLIC_FOO: envField.string({ context: "server", access: "public", optional: true, default: "ABC" }),
}
}
}
});
@@ -0,0 +1,8 @@
{
"name": "@test/astro-env-server-fail",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
@@ -0,0 +1,3 @@
<script>
import { PUBLIC_FOO } from "astro:env/server"
</script>
@@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/base"
}
1 change: 1 addition & 0 deletions packages/astro/test/fixtures/astro-env/astro.config.mjs
Expand Up @@ -7,6 +7,7 @@ export default defineConfig({
schema: {
PUBLIC_FOO: envField.string({ context: "client", access: "public", optional: true, default: "ABC" }),
PUBLIC_BAR: envField.string({ context: "client", access: "public", optional: true, default: "DEF" }),
PUBLIC_BAZ: envField.string({ context: "server", access: "public", optional: true, default: "GHI" }),
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion packages/astro/test/fixtures/astro-env/src/pages/index.astro
@@ -1,5 +1,8 @@
---
import { PUBLIC_FOO } from "astro:env/client"
import { PUBLIC_BAZ } from "astro:env/server"

console.log({ PUBLIC_BAZ })
---

<div id="server-rendered">{PUBLIC_FOO}</div>
Expand All @@ -9,4 +12,4 @@ import { PUBLIC_FOO } from "astro:env/client"
import { PUBLIC_BAR } from "astro:env/client"

document.getElementById("client-rendered").innerText = PUBLIC_BAR
</script>
</script>
50 changes: 50 additions & 0 deletions packages/astro/test/units/env/env-public.test.js
@@ -0,0 +1,50 @@
import assert from 'node:assert/strict';
import { before, describe, it } from 'node:test';
import { loadFixture } from '../../test-utils.js';
import { EnvServerOnlyModule } from '../../../dist/core/errors/errors-data.js';
import { AstroError } from '../../../dist/core/errors/errors.js';

describe('astro:env public variables', () => {
/** @type {Awaited<ReturnType<typeof loadFixture>>} */
let fixture;

describe('Client variables', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/astro-env/',
});
await fixture.build();
});

it('builds without throwing', async () => {
assert.equal(true, true);
});

it('includes client/public env in build', async () => {
let indexHtml = await fixture.readFile('/index.html');

assert.equal(indexHtml.includes('ABC'), true);
assert.equal(indexHtml.includes('DEF'), true);
});

it('does not include server/public env in build', async () => {
let indexHtml = await fixture.readFile('/index.html');

assert.equal(indexHtml.includes('GHI'), false);
});
});

describe('Server variables', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/astro-env-server-fail/',
});
});

it('throws if server module is called on the client', async () => {
const error = await fixture.build().catch(err => err);
assert.equal(error instanceof AstroError, true)
assert.equal(error.name, EnvServerOnlyModule.name);
});
});
});
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.