ultimate-express 1.4.8 → 1.4.9
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 +1 -1
- package/package.json +4 -1
- package/src/declarative.js +5 -0
- package/src/response.js +22 -4
- package/src/router.js +3 -0
- package/src/view.js +12 -13
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ app.listen(3000, () => {
|
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
- This also applies to non-SSL HTTP too. Do not create http server manually, use `app.listen()` instead.
|
|
104
|
-
-
|
|
104
|
+
- Node.JS max header size is 16384 bytes, while uWebSockets by default is 4096 bytes, so if you need longer headers set the env variable `UWS_HTTP_MAX_HEADERS_SIZE` to max byte count you need.
|
|
105
105
|
|
|
106
106
|
## Performance tips
|
|
107
107
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultimate-express",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.9",
|
|
4
4
|
"description": "The Ultimate Express. Fastest http server with full Express compatibility, based on uWebSockets.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@codechecks/client": "^0.1.12",
|
|
70
|
+
"better-sse": "^0.14.1",
|
|
70
71
|
"body-parser": "^1.20.3",
|
|
71
72
|
"compression": "^1.8.0",
|
|
72
73
|
"cookie-parser": "^1.4.6",
|
|
@@ -74,6 +75,7 @@
|
|
|
74
75
|
"cors": "^2.8.5",
|
|
75
76
|
"ejs": "^3.1.10",
|
|
76
77
|
"errorhandler": "^1.5.1",
|
|
78
|
+
"eventsource": "^3.0.6",
|
|
77
79
|
"exit-hook": "^2.2.1",
|
|
78
80
|
"express": "latest-4",
|
|
79
81
|
"express-art-template": "^1.0.1",
|
|
@@ -86,6 +88,7 @@
|
|
|
86
88
|
"express-session": "^1.18.0",
|
|
87
89
|
"express-subdomain": "^1.0.6",
|
|
88
90
|
"formdata-node": "^6.0.3",
|
|
91
|
+
"graphql-http": "^1.22.4",
|
|
89
92
|
"helmet": "^8.1.0",
|
|
90
93
|
"method-override": "^3.0.0",
|
|
91
94
|
"morgan": "^1.10.0",
|
package/src/declarative.js
CHANGED
|
@@ -201,8 +201,12 @@ module.exports = function compileDeclarative(cb, app) {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
// get body
|
|
204
|
+
let sendUsed = false;
|
|
204
205
|
for(let call of callExprs) {
|
|
205
206
|
if(call.obj.propertyName === 'send' || call.obj.propertyName === 'end') {
|
|
207
|
+
if(sendUsed) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
206
210
|
const arg = call.arguments[0];
|
|
207
211
|
if(arg) {
|
|
208
212
|
if(arg.type === 'Literal') {
|
|
@@ -315,6 +319,7 @@ module.exports = function compileDeclarative(cb, app) {
|
|
|
315
319
|
return false;
|
|
316
320
|
}
|
|
317
321
|
}
|
|
322
|
+
sendUsed = true;
|
|
318
323
|
}
|
|
319
324
|
}
|
|
320
325
|
|
package/src/response.js
CHANGED
|
@@ -71,6 +71,7 @@ module.exports = class Response extends Writable {
|
|
|
71
71
|
#socket = null;
|
|
72
72
|
#pendingChunks = [];
|
|
73
73
|
#lastWriteChunkTime = 0;
|
|
74
|
+
#writeTimeout = null;
|
|
74
75
|
constructor(res, req, app) {
|
|
75
76
|
super();
|
|
76
77
|
this._req = req;
|
|
@@ -155,11 +156,27 @@ module.exports = class Response extends Writable {
|
|
|
155
156
|
const now = Date.now();
|
|
156
157
|
// the first chunk is sent immediately (!this.#lastWriteChunkTime)
|
|
157
158
|
// the other chunks are sent when watermark is reached (size >= HIGH_WATERMARK)
|
|
158
|
-
// or if elapsed
|
|
159
|
-
if (!this.#lastWriteChunkTime || size >= HIGH_WATERMARK || now - this.#lastWriteChunkTime >
|
|
159
|
+
// or if elapsed 50ms of last send (now - this.#lastWriteChunkTime > 50)
|
|
160
|
+
if (!this.#lastWriteChunkTime || size >= HIGH_WATERMARK || now - this.#lastWriteChunkTime > 50) {
|
|
160
161
|
this._res.write(Buffer.concat(this.#pendingChunks, size));
|
|
161
162
|
this.#pendingChunks = [];
|
|
162
163
|
this.#lastWriteChunkTime = now;
|
|
164
|
+
if(this.#writeTimeout) {
|
|
165
|
+
clearTimeout(this.#writeTimeout);
|
|
166
|
+
this.#writeTimeout = null;
|
|
167
|
+
}
|
|
168
|
+
} else if(!this.#writeTimeout) {
|
|
169
|
+
this.#writeTimeout = setTimeout(() => {
|
|
170
|
+
this.#writeTimeout = null;
|
|
171
|
+
if(!this.finished && !this.aborted) this._res.cork(() => {
|
|
172
|
+
if(this.#pendingChunks.length) {
|
|
173
|
+
const size = this.#pendingChunks.reduce((acc, chunk) => acc + chunk.byteLength, 0);
|
|
174
|
+
this._res.write(Buffer.concat(this.#pendingChunks, size));
|
|
175
|
+
this.#pendingChunks = [];
|
|
176
|
+
this.#lastWriteChunkTime = now;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}, 50);
|
|
163
180
|
}
|
|
164
181
|
this.writingChunk = false;
|
|
165
182
|
callback(null);
|
|
@@ -201,12 +218,13 @@ module.exports = class Response extends Writable {
|
|
|
201
218
|
this.statusText = statusMessage;
|
|
202
219
|
}
|
|
203
220
|
if(!headers) {
|
|
204
|
-
if(!statusMessage) return;
|
|
221
|
+
if(!statusMessage) return this;
|
|
205
222
|
headers = statusMessage;
|
|
206
223
|
}
|
|
207
224
|
for(let header in headers) {
|
|
208
225
|
this.set(header, headers[header]);
|
|
209
226
|
}
|
|
227
|
+
return this;
|
|
210
228
|
}
|
|
211
229
|
writeHeaders(utf8) {
|
|
212
230
|
for(const header in this.headers) {
|
|
@@ -766,4 +784,4 @@ module.exports = class Response extends Writable {
|
|
|
766
784
|
get writableFinished() {
|
|
767
785
|
return this.finished;
|
|
768
786
|
}
|
|
769
|
-
}
|
|
787
|
+
}
|
package/src/router.js
CHANGED
|
@@ -526,6 +526,9 @@ module.exports = class Router extends EventEmitter {
|
|
|
526
526
|
req._opPath += '/';
|
|
527
527
|
}
|
|
528
528
|
const routed = await callback._routeRequest(req, res, 0);
|
|
529
|
+
if (req._error) {
|
|
530
|
+
req._errorKey = route.routeKey;
|
|
531
|
+
}
|
|
529
532
|
if(routed) return resolve(true);
|
|
530
533
|
next();
|
|
531
534
|
} else {
|
package/src/view.js
CHANGED
|
@@ -59,26 +59,25 @@ module.exports = class View {
|
|
|
59
59
|
this.path += this.ext;
|
|
60
60
|
}
|
|
61
61
|
} else {
|
|
62
|
-
this.path =
|
|
62
|
+
this.path = this.lookup(fileName);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
lookup(name) {
|
|
67
|
-
let
|
|
67
|
+
let _path;
|
|
68
68
|
let roots = [].concat(this.root);
|
|
69
|
-
for (let i = 0; i < roots.length && !
|
|
69
|
+
for (let i = 0; i < roots.length && !_path; i++) {
|
|
70
70
|
const root = roots[i];
|
|
71
71
|
|
|
72
72
|
// resolve the path
|
|
73
73
|
const loc = path.resolve(root, name);
|
|
74
74
|
const dir = path.dirname(loc);
|
|
75
75
|
const file = path.basename(loc);
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
// resolve the file
|
|
78
|
-
|
|
78
|
+
_path = this.resolve(dir, file);
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
return path;
|
|
80
|
+
return _path;
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
// ill be real idk what exactly this does but express implements it this way
|
|
@@ -101,19 +100,19 @@ module.exports = class View {
|
|
|
101
100
|
const ext = this.ext;
|
|
102
101
|
|
|
103
102
|
// <path>.<ext>
|
|
104
|
-
let
|
|
105
|
-
let stat = tryStat(
|
|
103
|
+
let _path = path.join(dir, file);
|
|
104
|
+
let stat = tryStat(_path);
|
|
106
105
|
|
|
107
106
|
if(stat && stat.isFile()) {
|
|
108
|
-
return
|
|
107
|
+
return _path;
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
// <path>/index.<ext>
|
|
112
|
-
|
|
113
|
-
stat = tryStat(
|
|
111
|
+
_path = path.join(dir, path.basename(file, ext), 'index' + ext);
|
|
112
|
+
stat = tryStat(_path);
|
|
114
113
|
|
|
115
114
|
if(stat && stat.isFile()) {
|
|
116
|
-
return
|
|
115
|
+
return _path;
|
|
117
116
|
}
|
|
118
117
|
}
|
|
119
118
|
}
|