From 877fb1276ab89d5eff25c33d0dab571be691680c Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Thu, 2 Apr 2026 20:56:01 +0000 Subject: [PATCH] feat: gzip compression by default for all registered routes --- .../app/middleware/compression_middleware.ts | 21 +++ admin/docs/release-notes.md | 2 + admin/package-lock.json | 157 ++++++++++++++++++ admin/package.json | 6 +- admin/start/env.ts | 1 + admin/start/kernel.ts | 1 + install/management_compose.yaml | 1 + 7 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 admin/app/middleware/compression_middleware.ts diff --git a/admin/app/middleware/compression_middleware.ts b/admin/app/middleware/compression_middleware.ts new file mode 100644 index 0000000..0661ac7 --- /dev/null +++ b/admin/app/middleware/compression_middleware.ts @@ -0,0 +1,21 @@ +import env from '#start/env' +import type { HttpContext } from '@adonisjs/core/http' +import type { NextFn } from '@adonisjs/core/types/http' +import compression from 'compression' + +const compress = env.get('DISABLE_COMPRESSION') ? null : compression() + +export default class CompressionMiddleware { + async handle({ request, response }: HttpContext, next: NextFn) { + if (!compress) return await next() + + await new Promise((resolve, reject) => { + compress(request.request as any, response.response as any, (err?: any) => { + if (err) reject(err) + else resolve() + }) + }) + + await next() + } +} diff --git a/admin/docs/release-notes.md b/admin/docs/release-notes.md index bc9b3ea..b1267ed 100644 --- a/admin/docs/release-notes.md +++ b/admin/docs/release-notes.md @@ -28,6 +28,8 @@ - **Docs**: Re-formatted the Quick Install command into multiple lines for better readability in the README. Thanks @samsara-02 for the contribution! - **Docs**: Updated the CONTRIBUTING and FAQ guides with the latest information and clarified some common questions. Thanks @jakeaturner for the contribution! - **Ops**: Bumped GitHub Actions to their latest versions. Thanks @salmanmkc for the contribution! +- **Performance**: Shrunk the bundle size of the Command Center UI significantly by optimizing dependencies and tree-shaking, resulting in faster load times and a snappier user experience. Thanks @jakeaturner for the contribution! +- **Performance**: Implemented gzip compression by default for all HTTP registered routes from the Command Center backend to further improve performance, especially on slower connections. The DISABLE_COMPRESSION environment variable can be used to turn off this feature if needed. Thanks @jakeaturner for the contribution! ## Version 1.30.3 - March 25, 2026 diff --git a/admin/package-lock.json b/admin/package-lock.json index 9a211f5..d34cc88 100644 --- a/admin/package-lock.json +++ b/admin/package-lock.json @@ -42,6 +42,7 @@ "better-sqlite3": "^12.1.1", "bullmq": "^5.65.1", "cheerio": "^1.2.0", + "compression": "^1.8.1", "dockerode": "^4.0.7", "edge.js": "^6.2.1", "fast-xml-parser": "^5.5.7", @@ -83,6 +84,7 @@ "@japa/runner": "^4.2.0", "@swc/core": "1.11.24", "@tanstack/eslint-plugin-query": "^5.81.2", + "@types/compression": "^1.8.1", "@types/dockerode": "^4.0.1", "@types/luxon": "^3.6.2", "@types/node": "^22.15.18", @@ -5144,6 +5146,17 @@ "@types/node": "*" } }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -5155,6 +5168,27 @@ "assertion-error": "^2.0.1" } }, + "node_modules/@types/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -5209,6 +5243,31 @@ "@types/estree": "*" } }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", @@ -5239,6 +5298,13 @@ "integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==", "license": "MIT" }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -5393,6 +5459,13 @@ "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "license": "MIT" }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.2.10", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.10.tgz", @@ -5412,6 +5485,27 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, "node_modules/@types/ssh2": { "version": "1.15.5", "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.5.tgz", @@ -7223,6 +7317,60 @@ "devOptional": true, "license": "ISC" }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -12699,6 +12847,15 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", diff --git a/admin/package.json b/admin/package.json index 1164029..ab229f4 100644 --- a/admin/package.json +++ b/admin/package.json @@ -47,6 +47,7 @@ "@japa/runner": "^4.2.0", "@swc/core": "1.11.24", "@tanstack/eslint-plugin-query": "^5.81.2", + "@types/compression": "^1.8.1", "@types/dockerode": "^4.0.1", "@types/luxon": "^3.6.2", "@types/node": "^22.15.18", @@ -94,10 +95,12 @@ "better-sqlite3": "^12.1.1", "bullmq": "^5.65.1", "cheerio": "^1.2.0", + "compression": "^1.8.1", "dockerode": "^4.0.7", "edge.js": "^6.2.1", "fast-xml-parser": "^5.5.7", "fuse.js": "^7.1.0", + "jszip": "^3.10.1", "luxon": "^3.6.1", "maplibre-gl": "^4.7.1", "mysql2": "^3.14.1", @@ -122,8 +125,7 @@ "tar": "^7.5.11", "tesseract.js": "^7.0.0", "url-join": "^5.0.0", - "yaml": "^2.8.3", - "jszip": "^3.10.1" + "yaml": "^2.8.3" }, "hotHook": { "boundaries": [ diff --git a/admin/start/env.ts b/admin/start/env.ts index ddf9b5f..8223fa9 100644 --- a/admin/start/env.ts +++ b/admin/start/env.ts @@ -19,6 +19,7 @@ export default await Env.create(new URL('../', import.meta.url), { URL: Env.schema.string(), LOG_LEVEL: Env.schema.string(), INTERNET_STATUS_TEST_URL: Env.schema.string.optional(), + DISABLE_COMPRESSION: Env.schema.boolean.optional(), /* |---------------------------------------------------------- diff --git a/admin/start/kernel.ts b/admin/start/kernel.ts index 56e1afa..cde1fb0 100644 --- a/admin/start/kernel.ts +++ b/admin/start/kernel.ts @@ -39,6 +39,7 @@ router.use([ () => import('@adonisjs/core/bodyparser_middleware'), // () => import('@adonisjs/session/session_middleware'), () => import('@adonisjs/shield/shield_middleware'), + () => import('#middleware/compression_middleware'), ]) /** diff --git a/install/management_compose.yaml b/install/management_compose.yaml index cadf753..f4c7b5f 100644 --- a/install/management_compose.yaml +++ b/install/management_compose.yaml @@ -44,6 +44,7 @@ services: - REDIS_HOST=redis # If you change the Redis port, make sure to update this accordingly - REDIS_PORT=6379 + - DISABLE_COMPRESSION=false # Most reverse proxies (Nginx, Caddy, etc.) will skip compression if the response is already compressed so this is usally a win all around, but if this causes issues with your setup you can set it to "true" to disable gzip in the admin server depends_on: mysql: condition: service_healthy