diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39003ee984..e882bdf919 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,27 @@ jobs: cache: 'npm' - run: npm ci - run: npm test + benchmark: + name: Benchmark + runs-on: ubuntu-latest + needs: build + strategy: + matrix: + node-version: + - 20.x + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm ci + - run: npm run benchmark + release: name: Release if: github.ref == 'refs/heads/main' && success() diff --git a/benchmarks/Makefile b/benchmarks/Makefile deleted file mode 100644 index ed1ddfc4f3..0000000000 --- a/benchmarks/Makefile +++ /dev/null @@ -1,17 +0,0 @@ - -all: - @./run 1 middleware 50 - @./run 5 middleware 50 - @./run 10 middleware 50 - @./run 15 middleware 50 - @./run 20 middleware 50 - @./run 30 middleware 50 - @./run 50 middleware 50 - @./run 100 middleware 50 - @./run 10 middleware 100 - @./run 10 middleware 250 - @./run 10 middleware 500 - @./run 10 middleware 1000 - @echo - -.PHONY: all diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 0000000000..f3dec7e076 --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,90 @@ +# Benchmark history + + +# 2024-01-06 + +Redesigned Express to not create a prototype chain on the req/res objects. The following are the benchmark results between the old version (Express 5 - with prototype chaining) with the new design. + +**System Specs** + +- Mac mini +- Apple M1 +- Memory: 16 GB +- OS Version: 14.2.1 macOS Sonoma + +## Old design (with prototype chain) + + autocannon -c 100 -d 5 -p 10 http://localhost:3333/?foo[bar]=baz + + Running 5s test @ http://localhost:3333/?foo[bar]=baz + 100 connections with 10 pipelining factor + + + ┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬─────────┐ + │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ + ├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼─────────┤ + │ Latency │ 16 ms │ 29 ms │ 66 ms │ 70 ms │ 38.63 ms │ 61.67 ms │ 1562 ms │ + └─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴─────────┘ + ┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬──────────┬─────────┐ + │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ + ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤ + │ Req/Sec │ 22,351 │ 22,351 │ 26,143 │ 26,543 │ 25,460.8 │ 1,568.25 │ 22,336 │ + ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤ + │ Bytes/Sec │ 5.32 MB │ 5.32 MB │ 6.22 MB │ 6.32 MB │ 6.06 MB │ 375 kB │ 5.32 MB │ + └───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴──────────┴─────────┘ + + Req/Bytes counts sampled once per second. + # of samples: 5 + + 128k requests in 5.02s, 30.3 MB read + +## New design + + autocannon -c 100 -d 5 -p 10 http://localhost:3333/?foo[bar]=baz + + Running 5s test @ http://localhost:3333/?foo[bar]=baz + 100 connections with 10 pipelining factor + + + ┌─────────┬──────┬───────┬───────┬───────┬──────────┬──────────┬────────┐ + │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ + ├─────────┼──────┼───────┼───────┼───────┼──────────┼──────────┼────────┤ + │ Latency │ 9 ms │ 16 ms │ 22 ms │ 26 ms │ 16.32 ms │ 11.46 ms │ 471 ms │ + └─────────┴──────┴───────┴───────┴───────┴──────────┴──────────┴────────┘ + ┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬──────────┬─────────┐ + │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ + ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤ + │ Req/Sec │ 54,943 │ 54,943 │ 60,575 │ 60,703 │ 59,363.2 │ 2,230.44 │ 54,922 │ + ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤ + │ Bytes/Sec │ 13.1 MB │ 13.1 MB │ 14.4 MB │ 14.4 MB │ 14.1 MB │ 531 kB │ 13.1 MB │ + └───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴──────────┴─────────┘ + + Req/Bytes counts sampled once per second. + # of samples: 5 + + 298k requests in 5.02s, 70.6 MB read + +# Results + +## Version 3 - 1/6/2024, 6:51:42 PM + +| Stat | 2.5% | 50% | 97.5% | 99% | Avg | Stdev | Max | +|:-----|:----:|:---:|:-----:|:---:|:---:|:-----:|:---:| +| Latency | 7 ms | 18 ms | 21 ms | 26 ms | 15.23 ms | 17.1 ms | 600 ms | + +| Stat | 1% | 2.5% | 50% | 97.5% | Avg | Stdev | Min | +|:-----|:--:|:----:|:---:|:-----:|:---:|:-----:|:---:| +| Req/Sec | 56,255 | 56,255 | 64,511 | 66,495 | 63,388.8 | 3,687.84 | 56,241 | +| Bytes/Sec | 13.4 MB | 13.4 MB | 15.4 MB | 15.8 MB | 15.1 MB | 877 kB | 13.4 MB | + +## Version 3 - 1/6/2024, 7:19:01 PM + +| Stat | 2.5% | 50% | 97.5% | 99% | Avg | Stdev | Max | +|:-----|:----:|:---:|:-----:|:---:|:---:|:-----:|:---:| +| Latency | 8 ms | 18 ms | 20 ms | 22 ms | 15.4 ms | 18.39 ms | 667 ms | + +| Stat | 1% | 2.5% | 50% | 97.5% | Avg | Stdev | Min | +|:-----|:--:|:----:|:---:|:-----:|:---:|:-----:|:---:| +| Req/Sec | 52,095 | 52,095 | 65,439 | 65,855 | 62,758.4 | 5,344.96 | 52,088 | +| Bytes/Sec | 12.4 MB | 12.4 MB | 15.6 MB | 15.7 MB | 14.9 MB | 1.27 MB | 12.4 MB | + diff --git a/benchmarks/index.mjs b/benchmarks/index.mjs new file mode 100644 index 0000000000..b07c54555b --- /dev/null +++ b/benchmarks/index.mjs @@ -0,0 +1,126 @@ + +import express from '../index.js' +import autocannon from 'autocannon' +import prettyBytes from 'pretty-bytes' +import fs from 'node:fs' + +const toMs = (ns) => { + return `${Math.floor(ns * 100) / 100} ms`; +} +const format = (ns) => { + return ns.toLocaleString({minimumFractionDigits: 2, maximumFractionDigits: 2}) +} + +const toTable = (data) => { + const { latency, requests, throughput } = data + const latencyTable = ` +| Stat | 2.5% | 50% | 97.5% | 99% | Avg | Stdev | Max | +|:-----|:----:|:---:|:-----:|:---:|:---:|:-----:|:---:| +| Latency | ${toMs(latency.p2_5)} | ${toMs(latency.p50)} | ${toMs(latency.p97_5)} | ${toMs(latency.p99)} | ${toMs(latency.average)} | ${toMs(latency.stddev)} | ${toMs(latency.max)} | +` + const rateTable = ` +| Stat | 1% | 2.5% | 50% | 97.5% | Avg | Stdev | Min | +|:-----|:--:|:----:|:---:|:-----:|:---:|:-----:|:---:| +| Req/Sec | ${format(requests.p1)} | ${format(requests.p2_5)} | ${format(requests.p50)} | ${format(requests.p97_5)} | ${format(requests.average)} | ${format(requests.stddev)} | ${format(requests.min)} | +| Bytes/Sec | ${prettyBytes(throughput.p1)} | ${prettyBytes(throughput.p2_5)} | ${prettyBytes(throughput.p50)} | ${prettyBytes(throughput.p97_5)} | ${prettyBytes(throughput.average)} | ${prettyBytes(throughput.stddev)} | ${prettyBytes(throughput.min)} | +` + return latencyTable + rateTable +} +const toHtmlTable = (data) => { + const { latency, requests, throughput } = data + const latencyTable = ` + + + + + + + + + + + + + + + + + + + + + + + + + +
Stat2.5%50%97.5%99%AvgStdevMax
Latency${toMs(latency.p2_5)} ms${toMs(latency.p50)} ms${toMs(latency.p97_5)} ms${toMs(latency.p99)} ms${toMs(latency.average)} ms${toMs(latency.stddev)} ms${toMs(latency.max)} ms
+` + const rateTable = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Stat1%2.5%50%97.5%AvgStdevMin
Req/Sec${requests.p1.toLocaleString()}${requests.p2_5.toLocaleString()}${requests.p50.toLocaleString()}${requests.p97_5.toLocaleString()}${requests.average.toLocaleString()}${requests.stddev.toLocaleString()}${requests.min.toLocaleString()}
Bytes/Sec${prettyBytes(throughput.p1)}${prettyBytes(throughput.p2_5)}${prettyBytes(throughput.p50)}${prettyBytes(throughput.p97_5)}${prettyBytes(throughput.average)}${prettyBytes(throughput.stddev)}${prettyBytes(throughput.min)}
+` + return latencyTable + rateTable +} +const app = express() +let n = parseInt(process.env.MW || '1', 10) +console.log(' %s middleware', n) +while (n--) { + app.use(function(req, res, next){ + next() + }) +} +app.use((req, res) => { + res.send('Hello World') +}) +const server = app.listen() +const { port } = server.address() +autocannon({ + url: `http://localhost:${port}/?foo[bar]=baz`, + pipelining: 10, + connections: 100, + duration: 5, + title: 'Version 3', + workers: 4 +}, (err, result) => { + console.log(toTable(result)) + fs.appendFile(`benchmarks/README.md`, `## ${result.title} - ${new Date().toLocaleString()} +${toTable(result)}\n`, 'utf8', () => { + server.close() + }) +}) + diff --git a/benchmarks/middleware.js b/benchmarks/middleware.js deleted file mode 100644 index fed97ba8ce..0000000000 --- a/benchmarks/middleware.js +++ /dev/null @@ -1,20 +0,0 @@ - -var express = require('..'); -var app = express(); - -// number of middleware - -var n = parseInt(process.env.MW || '1', 10); -console.log(' %s middleware', n); - -while (n--) { - app.use(function(req, res, next){ - next(); - }); -} - -app.use(function(req, res){ - res.send('Hello World') -}); - -app.listen(3333); diff --git a/benchmarks/run b/benchmarks/run deleted file mode 100755 index ec8f55d564..0000000000 --- a/benchmarks/run +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -echo -MW=$1 node $2 & -pid=$! - -echo " $3 connections" - -sleep 2 - -wrk 'http://localhost:3333/?foo[bar]=baz' \ - -d 3 \ - -c $3 \ - -t 8 \ - | grep 'Requests/sec\|Latency' \ - | awk '{ print " " $2 }' - -kill $pid diff --git a/package-lock.json b/package-lock.json index 98a9455b5d..c31259f753 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ }, "devDependencies": { "after": "^0.8.2", + "autocannon": "^7.14.0", "connect-redis": "^7.1.0", "cookie-parser": "^1.4.6", "cookie-session": "^2.0.0", @@ -69,6 +70,22 @@ "node": ">=0.10.0" } }, + "node_modules/@assemblyscript/loader": { + "version": "0.19.23", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.19.23.tgz", + "integrity": "sha512-ulkCYfFbYj01ie1MDOyxv2F6SpRN1TOj7fQxbP07D6HmeR+gr2JLSmINKjga2emB+b1L2KGrFKBTc+e00p54nw==", + "dev": true + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -314,12 +331,66 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/autocannon": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/autocannon/-/autocannon-7.14.0.tgz", + "integrity": "sha512-lusP43BAwrTwQhihLjKwy7LceyX01eKSvFJUsBktASGqcR1g1ySYSPxCoCGDX08uLEs9oaqEKBBUFMenK3B3lQ==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "char-spinner": "^1.0.1", + "cli-table3": "^0.6.0", + "color-support": "^1.1.1", + "cross-argv": "^2.0.0", + "form-data": "^4.0.0", + "has-async-hooks": "^1.0.0", + "hdr-histogram-js": "^3.0.0", + "hdr-histogram-percentiles-obj": "^3.0.0", + "http-parser-js": "^0.5.2", + "hyperid": "^3.0.0", + "lodash.chunk": "^4.2.0", + "lodash.clonedeep": "^4.5.0", + "lodash.flatten": "^4.4.0", + "manage-path": "^2.0.0", + "on-net-listen": "^1.1.1", + "pretty-bytes": "^5.4.1", + "progress": "^2.0.3", + "reinterval": "^1.1.0", + "retimer": "^3.0.0", + "semver": "^7.3.2", + "subarg": "^1.0.0", + "timestring": "^6.0.0" + }, + "bin": { + "autocannon": "autocannon.js" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -452,6 +523,27 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/char-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/char-spinner/-/char-spinner-1.0.1.tgz", + "integrity": "sha512-acv43vqJ0+N0rD+Uw3pDHSxP30FHrywu2NO6/wBaHChJIizpDeBUd6NjqhNhy9LGaEAhZAXn46QzmlAvIWd16g==", + "dev": true + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -470,6 +562,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -621,6 +722,12 @@ "node": ">= 0.8" } }, + "node_modules/cross-argv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cross-argv/-/cross-argv-2.0.0.tgz", + "integrity": "sha512-YIaY9TR5Nxeb8SMdtrU8asWVM4jqJDNDYlKV21LxtYcfNJhp1kEsgSa6qXwXgzN0WQWGODps0+TlGp2xQSHwOg==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -743,6 +850,12 @@ "node": ">=0.10.0" } }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1291,6 +1404,12 @@ "uglify-js": "^3.1.4" } }, + "node_modules/has-async-hooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-async-hooks/-/has-async-hooks-1.0.0.tgz", + "integrity": "sha512-YF0VPGjkxr7AyyQQNykX8zK4PvtEDsUJAPqwu06UFz1lb6EvI53sPh5H1kWxg8NXI5LsfRCZ8uX9NkYDZBb/mw==", + "dev": true + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1358,6 +1477,26 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/hdr-histogram-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-3.0.0.tgz", + "integrity": "sha512-/EpvQI2/Z98mNFYEnlqJ8Ogful8OpArLG/6Tf2bPnkutBVLIeMVNHjk1ZDfshF2BUweipzbk+dB1hgSB7SIakw==", + "dev": true, + "dependencies": { + "@assemblyscript/loader": "^0.19.21", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, "node_modules/hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", @@ -1398,6 +1537,22 @@ "node": ">= 0.6" } }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/hyperid": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hyperid/-/hyperid-3.1.1.tgz", + "integrity": "sha512-RveV33kIksycSf7HLkq1sHB5wW0OwuX8ot8MYnY++gaaPXGFfKpBncHrAWxdpuEeRlazUMGWefwP1w6o6GaumA==", + "dev": true, + "dependencies": { + "uuid": "^8.3.2", + "uuid-parse": "^1.1.0" + } + }, "node_modules/iconv-lite": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", @@ -1475,6 +1630,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1587,12 +1751,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.chunk": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", + "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==", + "dev": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/manage-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/manage-path/-/manage-path-2.0.0.tgz", + "integrity": "sha512-NJhyB+PJYTpxhxZJ3lecIGgh4kwIY2RAh44XvAz9UlqthlQwtPBf62uBVR8XaD8CRuSjQ6TnZH2lNJkbLPZM2A==", + "dev": true + }, "node_modules/marked": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/marked/-/marked-11.1.0.tgz", @@ -1812,6 +2000,15 @@ "node": ">= 0.8" } }, + "node_modules/on-net-listen": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/on-net-listen/-/on-net-listen-1.1.2.tgz", + "integrity": "sha512-y1HRYy8s/RlcBvDUwKXSmkODMdx4KSuIvloCnQYJ2LdBBC1asY4HtfhXwe3UWknLakATZDnbzht2Ijw3M1EqFg==", + "dev": true, + "engines": { + "node": ">=9.4.0 || ^8.9.4" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1868,6 +2065,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1937,6 +2140,27 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2038,6 +2262,12 @@ "node": ">= 0.8" } }, + "node_modules/reinterval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==", + "dev": true + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2047,6 +2277,12 @@ "node": ">=4" } }, + "node_modules/retimer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz", + "integrity": "sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==", + "dev": true + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -2300,6 +2536,20 @@ "node": ">= 0.8" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2324,6 +2574,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", + "dev": true, + "dependencies": { + "minimist": "^1.1.0" + } + }, "node_modules/superagent": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", @@ -2376,6 +2635,15 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/timestring": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/timestring/-/timestring-6.0.0.tgz", + "integrity": "sha512-wMctrWD2HZZLuIlchlkE2dfXJh7J2KDI9Dwl+2abPYg0mswQHfOAyQW3jJg1pY5VfttSINZuKcXoB3FGypVklA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -2479,6 +2747,21 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uuid-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/uuid-parse/-/uuid-parse-1.1.0.tgz", + "integrity": "sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A==", + "dev": true + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 1ba198419f..724cd7893e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@hubot-friends/express", "description": "Fast, unopinionated, minimalist web framework", - "version": "5.0.0", + "version": "0.0.0-development", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", @@ -63,6 +63,7 @@ }, "devDependencies": { "after": "^0.8.2", + "autocannon": "^7.14.0", "connect-redis": "^7.1.0", "cookie-parser": "^1.4.6", "cookie-session": "^2.0.0", @@ -90,7 +91,8 @@ ], "scripts": { "pretest": "eslint .", - "test": "NODE_ENV=test NO_DEPRECATION='body-parser,express' node --test" + "test": "NODE_ENV=test NO_DEPRECATION='body-parser,express' node --test", + "benchmark": "node benchmarks/index.mjs" }, "release": { "branches": [