koa-classic-server 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -6
- package/docs/CHANGELOG.md +17 -0
- package/docs/DOCUMENTATION.md +9 -5
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -64,8 +64,8 @@ npm install koa-classic-server
|
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
**Requirements:**
|
|
67
|
-
- Node.js >=
|
|
68
|
-
- Koa >= 2.0.0
|
|
67
|
+
- Node.js >= 18.0.0
|
|
68
|
+
- Koa >= 2.0.0 (Koa 3 requires >= 3.1.2)
|
|
69
69
|
|
|
70
70
|
---
|
|
71
71
|
|
|
@@ -264,7 +264,133 @@ app.use(koaClassicServer(__dirname + '/public', {
|
|
|
264
264
|
|
|
265
265
|
> **Note**: This conflict resolution behavior differs from Apache/Nginx, where directories typically take priority over files with the same base name.
|
|
266
266
|
|
|
267
|
-
### 7.
|
|
267
|
+
### 7. URL Rewriting Support (useOriginalUrl)
|
|
268
|
+
|
|
269
|
+
When using URL rewriting middleware (i18n, routing), set `useOriginalUrl: false` so koa-classic-server resolves files from the rewritten URL instead of the original one:
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
const Koa = require('koa');
|
|
273
|
+
const koaClassicServer = require('koa-classic-server');
|
|
274
|
+
|
|
275
|
+
const app = new Koa();
|
|
276
|
+
|
|
277
|
+
// i18n middleware: strips language prefix and rewrites ctx.url
|
|
278
|
+
app.use(async (ctx, next) => {
|
|
279
|
+
const langMatch = ctx.path.match(/^\/(it|en|fr|de|es)\//);
|
|
280
|
+
if (langMatch) {
|
|
281
|
+
ctx.state.lang = langMatch[1]; // Save language for templates
|
|
282
|
+
ctx.url = ctx.path.replace(/^\/(it|en|fr|de|es)/, '') + ctx.search;
|
|
283
|
+
}
|
|
284
|
+
await next();
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Serve files using the rewritten URL
|
|
288
|
+
app.use(koaClassicServer(__dirname + '/public', {
|
|
289
|
+
useOriginalUrl: false // Use ctx.url (rewritten) instead of ctx.originalUrl
|
|
290
|
+
}));
|
|
291
|
+
|
|
292
|
+
app.listen(3000);
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**How it works:**
|
|
296
|
+
|
|
297
|
+
| Request | `ctx.originalUrl` | `ctx.url` (rewritten) | File resolved |
|
|
298
|
+
|---------|-------------------|----------------------|---------------|
|
|
299
|
+
| `/it/page.html` | `/it/page.html` | `/page.html` | `public/page.html` |
|
|
300
|
+
| `/en/page.html` | `/en/page.html` | `/page.html` | `public/page.html` |
|
|
301
|
+
| `/page.html` | `/page.html` | `/page.html` | `public/page.html` |
|
|
302
|
+
|
|
303
|
+
- With `useOriginalUrl: true` (default): the server would look for `public/it/page.html` (which doesn't exist)
|
|
304
|
+
- With `useOriginalUrl: false`: the server looks for `public/page.html` (correct)
|
|
305
|
+
|
|
306
|
+
### 8. Advanced hideExtension Scenarios
|
|
307
|
+
|
|
308
|
+
#### Recommended file structure
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
views/
|
|
312
|
+
├── index.ejs ← / (home page)
|
|
313
|
+
├── about.ejs ← /about
|
|
314
|
+
├── contact.ejs ← /contact
|
|
315
|
+
├── blog/
|
|
316
|
+
│ ├── index.ejs ← /blog/
|
|
317
|
+
│ ├── first-post.ejs ← /blog/first-post
|
|
318
|
+
│ └── second-post.ejs ← /blog/second-post
|
|
319
|
+
├── docs/
|
|
320
|
+
│ ├── index.ejs ← /docs/
|
|
321
|
+
│ ├── getting-started.ejs ← /docs/getting-started
|
|
322
|
+
│ └── api-reference.ejs ← /docs/api-reference
|
|
323
|
+
└── assets/
|
|
324
|
+
├── style.css ← /assets/style.css (served normally)
|
|
325
|
+
└── script.js ← /assets/script.js (served normally)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### hideExtension with i18n middleware
|
|
329
|
+
|
|
330
|
+
Combine `hideExtension` with `useOriginalUrl: false` for multilingual sites with clean URLs:
|
|
331
|
+
|
|
332
|
+
```javascript
|
|
333
|
+
const Koa = require('koa');
|
|
334
|
+
const koaClassicServer = require('koa-classic-server');
|
|
335
|
+
const ejs = require('ejs');
|
|
336
|
+
|
|
337
|
+
const app = new Koa();
|
|
338
|
+
|
|
339
|
+
// i18n middleware: /it/about → ctx.url = /about, ctx.state.lang = 'it'
|
|
340
|
+
app.use(async (ctx, next) => {
|
|
341
|
+
const langMatch = ctx.path.match(/^\/(it|en|fr)\//);
|
|
342
|
+
if (langMatch) {
|
|
343
|
+
ctx.state.lang = langMatch[1];
|
|
344
|
+
ctx.url = ctx.path.replace(/^\/(it|en|fr)/, '') + ctx.search;
|
|
345
|
+
} else {
|
|
346
|
+
ctx.state.lang = 'en'; // Default language
|
|
347
|
+
}
|
|
348
|
+
await next();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
app.use(koaClassicServer(__dirname + '/views', {
|
|
352
|
+
index: ['index.ejs'],
|
|
353
|
+
useOriginalUrl: false, // Resolve files from rewritten URL
|
|
354
|
+
hideExtension: {
|
|
355
|
+
ext: '.ejs',
|
|
356
|
+
redirect: 301
|
|
357
|
+
},
|
|
358
|
+
template: {
|
|
359
|
+
ext: ['ejs'],
|
|
360
|
+
render: async (ctx, next, filePath) => {
|
|
361
|
+
ctx.body = await ejs.renderFile(filePath, { lang: ctx.state.lang });
|
|
362
|
+
ctx.type = 'text/html';
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}));
|
|
366
|
+
|
|
367
|
+
app.listen(3000);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Result:**
|
|
371
|
+
|
|
372
|
+
| Request | Rewritten URL | File resolved | Redirect target |
|
|
373
|
+
|---------|---------------|---------------|-----------------|
|
|
374
|
+
| `/it/about` | `/about` | `views/about.ejs` | — |
|
|
375
|
+
| `/en/blog/first-post` | `/blog/first-post` | `views/blog/first-post.ejs` | — |
|
|
376
|
+
| `/it/about.ejs` | `/about.ejs` | — | 301 → `/it/about` (preserves `/it/` prefix) |
|
|
377
|
+
|
|
378
|
+
> **Note**: Redirects always use `ctx.originalUrl` to preserve the language prefix, regardless of the `useOriginalUrl` setting.
|
|
379
|
+
|
|
380
|
+
#### Temporary redirect (302)
|
|
381
|
+
|
|
382
|
+
Use `redirect: 302` instead of 301 when the URL mapping may change (staging, A/B testing, or during migration):
|
|
383
|
+
|
|
384
|
+
```javascript
|
|
385
|
+
hideExtension: {
|
|
386
|
+
ext: '.ejs',
|
|
387
|
+
redirect: 302 // Temporary redirect — browsers won't cache it
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
> **When to use 302**: A 301 (permanent) tells browsers and search engines to cache the redirect. Use 302 (temporary) during development, staging, or when you're not yet sure the clean URL structure is final.
|
|
392
|
+
|
|
393
|
+
### 9. With HTTP Caching
|
|
268
394
|
|
|
269
395
|
Enable aggressive caching for static files:
|
|
270
396
|
|
|
@@ -286,7 +412,7 @@ The default value for `browserCacheEnabled` is `false` to facilitate development
|
|
|
286
412
|
|
|
287
413
|
**See details:** [HTTP Caching Optimization →](./docs/OPTIMIZATION_HTTP_CACHING.md)
|
|
288
414
|
|
|
289
|
-
###
|
|
415
|
+
### 10. Multiple Index Files with Priority
|
|
290
416
|
|
|
291
417
|
Search for multiple index files with custom order:
|
|
292
418
|
|
|
@@ -303,7 +429,7 @@ app.use(koaClassicServer(__dirname + '/public', {
|
|
|
303
429
|
|
|
304
430
|
**See details:** [Index Option Priority →](./docs/INDEX_OPTION_PRIORITY.md)
|
|
305
431
|
|
|
306
|
-
###
|
|
432
|
+
### 11. Complete Production Example
|
|
307
433
|
|
|
308
434
|
Real-world configuration for production:
|
|
309
435
|
|
|
@@ -326,9 +452,15 @@ app.use(koaClassicServer(path.join(__dirname, 'public'), {
|
|
|
326
452
|
browserCacheMaxAge: 86400, // 24 hours
|
|
327
453
|
}));
|
|
328
454
|
|
|
329
|
-
// Serve dynamic templates
|
|
455
|
+
// Serve dynamic templates with clean URLs
|
|
330
456
|
app.use(koaClassicServer(path.join(__dirname, 'views'), {
|
|
331
457
|
showDirContents: false,
|
|
458
|
+
index: ['index.ejs'],
|
|
459
|
+
useOriginalUrl: false, // Use ctx.url (for i18n or routing middleware)
|
|
460
|
+
hideExtension: {
|
|
461
|
+
ext: '.ejs', // /about → serves about.ejs
|
|
462
|
+
redirect: 301 // /about.ejs → 301 redirect to /about
|
|
463
|
+
},
|
|
332
464
|
template: {
|
|
333
465
|
ext: ['ejs'],
|
|
334
466
|
render: async (ctx, next, filePath) => {
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ All notable changes to koa-classic-server will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.5.1] - 2026-03-01
|
|
9
|
+
|
|
10
|
+
### 📝 Documentation
|
|
11
|
+
|
|
12
|
+
- Added dedicated usage example for `useOriginalUrl` (Section 7) with realistic i18n middleware scenario (/it/, /en/, /fr/)
|
|
13
|
+
- Added "Advanced hideExtension Scenarios" section (Section 8):
|
|
14
|
+
- Recommended file/directory structure (ASCII tree)
|
|
15
|
+
- Combined `hideExtension` + i18n middleware example with `useOriginalUrl: false`
|
|
16
|
+
- Temporary redirect (302) variant with guidance on 301 vs 302 usage
|
|
17
|
+
- Added `hideExtension` and `useOriginalUrl` to the Complete Production Example (Section 11)
|
|
18
|
+
|
|
19
|
+
### 📦 Package Changes
|
|
20
|
+
- **Version**: `2.5.0` → `2.5.1`
|
|
21
|
+
- **Semver**: Patch version bump (documentation only, no code changes)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
8
25
|
## [2.5.0] - 2026-02-28
|
|
9
26
|
|
|
10
27
|
### ✨ New Feature
|
package/docs/DOCUMENTATION.md
CHANGED
|
@@ -90,13 +90,17 @@ Il middleware segue questo flusso per ogni richiesta HTTP:
|
|
|
90
90
|
### Dipendenze
|
|
91
91
|
|
|
92
92
|
#### Production
|
|
93
|
-
- **
|
|
94
|
-
|
|
93
|
+
- **mime-types** (^2.1.35): Riconoscimento automatico MIME types
|
|
94
|
+
|
|
95
|
+
#### Peer Dependencies
|
|
96
|
+
- **koa** (^2.0.0 || >=3.1.2): Framework web minimale per Node.js
|
|
95
97
|
|
|
96
98
|
#### Development
|
|
97
|
-
- **jest** (^
|
|
98
|
-
- **supertest** (^7.
|
|
99
|
-
- **inquirer** (^
|
|
99
|
+
- **jest** (^30.2.0): Framework di testing
|
|
100
|
+
- **supertest** (^7.2.2): Testing richieste HTTP
|
|
101
|
+
- **inquirer** (^13.3.0): CLI interattiva per testing manuale
|
|
102
|
+
- **autocannon** (^8.0.0): HTTP benchmarking
|
|
103
|
+
- **ejs** (^3.1.10): Template engine per i test
|
|
100
104
|
|
|
101
105
|
---
|
|
102
106
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koa-classic-server",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.2",
|
|
4
4
|
"description": "High-performance Koa middleware for serving static files with Apache-like directory listing, HTTP caching, template engine support, and comprehensive security fixes",
|
|
5
5
|
"main": "index.cjs",
|
|
6
6
|
"exports": {
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"mime-types": "^2.1.35"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"koa": "^2.0.0 ||
|
|
40
|
+
"koa": "^2.0.0 || >=3.1.2"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"autocannon": "^
|
|
43
|
+
"autocannon": "^8.0.0",
|
|
44
44
|
"ejs": "^3.1.10",
|
|
45
|
-
"inquirer": "^
|
|
46
|
-
"jest": "^
|
|
47
|
-
"supertest": "^7.
|
|
45
|
+
"inquirer": "^13.3.0",
|
|
46
|
+
"jest": "^30.2.0",
|
|
47
|
+
"supertest": "^7.2.2"
|
|
48
48
|
}
|
|
49
49
|
}
|