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

Generate dynamic env types #6413

Merged
merged 4 commits into from
Aug 30, 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/dull-cheetahs-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

[breaking] remove App.PrivateEnv and App.PublicEnv in favour of generated types

Choose a reason for hiding this comment

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

Suggested change
[breaking] remove App.PrivateEnv and App.PublicEnv in favour of generated types
[breaking] remove App.PrivateEnv and App.PublicEnv in favor of generated types

Filthy european

Copy link
Member Author

Choose a reason for hiding this comment

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

🇬🇧

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
[breaking] remove App.PrivateEnv and App.PublicEnv in favour of generated types
[breaking] remouve App.PrivateEnv and App.PublicEnv in favour of generated types

Copy link
Member Author

Choose a reason for hiding this comment

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

🇬🇧

5 changes: 5 additions & 0 deletions .changeset/lovely-otters-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'create-svelte': patch
---

Remove App.PrivateEnv and App.PublicEnv placeholders
4 changes: 0 additions & 4 deletions packages/create-svelte/templates/default/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,4 @@ declare namespace App {
// interface PageData {}

// interface Platform {}

// interface PrivateEnv {}

// interface PublicEnv {}
}
2 changes: 0 additions & 2 deletions packages/create-svelte/templates/libskeleton/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,4 @@ declare namespace App {
// interface Locals {}
// interface PageData {}
// interface Platform {}
// interface PrivateEnv {}
// interface PublicEnv {}
}
2 changes: 0 additions & 2 deletions packages/create-svelte/templates/skeleton/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@ declare namespace App {
// interface Locals {}
// interface PageData {}
// interface Platform {}
// interface PrivateEnv {}
// interface PublicEnv {}
}
8 changes: 8 additions & 0 deletions packages/kit/scripts/special-types/$env+dynamic+private.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) (or running [`vite preview`](https://kit.svelte.dev/docs/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#kit-env-publicprefix).

This module cannot be imported into client-side code.

```ts
import { env } from '$env/dynamic/private';
console.log(env.DEPLOYMENT_SPECIFIC_VARIABLE);
```
8 changes: 8 additions & 0 deletions packages/kit/scripts/special-types/$env+dynamic+public.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Similar to [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#kit-env-publicprefix) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.

Note that public dynamic environment variables must all be sent from the server to the client, causing larger network requests — when possible, use `$env/static/public` instead.

```ts
import { env } from '$env/dynamic/public';
console.log(env.PUBLIC_DEPLOYMENT_SPECIFIC_VARIABLE);
```
17 changes: 16 additions & 1 deletion packages/kit/src/core/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function create_dynamic_module(type) {
* @param {Record<string, string>} env
* @returns {string}
*/
export function create_types(id, env) {
export function create_static_types(id, env) {
const declarations = Object.keys(env)
.filter((k) => valid_identifier.test(k))
.map((k) => `\texport const ${k}: string;`)
Expand All @@ -43,6 +43,21 @@ export function create_types(id, env) {
return `declare module '${id}' {\n${declarations}\n}`;
}

/**
* @param {string} id
* @param {Record<string, string>} env
* @returns {string}
*/
export function create_dynamic_types(id, env) {
const properties = Object.keys(env)
.filter((k) => valid_identifier.test(k))
.map((k) => `\t\t${k}: string;`);

properties.push(`\t\t[key: string]: string | undefined;`);

return `declare module '${id}' {\n\texport const env: {\n${properties.join('\n')}\n\t}\n}`;
}

export const reserved = new Set([
'do',
'if',
Expand Down
46 changes: 36 additions & 10 deletions packages/kit/src/core/sync/write_ambient.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
import fs from 'fs';
import path from 'path';
import { get_env } from '../../exports/vite/utils.js';
import { GENERATED_COMMENT } from '../../constants.js';
import { create_types } from '../env.js';
import { create_dynamic_types, create_static_types } from '../env.js';
import { write_if_changed } from './utils.js';
import { fileURLToPath } from 'url';

const types_reference = '/// <reference types="@sveltejs/kit" />\n\n';
const descriptions_dir = fileURLToPath(new URL('../../../scripts/special-types', import.meta.url));

/** @param {string} filename */
function read_description(filename) {
const content = fs.readFileSync(`${descriptions_dir}/${filename}`, 'utf8');
return `/**\n${content
.trim()
.split('\n')
.map((line) => ` * ${line}`)
.join('\n')}\n */`;
}

/**
* @param {{ public: Record<string, string>, private: Record<string, string> }} env
*/
const template = (env) => `
${GENERATED_COMMENT}

/// <reference types="@sveltejs/kit" />

${read_description('$env+static+private.md')}
${create_static_types('$env/static/private', env.private)}

${read_description('$env+static+public.md')}
${create_static_types('$env/static/public', env.public)}

${read_description('$env+dynamic+private.md')}
${create_dynamic_types('$env/dynamic/private', env.private)}

${read_description('$env+dynamic+public.md')}
${create_dynamic_types('$env/dynamic/public', env.public)}
`;

/**
* Writes ambient declarations including types reference to @sveltejs/kit,
Expand All @@ -16,12 +49,5 @@ const types_reference = '/// <reference types="@sveltejs/kit" />\n\n';
export function write_ambient(config, mode) {
const env = get_env(config.env, mode);

write_if_changed(
path.join(config.outDir, 'ambient.d.ts'),
GENERATED_COMMENT +
types_reference +
create_types('$env/static/public', env.public) +
'\n\n' +
create_types('$env/static/private', env.private)
);
write_if_changed(path.join(config.outDir, 'ambient.d.ts'), template(env));
}
1 change: 0 additions & 1 deletion packages/kit/src/runtime/env-private.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/** @type {App.PrivateEnv} */
export let env = {};

/** @type {(environment: Record<string, string>) => void} */
Expand Down
1 change: 0 additions & 1 deletion packages/kit/src/runtime/env-public.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/** @type {App.PublicEnv} */
export let env = {};

/** @type {(environment: Record<string, string>) => void} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@
declare namespace App {
// interface Locals {}
// interface Platform {}
// interface PrivateEnv {}
// interface PublicEnv {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@
declare namespace App {
// interface Locals {}
// interface Platform {}
// interface PrivateEnv {}
// interface PublicEnv {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@
declare namespace App {
// interface Locals {}
// interface Platform {}
// interface PrivateEnv {}
// interface PublicEnv {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@
declare namespace App {
// interface Locals {}
// interface Platform {}
// interface PrivateEnv {}
// interface PublicEnv {}
}
49 changes: 1 addition & 48 deletions packages/kit/types/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,10 @@
* interface PageData {}
*
* interface Platform {}
*
* interface PrivateEnv {}
*
* interface PublicEnv {}
* }
* ```
*
* By populating these interfaces, you will gain type safety when using `env`, `event.locals` and `event.platform`.
* By populating these interfaces, you will gain type safety when using `event.locals`, `event.platform`, and `data` from `load` functions.
*
* Note that since it's an ambient declaration file, you have to be careful when using `import` statements. Once you add an `import`
* at the top level, the declaration file is no longer considered ambient and you lose access to these typings in other files.
Expand Down Expand Up @@ -60,16 +56,6 @@ declare namespace App {
* If your adapter provides [platform-specific context](https://kit.svelte.dev/docs/adapters#supported-environments-platform-specific-context) via `event.platform`, you can specify it here.
*/
export interface Platform {}

/**
* The interface that defines the dynamic environment variables exported from `$env/dynamic/private`.
*/
export interface PrivateEnv extends Record<string, string> {}

/**
* The interface that defines the dynamic environment variables exported from `$env/dynamic/public`.
*/
export interface PublicEnv extends Record<string, string> {}
}

/**
Expand All @@ -94,39 +80,6 @@ declare module '$app/environment' {
export const prerendering: boolean;
}

/**
* This module provides access to runtime environment variables, as defined by the platform you're running on. For example
* if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) (or running
* [`vite preview`](https://kit.svelte.dev/docs/cli)), this is equivalent to `process.env`. This module only includes
* variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#kit-env-publicprefix).
*
* This module cannot be imported into client-side code.
*
* ```ts
* import { env } from '$env/dynamic/private';
* console.log(env.DEPLOYMENT_SPECIFIC_VARIABLE);
* ```
*/
declare module '$env/dynamic/private' {
export let env: App.PrivateEnv;
}

/**
* Similar to [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), but only includes
* variables that begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#kit-env-publicprefix)
* (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code
*
* Note that public dynamic environment variables must all be sent from the server to the client, causing larger network requests — when possible, use `$env/static/public` instead.
*
* ```ts
* import { env } from '$env/dynamic/public';
* console.log(env.PUBLIC_DEPLOYMENT_SPECIFIC_VARIABLE);
* ```
*/
declare module '$env/dynamic/public' {
export let env: App.PublicEnv;
}

/**
* ```ts
* import {
Expand Down