ultimate-express 1.0.2 → 1.0.3
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 +18 -1
- package/package.json +4 -4
- package/src/request.js +1 -1
- package/src/router.js +9 -3
- package/src/utils.js +5 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# µExpress
|
|
1
|
+
# µExpress / Ultimate Express
|
|
2
2
|
|
|
3
3
|
The *Ultimate* Express. Fastest http server with **full** Express compatibility, based on µWebSockets.
|
|
4
4
|
|
|
@@ -19,6 +19,21 @@ Similar projects based on uWebSockets:
|
|
|
19
19
|
- `hyper-express` - while having a similar API to Express, it's very far from being a drop-in replacement, and implements most of the functionality differently. This creates a lot of random quirks and issues, making the switch quite difficult. Built in middlewares are also very different.
|
|
20
20
|
- `uwebsockets-express` - this library is closer to being a drop-in replacement, but misses a lot of APIs, depends on Express by calling it's methods under the hood and doesn't try to optimize routing by using native uWS router.
|
|
21
21
|
|
|
22
|
+
## Performance
|
|
23
|
+
|
|
24
|
+
Tested using [wrk](https://github.com/wg/wrk) (`-d 60 -t 1 -c 200`). Etag was disabled in both Express and µExpress. Tested on Ubuntu 22.04, Node.js 20.17.0, AMD Ryzen 5 3600, 64GB RAM.
|
|
25
|
+
|
|
26
|
+
| Test | Path | Express req/sec | µExpress req/sec | Express throughput | µExpress throughput | µExpress speedup |
|
|
27
|
+
| --------------------------- | ---------------- | --------------- | ---------------- | ------------------ | ------------------- | ---------------- |
|
|
28
|
+
| routing/simple-routes.js | / | 10.90k | 70.10k | 2.04 MB/sec | 11.57 MB/sec | **6.43X** |
|
|
29
|
+
| routing/lot-of-routes.js | /999 | 4.66k | 51.58k | 0.85 MB/sec | 8.07 MB/sec | **11.07X** |
|
|
30
|
+
| routing/some-middlewares.js | /90 | 10.18k | 66.97k | 1.81 MB/sec | 10.42 MB/sec | **6.58X** |
|
|
31
|
+
| middlewares/express-static | /static/index.js | 7.52k | 31.08k | 6.92 MB/sec | 26.48 MB/sec | **4.13X** |
|
|
32
|
+
| engines/ejs.js | /test | 5.92k | 14.43k | 2.40 MB/sec | 5.53 MB/sec | **2.44X** |
|
|
33
|
+
| middlewares/body-urlencoded | /abc (POST) | 7.90k | 29.90k | 1.64 MB/sec | 5.36 MB/sec | **3.78X** |
|
|
34
|
+
|
|
35
|
+
Also tested on a real-world application with templates, static files and dynamic pages with data from database ([nekoweb.org](https://nekoweb.org)), and showed about 1.5-4X speedup in requests per second.
|
|
36
|
+
|
|
22
37
|
## Differences from Express
|
|
23
38
|
|
|
24
39
|
In a lot of cases, you can just replace `require("express")` with `require("ultimate-express")` and everything works the same. But there are some differences:
|
|
@@ -81,6 +96,8 @@ Optimized routes can be up to 10 times faster than normal routes, as they're usi
|
|
|
81
96
|
|
|
82
97
|
## Compatibility
|
|
83
98
|
|
|
99
|
+
In general, basically all features and options are supported. Use [Express 4.x documentation](https://expressjs.com/en/4x/api.html) for API reference.
|
|
100
|
+
|
|
84
101
|
✅ - Full support (all features and options are supported)
|
|
85
102
|
🚧 - Partial support (some options are not supported)
|
|
86
103
|
❌ - Not supported
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultimate-express",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
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": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
],
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
|
-
"url": "git+https://github.com/dimdenGD/
|
|
15
|
+
"url": "git+https://github.com/dimdenGD/ultimate-express.git"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"express",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"author": "dimden.dev",
|
|
32
32
|
"license": "Apache-2.0",
|
|
33
33
|
"bugs": {
|
|
34
|
-
"url": "https://github.com/dimdenGD/
|
|
34
|
+
"url": "https://github.com/dimdenGD/ultimate-express/issues"
|
|
35
35
|
},
|
|
36
|
-
"homepage": "https://github.com/dimdenGD/
|
|
36
|
+
"homepage": "https://github.com/dimdenGD/ultimate-express#readme",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"accepts": "^1.3.8",
|
|
39
39
|
"body-parser": "^1.20.3",
|
package/src/request.js
CHANGED
|
@@ -46,7 +46,7 @@ module.exports = class Request extends Readable {
|
|
|
46
46
|
this._gotParams = new Set();
|
|
47
47
|
this._stack = [];
|
|
48
48
|
this._paramStack = [];
|
|
49
|
-
this.bufferedData = Buffer.
|
|
49
|
+
this.bufferedData = Buffer.allocUnsafe(0);
|
|
50
50
|
this.receivedData = false;
|
|
51
51
|
|
|
52
52
|
const additionalMethods = this.app.get('body methods');
|
package/src/router.js
CHANGED
|
@@ -52,10 +52,11 @@ module.exports = class Router extends EventEmitter {
|
|
|
52
52
|
get(path, ...callbacks) {
|
|
53
53
|
if(typeof path === 'string' && callbacks.length === 0) {
|
|
54
54
|
const key = path;
|
|
55
|
-
|
|
55
|
+
const res = this.settings[key];
|
|
56
|
+
if(typeof res === 'undefined' && this.parent) {
|
|
56
57
|
return this.parent.get(key);
|
|
57
58
|
} else {
|
|
58
|
-
return
|
|
59
|
+
return res;
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
return this.#createRoute('GET', path, this, ...callbacks);
|
|
@@ -419,7 +420,12 @@ module.exports = class Router extends EventEmitter {
|
|
|
419
420
|
if(!skipCheck && skipUntil && skipUntil.routeKey >= route.routeKey) {
|
|
420
421
|
return next();
|
|
421
422
|
}
|
|
422
|
-
|
|
423
|
+
const out = callback(req, res, next);
|
|
424
|
+
if(out instanceof Promise) {
|
|
425
|
+
out.catch(err => {
|
|
426
|
+
throw err;
|
|
427
|
+
});
|
|
428
|
+
}
|
|
423
429
|
} catch(err) {
|
|
424
430
|
this.#handleError(err, req, res);
|
|
425
431
|
return resolve(true);
|
package/src/utils.js
CHANGED
|
@@ -13,7 +13,7 @@ function patternToRegex(pattern, isPrefix = false) {
|
|
|
13
13
|
if(pattern instanceof RegExp) {
|
|
14
14
|
return pattern;
|
|
15
15
|
}
|
|
16
|
-
if(isPrefix && pattern === '
|
|
16
|
+
if(isPrefix && pattern === '') {
|
|
17
17
|
return new RegExp(``);
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -241,7 +241,10 @@ function isPreconditionFailure(req, res) {
|
|
|
241
241
|
|
|
242
242
|
function createETagGenerator(options) {
|
|
243
243
|
return function generateETag (body, encoding) {
|
|
244
|
-
|
|
244
|
+
if(body instanceof Stats) {
|
|
245
|
+
return etag(body, options);
|
|
246
|
+
}
|
|
247
|
+
const buf = !Buffer.isBuffer(body) ? Buffer.from(body, encoding) : body;
|
|
245
248
|
return etag(buf, options);
|
|
246
249
|
}
|
|
247
250
|
}
|