Skip to content

Commit 55493cb

Browse files
docs: Document $lib/server and *.server.* server-only modules (#6646)
* feat: Added server-only modules docs * fix: Script blocks and naming * feat: Other miscellaneous docs * fix: Header level * flesh out docs a bit more, amend stuff around dynamic imports * reference public-facing code rather than client-side code * small tweak * merge Co-authored-by: Rich Harris <hello@rich-harris.dev>
1 parent a9bcd35 commit 55493cb

File tree

23 files changed

+91
-25
lines changed

23 files changed

+91
-25
lines changed

.changeset/gold-walls-rush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
Change illegal import message to reference public-facing code rather than client-side code

documentation/docs/01-project-structure.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ A typical SvelteKit project looks like this:
88
my-project/
99
├ src/
1010
│ ├ lib/
11+
│ │ ├ server/
12+
│ │ │ └ [your server-only lib files]
1113
│ │ └ [your lib files]
1214
│ ├ params/
1315
│ │ └ [your param matchers]
@@ -35,6 +37,7 @@ You'll also find common files like `.gitignore` and `.npmrc` (and `.prettierrc`
3537
The `src` directory contains the meat of your project.
3638

3739
- `lib` contains your library code, which can be imported via the [`$lib`](/docs/modules#$lib) alias, or packaged up for distribution using [`svelte-package`](/docs/packaging)
40+
- `server` contains your server-only library code. It can be imported by using the [`$lib/server`](/docs/server-only-modules) alias. SvelteKit will prevent you from importing these in client code.
3841
- `params` contains any [param matchers](/docs/advanced-routing#matching) your app needs
3942
- `routes` contains the [routes](/docs/routing) of your application
4043
- `app.html` is your page template — an HTML document containing the following placeholders:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
title: Server-only modules
3+
---
4+
5+
Like a good friend, SvelteKit keeps your secrets. When writing your backend and frontend in the same repository, it can be easy to accidentally import sensitive data into your front-end code (environment variables containing API keys, for example). SvelteKit provides a way to prevent this entirely: server-only modules.
6+
7+
### Private environment variables
8+
9+
The `$env/static/private` and `$env/dynamic/private` modules, which are covered in the [modules](/docs/modules) section, can only be imported into modules that only run on the server, such as [`hooks.server.js`](/docs/hooks#server-hooks) or [`+page.server.js`](/docs/routing#page-page-server-js).
10+
11+
### Your modules
12+
13+
You can make your own modules server-only in two ways:
14+
15+
- adding `.server` to the filename, e.g. `secrets.server.js`
16+
- placing them in `$lib/server`, e.g. `$lib/server/secrets.js`
17+
18+
### How it works
19+
20+
Any time you have public-facing code that imports server-only code (whether directly or indirectly)...
21+
22+
```js
23+
// @errors: 7005
24+
/// file: $lib/server/secrets.js
25+
export const atlantisCoordinates = [/* redacted */];
26+
```
27+
28+
```js
29+
// @errors: 2307 7006
30+
/// file: src/routes/utils.js
31+
export { atlantisCoordinates } from '$lib/server/secrets.js';
32+
33+
export const add = (a, b) => a + b;
34+
```
35+
36+
```html
37+
/// file: src/routes/+page.svelte
38+
<script>
39+
import { add } from './utils.js';
40+
</script>
41+
```
42+
43+
...SvelteKit will error:
44+
45+
```
46+
Cannot import $lib/server/secrets.js into public-facing code:
47+
- src/routes/+page.svelte
48+
- src/routes/utils.js
49+
- $lib/server/secrets.js
50+
```
51+
52+
Even though the public-facing code — `src/routes/+page.svelte` — only uses the `add` export and not the secret `atlantisCoordinates` export, the secret code could end up in JavaScript that the browser downloads, and so the import chain is considered unsafe.
53+
54+
This feature also works with dynamic imports, even interpolated ones like ``await import(`./${foo}.js`)``, with one small caveat: during development, if there are two or more dynamic imports between the public-facing code and the server-only module, the illegal import will not be detected the first time the code is loaded.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)