Skip to content

Commit 5ad3fc7

Browse files
authored
Add docs for src directory and custom server builds (#240)
1 parent 38938bd commit 5ad3fc7

File tree

3 files changed

+133
-31
lines changed

3 files changed

+133
-31
lines changed

.vscode/settings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,8 @@
66
"javascript.format.semicolons": "remove",
77
"typescript.format.semicolons": "remove",
88
"javascript.preferences.quoteStyle": "auto",
9-
"typescript.preferences.quoteStyle": "auto"
9+
"typescript.preferences.quoteStyle": "auto",
10+
"[markdown]": {
11+
"editor.formatOnSave": false,
12+
}
1013
}

docs/guide/build-and-deploy.md

Lines changed: 110 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
# Build and Deploy
55

6-
You'll quickly notice running your Fastify server without the `--dev` flag can get you the following error message:
6+
Without building, you will quickly notice running your Fastify server without the `--dev` flag can get you the following error message:
77

88
```
99
% node server.js
@@ -14,46 +14,131 @@ You'll quickly notice running your Fastify server without the `--dev` flag can g
1414
Error: No distribution bundle found.
1515
```
1616

17-
This means you're trying to run **`@fastify/vite`** in production mode, in which case a **distribution bundle** is assumed to exist. To build your client application code in preparation for **`@fastify/vite`**, you must run two `vite build` commands, one for the actual client bundle, that gets delivered to the browser, and another for the server-side version of it (what **`@fastify/vite`** sees as the *_client module_*, or *_server entry point_*).
17+
This means you're trying to run **`@fastify/vite`** in production mode, in which case a **distribution bundle** is assumed to exist. You need to first build your application code in preparation for **`@fastify/vite`**.
1818

19-
Assuming you're using the default `clientModule` resolution (`/index.js`), these are the `scripts` needed in `package.json`:
19+
## Building multiple bundles
2020

