Skip to content

Commit 9455ecf

Browse files
committed
Adding an option to surpress or modify the non-existent root directory warning (#524)
1 parent e76497f commit 9455ecf

File tree

4 files changed

+166
-123
lines changed

4 files changed

+166
-123
lines changed

README.md

Lines changed: 131 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -7,108 +7,108 @@
77
Plugin for serving static files as fast as possible.
88

99
## Install
10+
1011
```
1112
npm i @fastify/static
1213
```
1314

1415
### Compatibility
1516

1617
| Plugin version | Fastify version |
17-
| ---------------|-----------------|
18+
| -------------- | --------------- |
1819
| `>=8.x` | `^5.x` |
1920
| `^7.x` | `^4.x` |
2021
| `>=5.x <7.x` | `^3.x` |
2122
| `>=2.x <5.x` | `^2.x` |
2223
| `^1.x` | `^1.x` |
2324

24-
2525
Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin
2626
in the table above.
2727
See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.
2828

2929
## Usage
3030

3131
```js
32-
const fastify = require('fastify')({logger: true})
33-
const path = require('node:path')
32+
const fastify = require("fastify")({ logger: true });
33+
const path = require("node:path");
3434

35-
fastify.register(require('@fastify/static'), {
36-
root: path.join(__dirname, 'public'),
37-
prefix: '/public/', // optional: default '/'
38-
constraints: { host: 'example.com' } // optional: default {}
39-
})
35+
fastify.register(require("@fastify/static"), {
36+
root: path.join(__dirname, "public"),
37+
prefix: "/public/", // optional: default '/'
38+
constraints: { host: "example.com" }, // optional: default {}
39+
});
4040

41-
fastify.get('/another/path', function (req, reply) {
42-
reply.sendFile('myHtml.html') // serving path.join(__dirname, 'public', 'myHtml.html') directly
43-
})
41+
fastify.get("/another/path", function (req, reply) {
42+
reply.sendFile("myHtml.html"); // serving path.join(__dirname, 'public', 'myHtml.html') directly
43+
});
4444

45-
fastify.get('/another/patch-async', async function (req, reply) {
46-
return reply.sendFile('myHtml.html')
47-
})
45+
fastify.get("/another/patch-async", async function (req, reply) {
46+
return reply.sendFile("myHtml.html");
47+
});
4848

49-
fastify.get('/path/with/different/root', function (req, reply) {
50-
reply.sendFile('myHtml.html', path.join(__dirname, 'build')) // serving a file from a different root location
51-
})
49+
fastify.get("/path/with/different/root", function (req, reply) {
50+
reply.sendFile("myHtml.html", path.join(__dirname, "build")); // serving a file from a different root location
51+
});
5252

53-
fastify.get('/another/path', function (req, reply) {
54-
reply.sendFile('myHtml.html', { cacheControl: false }) // overriding the options disabling cache-control headers
55-
})
53+
fastify.get("/another/path", function (req, reply) {
54+
reply.sendFile("myHtml.html", { cacheControl: false }); // overriding the options disabling cache-control headers
55+
});
5656

5757
// Run the server!
5858
fastify.listen({ port: 3000 }, (err, address) => {
59-
if (err) throw err
59+
if (err) throw err;
6060
// Server is now listening on ${address}
61-
})
61+
});
6262
```
6363

6464
### Multiple prefixed roots
6565

6666
```js
67-
const fastify = require('fastify')()
68-
const fastifyStatic = require('@fastify/static')
69-
const path = require('node:path')
67+
const fastify = require("fastify")();
68+
const fastifyStatic = require("@fastify/static");
69+
const path = require("node:path");
7070
// first plugin
7171
fastify.register(fastifyStatic, {
72-
root: path.join(__dirname, 'public')
73-
})
72+
root: path.join(__dirname, "public"),
73+
});
7474

7575
// second plugin
7676
fastify.register(fastifyStatic, {
77-
root: path.join(__dirname, 'node_modules'),
78-
prefix: '/node_modules/',
79-
decorateReply: false // the reply decorator has been added by the first plugin registration
80-
})
81-
77+
root: path.join(__dirname, "node_modules"),
78+
prefix: "/node_modules/",
79+
decorateReply: false, // the reply decorator has been added by the first plugin registration
80+
});
8281
```
8382

8483
### Sending a file with `content-disposition` header
8584

8685
```js
87-
const fastify = require('fastify')()
88-
const path = require('node:path')
86+
const fastify = require("fastify")();
87+
const path = require("node:path");
8988

90-
fastify.register(require('@fastify/static'), {
91-
root: path.join(__dirname, 'public'),
92-
prefix: '/public/', // optional: default '/'
93-
})
89+
fastify.register(require("@fastify/static"), {
90+
root: path.join(__dirname, "public"),
91+
prefix: "/public/", // optional: default '/'
92+
});
9493

95-
fastify.get('/another/path', function (req, reply) {
96-
reply.download('myHtml.html', 'custom-filename.html') // sending path.join(__dirname, 'public', 'myHtml.html') directly with custom filename
97-
})
94+
fastify.get("/another/path", function (req, reply) {
95+
reply.download("myHtml.html", "custom-filename.html"); // sending path.join(__dirname, 'public', 'myHtml.html') directly with custom filename
96+
});
9897

99-
fastify.get('another/patch-async', async function (req, reply) {
98+
fastify.get("another/patch-async", async function (req, reply) {
10099
// an async handler must always return the reply object
101-
return reply.download('myHtml.html', 'custom-filename.html')
102-
})
103-
104-
fastify.get('/path/without/cache/control', function (req, reply) {
105-
reply.download('myHtml.html', { cacheControl: false }) // serving a file disabling cache-control headers
106-
})
107-
108-
fastify.get('/path/without/cache/control', function (req, reply) {
109-
reply.download('myHtml.html', 'custom-filename.html', { cacheControl: false })
110-
})
111-
100+
return reply.download("myHtml.html", "custom-filename.html");
101+
});
102+
103+
fastify.get("/path/without/cache/control", function (req, reply) {
104+
reply.download("myHtml.html", { cacheControl: false }); // serving a file disabling cache-control headers
105+
});
106+
107+
fastify.get("/path/without/cache/control", function (req, reply) {
108+
reply.download("myHtml.html", "custom-filename.html", {
109+
cacheControl: false,
110+
});
111+
});
112112
```
113113

114114
### Managing cache-control headers
@@ -117,23 +117,23 @@ Production sites should use a reverse-proxy to manage caching headers.
117117
However, here is an example of using fastify-static to host a Single Page Application (for example a [vite.js](https://vite.dev/) build) with sane caching.
118118

119119
```js
120-
fastify.register(require('@fastify/static'), {
121-
root: path.join(import.meta.dirname, 'dist'), // import.meta.dirname node.js >= v20.11.0
120+
fastify.register(require("@fastify/static"), {
121+
root: path.join(import.meta.dirname, "dist"), // import.meta.dirname node.js >= v20.11.0
122122
// By default all assets are immutable and can be cached for a long period due to cache bursting techniques
123-
maxAge: '30d',
123+
maxAge: "30d",
124124
immutable: true,
125-
})
125+
});
126126

127127
// Explicitly reduce caching of assets that don't use cache bursting techniques
128-
fastify.get('/', function (req, reply) {
128+
fastify.get("/", function (req, reply) {
129129
// index.html should never be cached
130-
reply.sendFile('index.html', {maxAge: 0, immutable: false})
131-
})
130+
reply.sendFile("index.html", { maxAge: 0, immutable: false });
131+
});
132132

133-
fastify.get('/favicon.ico', function (req, reply) {
133+
fastify.get("/favicon.ico", function (req, reply) {
134134
// favicon can be cached for a short period
135-
reply.sendFile('favicon.ico', {maxAge: '1d', immutable: false})
136-
})
135+
reply.sendFile("favicon.ico", { maxAge: "1d", immutable: false });
136+
});
137137
```
138138
139139
### Options
@@ -148,6 +148,12 @@ An array of directories can be provided to serve multiple static directories
148148
under a single prefix. Files are served in a "first found, first served" manner,
149149
so list directories in order of priority. Duplicate paths will raise an error.
150150
151+
#### `getPathNotFoundWarning`
152+
153+
A custom function that returns a warning message to log when a specified root directory is not found.
154+
It receives a single argument: the path of the missing root directory.
155+
The function should return a string describing the missing path.
156+
151157
#### `prefix`
152158
153159
Default: `'/'`
@@ -275,12 +281,12 @@ If `dotfiles` is `deny` or `ignore`, dotfiles are excluded.
275281
Example:
276282
277283
```js
278-
fastify.register(require('@fastify/static'), {
279-
root: path.join(__dirname, 'public'),
280-
prefix: '/public/',
284+
fastify.register(require("@fastify/static"), {
285+
root: path.join(__dirname, "public"),
286+
prefix: "/public/",
281287
index: false,
282-
list: true
283-
})
288+
list: true,
289+
});
284290
```
285291
286292
Request
@@ -314,25 +320,32 @@ Returns the response as JSON, regardless of `list.format`.
314320
Example:
315321
316322
```js
317-
fastify.register(require('@fastify/static'), {
318-
root: path.join(__dirname, 'public'),
319-
prefix: '/public/',
323+
fastify.register(require("@fastify/static"), {
324+
root: path.join(__dirname, "public"),
325+
prefix: "/public/",
320326
list: {
321-
format: 'html',
327+
format: "html",
322328
render: (dirs, files) => {
323329
return `
324330
<html><body>
325331
<ul>
326-
${dirs.map(dir => `<li><a href="${dir.href}">${dir.name}</a></li>`).join('\n ')}
332+
${dirs
333+
.map((dir) => `<li><a href="${dir.href}">${dir.name}</a></li>`)
334+
.join("\n ")}
327335
</ul>
328336
<ul>
329-
${files.map(file => `<li><a href="${file.href}" target="_blank">${file.name}</a></li>`).join('\n ')}
337+
${files
338+
.map(
339+
(file) =>
340+
`<li><a href="${file.href}" target="_blank">${file.name}</a></li>`
341+
)
342+
.join("\n ")}
330343
</ul>
331344
</body></html>
332-
`
333-
},
334-
}
335-
})
345+
`;
346+
},
347+
},
348+
});
336349
```
337350
338351
Request
@@ -344,18 +357,20 @@ GET /public
344357
Response
345358
346359
```html
347-
<html><body>
348-
<ul>
349-
<li><a href="/dir1">dir1</a></li>
350-
<li><a href="/dir1">dir2</a></li>
351-
</ul>
352-
<ul>
353-
<li><a href="/foo.html" target="_blank">foo.html</a></li>
354-
<li><a href="/foobar.html" target="_blank">foobar.html</a></li>
355-
<li><a href="/index.css" target="_blank">index.css</a></li>
356-
<li><a href="/index.html" target="_blank">index.html</a></li>
357-
</ul>
358-
</body></html>
360+
<html>
361+
<body>
362+
<ul>
363+
<li><a href="/dir1">dir1</a></li>
364+
<li><a href="/dir1">dir2</a></li>
365+
</ul>
366+
<ul>
367+
<li><a href="/foo.html" target="_blank">foo.html</a></li>
368+
<li><a href="/foobar.html" target="_blank">foobar.html</a></li>
369+
<li><a href="/index.css" target="_blank">index.css</a></li>
370+
<li><a href="/index.html" target="_blank">index.html</a></li>
371+
</ul>
372+
</body>
373+
</html>
359374
```
360375
361376
#### `list.names`
@@ -369,15 +384,15 @@ Directory list can respond to different routes declared in `list.names`.
369384
Example:
370385
371386
```js
372-
fastify.register(require('@fastify/static'), {
373-
root: path.join(__dirname, '/static'),
374-
prefix: '/public',
387+
fastify.register(require("@fastify/static"), {
388+
root: path.join(__dirname, "/static"),
389+
prefix: "/public",
375390
prefixAvoidTrailingSlash: true,
376391
list: {
377-
format: 'json',
378-
names: ['index', 'index.json', '/']
379-
}
380-
})
392+
format: "json",
393+
names: ["index", "index.json", "/"],
394+
},
395+
});
381396
```
382397
383398
Dir list respond with the same content to:
@@ -418,20 +433,16 @@ Options: `names`, `extended`
418433
Determines the output format when `json` is selected.
419434
420435
`names`:
436+
421437
```json
422438
{
423-
"dirs": [
424-
"dir1",
425-
"dir2"
426-
],
427-
"files": [
428-
"file1.txt",
429-
"file2.txt"
430-
]
439+
"dirs": ["dir1", "dir2"],
440+
"files": ["file1.txt", "file2.txt"]
431441
}
432442
```
433443
434444
`extended`:
445+
435446
```json
436447
{
437448
"dirs": [
@@ -496,18 +507,21 @@ handler is called. Set a custom 404 handler with [`fastify.setNotFoundHandler()`
496507
When registering `@fastify/static` within an encapsulated context, the `wildcard` option may need to be set to `false` to support index resolution and nested not-found-handler:
497508
498509
```js
499-
const app = require('fastify')();
510+
const app = require("fastify")();
500511

501-
app.register((childContext, _, done) => {
502-
childContext.register(require('@fastify/static'), {
503-
root: path.join(__dirname, 'docs'), // docs is a folder that contains `index.html` and `404.html`
504-
wildcard: false
512+
app.register(
513+
(childContext, _, done) => {
514+
childContext.register(require("@fastify/static"), {
515+
root: path.join(__dirname, "docs"), // docs is a folder that contains `index.html` and `404.html`
516+
wildcard: false,
505517
});
506518
childContext.setNotFoundHandler((_, reply) => {
507-
return reply.code(404).type('text/html').sendFile('404.html');
519+
return reply.code(404).type("text/html").sendFile("404.html");
508520
});
509521
done();
510-
}, { prefix: 'docs' });
522+
},
523+
{ prefix: "docs" }
524+
);
511525
```
512526
513527
This code will send the `index.html` for the paths `docs`, `docs/`, and `docs/index.html`. For all other `docs/<undefined-routes>` it will reply with `404.html`.
@@ -522,10 +536,10 @@ Set a custom handler with [`fastify.setErrorHandler()`](https://fastify.dev/docs
522536
Access the file path inside the `onSend` hook using `payload.path`.
523537
524538
```js
525-
fastify.addHook('onSend', function (req, reply, payload, next) {
526-
console.log(payload.path)
527-
next()
528-
})
539+
fastify.addHook("onSend", function (req, reply, payload, next) {
540+
console.log(payload.path);
541+
next();
542+
});
529543
```
530544
531545
## License

0 commit comments

Comments
 (0)