feat: adiciona pré-compressão gzip no build
- Instala vite-plugin-compression2 para gerar .gz no build - Configura Express para servir arquivos .gz quando disponível - Reduz transferência em ~70% para assets principais Agent.js: 33KB → 9.9KB (gzip) index.js: 348KB → 108KB (gzip)
This commit is contained in:
parent
58efb8c95c
commit
e27f2998e5
|
|
@ -146,7 +146,8 @@
|
|||
"tailwindcss": "^4.1.14",
|
||||
"tsx": "^4.20.5",
|
||||
"typescript": "5.6.3",
|
||||
"vite": "^7.1.9"
|
||||
"vite": "^7.1.9",
|
||||
"vite-plugin-compression2": "^2.5.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.8"
|
||||
|
|
@ -5515,6 +5516,29 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
|
||||
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
|
||||
|
|
@ -9660,6 +9684,13 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
|
|
@ -13631,6 +13662,13 @@
|
|||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-mini": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-mini/-/tar-mini-0.2.0.tgz",
|
||||
"integrity": "sha512-+qfUHz700DWnRutdUsxRRVZ38G1Qr27OetwaMYTdg8hcPxf46U0S1Zf76dQMWRBmusOt2ZCK5kbIaiLkoGO7WQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/text-hex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||
|
|
@ -14133,6 +14171,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite-plugin-compression2": {
|
||||
"version": "2.5.3",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-compression2/-/vite-plugin-compression2-2.5.3.tgz",
|
||||
"integrity": "sha512-ItPgqQWkcnBbVw7is9OKwiZ8v6+ju9rYROl5Lp6QfQDEx/d55AwJQb/KLpsQqsU9HoigYBsZ8tK6I02UwJNvEw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": "^5.1.0",
|
||||
"tar-mini": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-keyname": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||
|
|
|
|||
|
|
@ -153,7 +153,8 @@
|
|||
"tailwindcss": "^4.1.14",
|
||||
"tsx": "^4.20.5",
|
||||
"typescript": "5.6.3",
|
||||
"vite": "^7.1.9"
|
||||
"vite": "^7.1.9",
|
||||
"vite-plugin-compression2": "^2.5.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.8"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import express, { type Express } from "express";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import compression from "compression";
|
||||
|
||||
export function serveStatic(app: Express) {
|
||||
const distPath = path.resolve(__dirname, "public");
|
||||
|
|
@ -11,29 +10,48 @@ export function serveStatic(app: Express) {
|
|||
);
|
||||
}
|
||||
|
||||
// Enable gzip compression for static assets
|
||||
// Caddy/Traefik devem respeitar isso ou fazer override
|
||||
app.use(compression({
|
||||
level: 6,
|
||||
threshold: 1024, // Compress files > 1KB
|
||||
filter: (req, res) => {
|
||||
// Don't compress if already compressed by proxy
|
||||
if (req.headers['x-no-compression']) {
|
||||
return false;
|
||||
// Middleware to serve pre-compressed .gz files
|
||||
app.use((req, res, next) => {
|
||||
const acceptEncoding = req.headers["accept-encoding"] || "";
|
||||
|
||||
// Only handle GET/HEAD requests
|
||||
if (req.method !== "GET" && req.method !== "HEAD") {
|
||||
return next();
|
||||
}
|
||||
|
||||
// Check if client accepts gzip
|
||||
if (!acceptEncoding.includes("gzip")) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const url = req.url;
|
||||
// Only handle JS, CSS, and HTML files
|
||||
if (!url.match(/\.(js|css|html?)$/)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const gzPath = path.join(distPath, url + ".gz");
|
||||
|
||||
if (fs.existsSync(gzPath)) {
|
||||
// Set headers for gzip response
|
||||
res.setHeader("Content-Encoding", "gzip");
|
||||
res.setHeader("Vary", "Accept-Encoding");
|
||||
|
||||
// Set correct content type
|
||||
if (url.endsWith(".js")) {
|
||||
res.setHeader("Content-Type", "application/javascript; charset=UTF-8");
|
||||
} else if (url.endsWith(".css")) {
|
||||
res.setHeader("Content-Type", "text/css; charset=UTF-8");
|
||||
} else if (url.match(/\.html?$/)) {
|
||||
res.setHeader("Content-Type", "text/html; charset=UTF-8");
|
||||
}
|
||||
// Compress JS, CSS, JSON, HTML
|
||||
const contentType = res.getHeader('content-type') || '';
|
||||
if (typeof contentType === 'string') {
|
||||
if (contentType.includes('javascript') ||
|
||||
contentType.includes('css') ||
|
||||
contentType.includes('json') ||
|
||||
contentType.includes('html')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return compression.filter(req, res);
|
||||
},
|
||||
}));
|
||||
|
||||
// Serve the gzipped file
|
||||
return res.sendFile(gzPath);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
// Serve static files with proper caching
|
||||
app.use(express.static(distPath, {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import tailwindcss from "@tailwindcss/vite";
|
|||
import path from "path";
|
||||
import runtimeErrorOverlay from "@replit/vite-plugin-runtime-error-modal";
|
||||
import { metaImagesPlugin } from "./vite-plugin-meta-images";
|
||||
import { compression } from "vite-plugin-compression2";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
|
|
@ -11,6 +12,14 @@ export default defineConfig({
|
|||
runtimeErrorOverlay(),
|
||||
tailwindcss(),
|
||||
metaImagesPlugin(),
|
||||
compression({
|
||||
algorithm: "gzip",
|
||||
exclude: [/\.(br)$/, /\.(gz)$/],
|
||||
threshold: 1024,
|
||||
compressionOptions: {
|
||||
level: 6,
|
||||
},
|
||||
}),
|
||||
...(process.env.NODE_ENV !== "production" &&
|
||||
process.env.REPL_ID !== undefined
|
||||
? [
|
||||
|
|
|
|||
Loading…
Reference in New Issue