21-
```json
21+
Depending on your application, there can be up to _three_ distribution bundles:
22+
23+
1. The bundle that gets delivered to the **browser**. Required no matter what.
24+
2. The bundle used for **server side rendering** (SSR). Only required if you intend to use server side rendering.
25+
3. The "bundle" that contains the code that instantiates the **Fastify server itself**. Some servers need this, such as ones that are written in TypeScript and do not want to use type-stripping. This build process is entirely up to you.
26+
27+
Building the **browser bundle** and the **ssr bundle** can be accomplished by running a single `vite build` command. Their entry points are as follows:
28+
29+
```text{2,3}
30+
├── client/
31+
│ ├── index.js <-- ssr entry point (default)
32+
│ ├── mount.js <-- browser entry point
33+
│ └── index.html
34+
```
35+
36+
You can use the included Vite plugin to customize the SSR build:
37+
38+
```js{7}
39+
import { resolve } from 'node:path'
40+
import viteFastify from '@fastify/vite/plugin'
41+
42+
export default {
43+
root: resolve(import.meta.dirname, 'client'),
44+
plugins: [
45+
viteFastify({/* see below for available options */})
46+
],
47+
}
48+
```
49+
50+
The `viteFastify` plugin can be given the following options:
51+
52+
* `spa` - Set this to `true` to disable the SSR build entirely. Default: `false`.
53+
* `clientModule` - The location of the SSR entry point, relative to the index.html file. Defaults to `index.js`. You can also use an absolute path to be extra safe.
54+
55+
Assuming you do not need to build your Fastify server itself, the only build script you need in your `package.json` file is below:
56+
57+
```json{3}
58+
{
59+
"scripts": {
60+
"build": "vite build"
61+
}
62+
}
63+
```
64+
65+
If you **do** need to run a custom build process on the code that instantiates the Fastify server itself, your `package.json` file likely contains the scripts below:
66+
67+
```json{5}
2268
{
2369
"scripts": {
2470
"build": "npm run build:client && npm run build:server",
25-
"build:client": "vite build --outDir dist/client --ssrManifest",
26-
"build:server": "vite build --outDir dist/server --ssr /index.js",
71+
"build:client": "vite build",
72+
"build:server": "tsc",
2773
}
2874
}
2975
```
3076

31-
If you're using a **different** [`clientModule`](/config/#clientmodule) settings, you *will* need to change the `build:server` command accordingly, i.e., that's not taken care of by `**@fastify/vite**`. After running `npm run build` on [`react-vanilla`](https://github.com/fastify/fastify-vite/tree/dev/examples/react-vanilla), for example, you should see a new `client/dist` folder.
77+
In the example above, `tsc` is used as the custom build process for the server code, but this can be replaced with whatever you need to use. If you do this, you probably want to customize the location of your dist directory (see below).
78+
79+
### The dist directory
80+
81+
The `vite build` script above creates a `dist` directory with the following contents:
82+
83+
```text
84+
├── dist/
85+
│ ├── client/ (contains client bundle)
86+
│ └── server/ (contains ssr bundle, if enabled)
87+
```
88+
89+
Depending on whether you have decided to use a `src` directory, you may also want to customize where your `dist` directory is located. This especially true if you have a custom build process for your server code. Common locations for the `dist` directory can be:
90+
91+
1. Within the client folder, aka the location specified as the `root` of your `vite.config.js` file. This is the default and is recommended if you do not run a custom build for your server code.
92+
2. At the root of the application. If you run a custom build for your server code, it generally builds into a dist folder that is a sibling to your `src` directory. In this case, you likely want to put your client and SSR bundles into this folder as well.
93+
94+
If you choose to go with (2), your `dist` folder should also contain the built server files at its root level:
3295

3396
```diff
34-
├── client
35-
+ │ ├── dist
36-
│ ├── base.jsx
37-
│ ├── index.html
38-
│ ├── index.js
39-
│ └── mount.js
40-
├── package.json
41-
├── server.js
42-
└── vite.config.js
97+
├── dist/
98+
│ ├── client/ (contains client bundle)
99+
│ ├── server/ (contains ssr bundle, if enabled)
100+
+ | └── server.js (the built server files)
43101
```
44102

45-
That's where the production bundle of your Vite application is located, so this folder needs to exist before you can run a Fastify server with **`@fastify/vite`** in production mode. Once you have `client/dist` available, `node server.js` without the `--dev` flag should be able to run.
103+
To achieve this, you need to do two things:
46104

47-
> Make sure to have `NODE_ENV` set to `production` as well in case your framework requires it (like React) for SSR in production as well. Accidentally running React SSR in development mode is quite common and can lead to serious performance degradation.
105+
1. Instruct the included `viteFastify` plugin to output its files into your custom `dist` directory location using vite's [`build.outDir`](https://vite.dev/config/build-options.html#build-outdir) option.
106+
2. Instruct your custom build process to output the built server files into the same `dist` directory.
48107

49-
Also note that in **production mode**, **`@fastify/vite`** will serve static assets from your Vite application via [`@fastify/static`](https://github.com/fastify/fastify-static) automatically, but you should consider using a CDN for those files if you can, or just serve through Nginx instead of directly through Node.js.
108+
If you do not do the above two steps, you could end up with two separate `dist` folders that you will need to handle on your own. Below is an example of this setup using `tsc` as the custom server build process:
50109

51-
If you don't need SSR, it can also just serve as a convenience to serve your static Vite bundle through Fastify via [@fastify/static][fastify-static], automatically inferring your bundle's output directory from your Vite configuration file, and still allowing you to leverage Vite's development server for hot reload.
110+
::: code-group
111+
```js{7} [vite.config.js]
112+
import { resolve } from 'node:path'
113+
import viteFastify from '@fastify/vite/plugin'
114+
115+
export default {
116+
root: resolve(import.meta.dirname, 'client'),
117+
build: {
118+
outDir: resolve(import.meta.dirname, 'dist'),
119+
},
120+
plugins: [
121+
viteFastify()
122+
],
123+
}
124+
```
125+
```json{3} [tsconfig.json]
126+
{
127+
"compilerOptions": {
128+
"outDir": "dist"
129+
}
130+
}
131+
```
132+
:::
52133

53-
## Steps
134+
## Running in production mode
54135

55-
To recap, the steps to build and deploy are:
136+
Once your build processes are complete and your `dist` directory is populated, you should be able to run a Fastify server with **`@fastify/vite`** in production mode. Run `node server.js` without the `--dev` flag to see. Don't forget to include your `dist` directory as part of your deployment.
137+
138+
> Make sure to have `NODE_ENV` set to `production` as well in case your framework requires it (like React) for SSR in production as well. Accidentally running React SSR in development mode is quite common and can lead to serious performance degradation.
139+
140+
Also note that in **production mode**, **`@fastify/vite`** will serve static assets from your Vite application via [`@fastify/static`](https://github.com/fastify/fastify-static) automatically, but you should consider using a CDN for those files if you can, or just serve through Nginx instead of directly through Node.js.
141+
142+
If you don't need SSR, it can also just serve as a convenience to serve your static Vite bundle through Fastify via [@fastify/static][fastify-static], automatically inferring your bundle's output directory from your Vite configuration file, and still allowing you to leverage Vite's development server for hot reload.
56143

57-
- Running vite build with client configuration.
58-
- Running vite build with server configuration.
59-
- Including `client/dist` as part of your deployment.
144+
> Tip: If you are using Docker, your final `CMD` should be `node server.js` and not `npm run anything`. This will allow SIGTERM signals to be sent directly to the `node` process and not an intermediary `npm` process which usually fails to forward the messages properly to `node`.

docs/guide/getting-started.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,25 +152,39 @@ export function createApp () {
152152
153153
## Directory structure
154154
155-
This is what the directory structure for the example above looks like:
155+
**`@fastify/vite`** recommends one of the following directory structures for your application:
156156
157-
```text{1,5,6}
157+
::: code-group
158+
```text{2,5,6} [without src directory]
159+
// For very simple servers
158160
├── server.js
159161
├── client/
160-
│ ├── base.jsx
161162
│ ├── mount.js
162163
│ └── index.html
163164
├── vite.config.js
164165
└── package.json
165166
```
167+
```text{3,6,7} [with src directory]
168+
// For servers that have many files or require a build step
169+
├── src/
170+
| ├── server.js
171+
| └── client/
172+
│ ├── mount.js
173+
│ └── index.html
174+
├── vite.config.js
175+
└── package.json
176+
```
177+
:::
178+
179+
The choice to use a `src` directory or not is up to you. The primary benefit of using a `src` directory is if your server code requires any kind of build step where you want to separate your `src` files from `dist` files. For example, if your server is written in TypeScript you most likely want your `src` and `dist` files to be separate. It is also not uncommon for server code to be built using Webpack or Rollup. Even if your server does not require a build step, you may want to use a `src` directory anyway for better organization if your server code is divided into many files. If you **do** choose to use a `src` directory, you probably also want to customize the location of your `dist` directory; see: [the dist directory](/guide/build-and-deploy#the-dist-directory).
166180
167181
In all examples in this documentation, the client application code is kept in a `client/` directory, to be explicitly separated from the server code and configuration files. In the `vite.config.js` previously shown, the project **root** is set as `client`. This is the recommended approach.
168182
169183
::: warning
170-
It's important to realize that in `server.js`, the `root` configuration option determines where your `vite.config.js` is located. But in `vite.config.js` itself, the `root` configuration option determines your **project root** in Vite's context.
184+
It's important to realize that in `server.js`, the `root` configuration option determines where your `vite.config.js` is located. But in `vite.config.js` itself, the `root` configuration option determines where your `index.html` is located. This is your **project root** in Vite's context.
171185
:::
172186
173-
Regardless of whether you want to simply deliver a SPA bundle to the browser or perform SSR, projects using `@fastify/vite` will always need a minimum of **three files**: the Fastify **server**, an [index.html file](https://vitejs.dev/guide/#index-html-and-project-root) and a [Vite configuration file](https://vitejs.dev/config/).
187+
Regardless of whether you want to simply deliver a SPA bundle to the browser or perform SSR, projects using **`@fastify/vite`** will always need a minimum of **three files**: the Fastify **server**, an [index.html file](https://vitejs.dev/guide/#index-html-and-project-root) and a [Vite configuration file](https://vitejs.dev/config/).
174188
175189
## Architectural primitives
176190

0 commit comments

Comments
 (0)