melhorias de performance
This commit is contained in:
1 parent
ce851b9cf9
commit
63d5cbebe7
4 files changed
+59
-19
No files matched your search
@@ -20,12 +20,17 @@ const app = Fastify({ logger: true, trustProxy: true });
|
||||
|
||||
await app.register(cors, { origin: true });
|
||||
|
||||
// Cache-Control é decidido no nginx interno (ver nginx/nginx.conf,
|
||||
// location /models/), não aqui — "immutable"/maxAge nesse nível conflitava
|
||||
// com o "no-cache" que o nginx adiciona por cima (dois headers
|
||||
// Cache-Control na mesma resposta, comportamento indefinido entre
|
||||
// navegadores), e ia contra o motivo do "no-cache": os .glb têm nome fixo
|
||||
// mas o CONTEÚDO muda toda vez que o pipeline roda de novo.
|
||||
await app.register(fastifyStatic, {
|
||||
root: MODELS_DIR,
|
||||
prefix: "/models/",
|
||||
decorateReply: false,
|
||||
immutable: true,
|
||||
maxAge: "7d",
|
||||
etag: true,
|
||||
});
|
||||
|
||||
app.get("/api/health", async () => ({ status: "ok" }));
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
// - data-pipeline/seed/manifest-real.json (entradas para o seed do banco)
|
||||
import { NodeIO } from "@gltf-transform/core";
|
||||
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
|
||||
import { prune, dedup, weld, simplify } from "@gltf-transform/functions";
|
||||
import { MeshoptSimplifier } from "meshoptimizer";
|
||||
import { prune, dedup, weld, simplify, meshopt } from "@gltf-transform/functions";
|
||||
import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
|
||||
import { writeFileSync, mkdirSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -21,6 +21,7 @@ import { MUSCLE_DESCRIPTIONS } from "./muscle-descriptions.mjs";
|
||||
import { NERVE_DESCRIPTIONS } from "./nerve-descriptions.mjs";
|
||||
|
||||
await MeshoptSimplifier.ready;
|
||||
await MeshoptEncoder.ready;
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const CONVERTED_DIR = path.resolve(__dirname, "../converted");
|
||||
@@ -183,7 +184,12 @@ function classifySystem(key, rawName) {
|
||||
return RESPIRATORY_KEYWORDS.some((kw) => lower.includes(kw)) ? "respiratorio" : "visceral";
|
||||
}
|
||||
|
||||
const io = new NodeIO().registerExtensions(ALL_EXTENSIONS);
|
||||
// registerDependencies com a chave "meshopt.encoder" é o que permite ao
|
||||
// io.write() de fato aplicar a compressão EXT_meshopt_compression pedida
|
||||
// no transform() abaixo — sem isso, ela seria ignorada silenciosamente.
|
||||
const io = new NodeIO()
|
||||
.registerExtensions(ALL_EXTENSIONS)
|
||||
.registerDependencies({ "meshopt.encoder": MeshoptEncoder });
|
||||
const manifest = [];
|
||||
let totalStructures = 0;
|
||||
|
||||
@@ -349,6 +355,12 @@ for (const { fbx, key } of SOURCES) {
|
||||
simplify({ simplifier: MeshoptSimplifier, ratio: 0.5, error: 0.01 }),
|
||||
prune(),
|
||||
dedup(),
|
||||
// Comprime os atributos de vértice (posição/normal/UV) com o mesmo
|
||||
// codec Meshopt já usado pra simplificação — reduz bastante o tamanho
|
||||
// do .glb final (os floats crus de posição/normal dominam o arquivo),
|
||||
// e o carregamento no navegador não precisa de nada extra: o useGLTF
|
||||
// do drei já vem com o decoder Meshopt ligado por padrão.
|
||||
meshopt({ encoder: MeshoptEncoder, level: "medium" }),
|
||||
);
|
||||
|
||||
const outPath = path.join(MODELS_OUT_DIR, target.modelFile);
|
||||
|
||||
+22
-14
@@ -1,22 +1,30 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { Route, Routes } from "react-router-dom";
|
||||
import { Layout } from "./components/Layout.js";
|
||||
|
||||
// A página inicial (Atlas) já carrega o peso pesado de verdade (three.js +
|
||||
// r3f + drei) — separar as OUTRAS rotas em chunks à parte só evita que
|
||||
// quem abre o atlas baixe/parseie de graça o código do Quiz, de Planos e
|
||||
// do painel interno de estatísticas antes mesmo de ver o modelo 3D.
|
||||
import AtlasPage from "./routes/AtlasPage.js";
|
||||
import PlanesPage from "./routes/PlanesPage.js";
|
||||
import QuizPage from "./routes/QuizPage.js";
|
||||
import PhysicalExamPage from "./routes/PhysicalExamPage.js";
|
||||
import AdminStatsPage from "./routes/AdminStatsPage.js";
|
||||
const PlanesPage = lazy(() => import("./routes/PlanesPage.js"));
|
||||
const PhysicalExamPage = lazy(() => import("./routes/PhysicalExamPage.js"));
|
||||
const QuizPage = lazy(() => import("./routes/QuizPage.js"));
|
||||
const AdminStatsPage = lazy(() => import("./routes/AdminStatsPage.js"));
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route element={<Layout />}>
|
||||
<Route path="/" element={<AtlasPage />} />
|
||||
<Route path="/planos-anatomicos" element={<PlanesPage />} />
|
||||
<Route path="/exame-fisico" element={<PhysicalExamPage />} />
|
||||
<Route path="/quiz" element={<QuizPage />} />
|
||||
</Route>
|
||||
{/* Fora do Layout: painel interno, sem o menu/nav do atlas. */}
|
||||
<Route path="/estatisticas" element={<AdminStatsPage />} />
|
||||
</Routes>
|
||||
<Suspense fallback={null}>
|
||||
<Routes>
|
||||
<Route element={<Layout />}>
|
||||
<Route path="/" element={<AtlasPage />} />
|
||||
<Route path="/planos-anatomicos" element={<PlanesPage />} />
|
||||
<Route path="/exame-fisico" element={<PhysicalExamPage />} />
|
||||
<Route path="/quiz" element={<QuizPage />} />
|
||||
</Route>
|
||||
{/* Fora do Layout: painel interno, sem o menu/nav do atlas. */}
|
||||
<Route path="/estatisticas" element={<AdminStatsPage />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
@@ -11,6 +11,13 @@ http {
|
||||
keepalive_timeout 65;
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/javascript application/json application/wasm model/gltf-binary;
|
||||
# Sem isso, o default do nginx (gzip_proxied off) desliga a compressão
|
||||
# justamente nas respostas que passam por proxy_pass (/api/ e /models/,
|
||||
# que são as maiores — JSON de estruturas e os .glb) — só os arquivos
|
||||
# estáticos servidos direto por este nginx (JS/CSS do build) estavam
|
||||
# sendo comprimidos até agora.
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
|
||||
# Respect a proxy in front of this container (the user's own reverse proxy).
|
||||
set_real_ip_from 0.0.0.0/0;
|
||||
@@ -72,6 +79,14 @@ http {
|
||||
add_header Cache-Control "no-cache";
|
||||
}
|
||||
|
||||
# Bundle do Vite (JS/CSS/fonts) tem hash de conteúdo no nome do arquivo
|
||||
# — ao contrário dos .glb, um arquivo com esse nome NUNCA muda de
|
||||
# conteúdo (um build novo gera nomes novos), então pode cachear "pra
|
||||
# sempre" sem risco de servir algo desatualizado.
|
||||
location /assets/ {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
}
|
||||
|
||||
# SPA fallback.
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
|
||||
Reference in new issue
Block a user