04 — Ambientes e configuração
04 — Ambientes e configuração
Como o projeto descobre em runtime a qual backend falar. Dois mecanismos distintos:
config/{env}.json(por ambiente, versionado) e.env(por máquina, local). Não os confunda. Regra de ouro:public/config.jsoné gerado, nunca editado à mão, nunca versionado.
O fluxo
config/{env}.json ──[setEnvironment.js]──▶ public/config.json ──[fetch em runtime]──▶ SessionManager
▲
│
.env (override)
-
npm run devexecutanpm run env:devantes do Vite. -
setEnvironment.js devlêconfig/dev.json, aplica overrides do.enve escrevepublic/config.json. - Em runtime,
getSessionManager()fazfetch("./config.json")e constrói o transporte.
Por que em runtime e não em build: permite apontar o mesmo bundle para outro servidor trocando um arquivo, sem recompilar. É o que viabiliza o deploy ISAPI — ver 15.
config/{env}.json
Um arquivo por ambiente. Versionados.
// config/dev.json
{
"service": {
"url": "https://srvd1.dev.exemplo.com.br/cxClient/cxIsapiClient.dll/gatewayJSONBalanced?version=4",
"server": "192.168.0.00",
"system": "61",
"port": "5369"
},
"accessToken": "SUBSTITUA",
"resources": {
"get": "https://srvd1.dev.exemplo.com.br/cxClient/cxIsapiClient.dll/getpr",
"put": "https://srvd1.dev.exemplo.com.br/cxClient/cxIsapiClient.dll/putpr",
"viewer": "https://srvd1.dev.exemplo.com.br/relatorios/viewer/rel.html?id="
},
"logs": true
}
Chaves
| Chave | Tipo | O que é |
|---|---|---|
service.url |
string |
Endpoint do gateway Curio. Inclui ?version=4
|
service.server |
string |
IP/host do servidor de aplicação de destino |
service.system |
string |
Identificador numérico do sistema no Curio |
service.port |
string |
Porta do servidor de aplicação |
accessToken |
string |
Token de acesso ao gateway |
resources.get |
string |
Endpoint de download de recurso/arquivo |
resources.put |
string |
Endpoint de upload |
resources.viewer |
string |
URL base do visualizador de relatórios; recebe o id concatenado |
logs |
boolean |
Liga logs verbosos do transporte |
O tipo é declarado em src/lib/curio/index.ts:
// src/lib/curio/index.ts
export interface Config {
service: { url: string; server: string; system: number; port: number };
accessToken: string;
resources: { get: string; put: string; viewer: string };
logs: boolean;
}
Cuidado com mentira de tipo. Se o JSON trouxer
systemeportcomo string mas a interfaceConfigdeclarar number, o TypeScript não acusa nada — o JSON é lido viafetch, sem checagem de tipo em runtime, e o Curio aceita ambos os formatos. Ainda assim é uma mentira de tipo. Declare a interface fiel ao que o JSON realmente contém (system: string; port: string, se for o caso) em vez de forçar um tipo que não corresponde ao dado real.
setEnvironment.js
#!/bin/node
// setEnvironment.js — copia config/{env}.json para public/config.json
import fs from "fs";
import path from "path";
const environment = process.argv[2];
if (!environment) {
console.error("Por favor, especifique um ambiente: dev, homolog ou prod");
process.exit(1);
}
// .env so eh lido se Node >= 20.6 e arquivo existe
if (typeof process.loadEnvFile === "function" && fs.existsSync(".env")) {
process.loadEnvFile(".env");
}
try {
const envFileContent = JSON.parse(fs.readFileSync(`./config/${environment}.json`, "utf8"));
// override so vale em dev — prod nunca le .env
if (environment === "dev") {
if (process.env.LOCAL_SERVER) {
envFileContent.service.server = process.env.LOCAL_SERVER;
console.log(`service.server sobrescrito via LOCAL_SERVER: ${process.env.LOCAL_SERVER}`);
}
if (process.env.ACCESS_TOKEN) {
envFileContent.accessToken = process.env.ACCESS_TOKEN;
console.log("accessToken sobrescrito via ACCESS_TOKEN");
}
}
console.log(`Configurando ambiente: ${environment}`);
const publicDir = path.join(process.cwd(), "public");
if (!fs.existsSync(publicDir)) fs.mkdirSync(publicDir, { recursive: true });
fs.writeFileSync(path.join(publicDir, "config.json"), JSON.stringify(envFileContent, undefined, 2));
console.log(`Ambiente ${environment} configurado com sucesso!`);
} catch (error) {
console.error(`Erro ao configurar ambiente ${environment}:`, error.message);
process.exit(1);
}
Nunca logue o valor do
ACCESS_TOKENno console. Token não vai para stdout. O snippet acima já evita isso.
.env — variáveis por máquina
Serve para o dev apontar o ambiente dev ao seu servidor local sem sujar o config/dev.json
compartilhado.
# .env.example — copie para .env e ajuste. .env nao eh versionado.
# Sobrescreve service.server no config gerado (so em dev)
LOCAL_SERVER="ENDERECO_DO_SERVIDOR_LOCAL"
# Sobrescreve accessToken (so em dev)
ACCESS_TOKEN="TOKEN_DE_ACESSO"
Regras:
-
.env.exampleé versionado e contém apenas placeholders. -
.envé gitignored. - Overrides só se aplicam ao ambiente
dev.homologeprodignoram o.envpor construção — isso é proposital, para que um.envesquecido não vaze para um build de produção. - Não use
import.meta.env/ prefixoVITE_para configuração de backend. Isso embute o valor no bundle em tempo de build e derrota o propósito doconfig.json.import.meta.env.DEV(flag de modo) é aceitável.
Adicionar um ambiente novo
- Crie
config/{nome}.jsoncom todas as chaves. - Adicione ao
package.json:"env:{nome}": "node ./setEnvironment.js {nome}", "start:{nome}": "npm run env:{nome} && vite" - Se o ambiente tiver build próprio, adicione
"build:{nome}".
Segurança
-
public/config.jsonno.gitignore. É gerado; versioná-lo cria conflito toda vez que alguém troca de ambiente. -
config/*.jsoné servido ao browser. Tudo ali é público para quem abrir o DevTools. Não coloque segredo que não possa ser lido pelo usuário final. -
accessTokenemconfig/dev.jsonfica no histórico do Git para sempre. Nunca commite um token real nesse arquivo. Commite"accessToken": "SUBSTITUA"e distribua o valor real via.env(dev) ou via substituição no pipeline (homolog/prod).