15 — Build e deploy
15 — Build e deploy
Builds por ambiente, o artefato gerado e como ele é servido atrás do ISAPI. A escolha de ambiente acontece em build (qual
config.jsoné embarcado) e pode ser trocada em deploy (substituindo o arquivo) — sem recompilar. Não há pipeline de CI na referência. Isso é lacuna, não decisão.
Scripts
| Comando | O que faz |
|---|---|
npm run dev |
env:dev + Vite dev server (porta 5000) |
npm run start:homolog |
env:homolog + dev server apontando para homologação |
npm run build |
lint → env:prod → tsc → vite build
|
npm run build:homolog |
env:homolog → tsc → vite build
|
npm run preview |
Serve o dist/ localmente |
O build de produção inclui o lint
"build": "npm run lint && npm run env:prod && tsc && vite build"
Quatro etapas, sequenciais, qualquer falha aborta:
-
lint— ESLint com zero warnings -
env:prod— gerapublic/config.jsona partir deconfig/prod.json -
tsc— type-check completo (noEmit) -
vite build— bundle emdist/
build:homolognão roda o lint. É inconsistente com obuild. No projeto novo, inclua o lint nos dois:"build:homolog": "npm run lint && npm run env:homolog && tsc && vite build".
Por que tsc além do vite-plugin-checker
O checker do dev só verifica o que foi tocado na sessão. tsc verifica o projeto inteiro. Um erro de
tipo num arquivo que ninguém abriu passa pelo checker e é pego aqui.
O artefato
dist/
├── index.html
├── config.json ← copiado de public/, define o backend
└── assets/
├── index-<hash>.js
├── index-<hash>.css
└── <Pagina>-<hash>.js ← um chunk por página (lazy)
build: { outDir: "dist", sourcemap: true }
sourcemap: true publica os .map junto do bundle — qualquer um com acesso à URL lê o código-fonte
original. Aceitável em sistema interno; desligue se o app for exposto na internet.
Trocar de ambiente sem rebuild
Como o config.json é lido em runtime (fetch("./config.json") — ver 04),
o mesmo dist/ serve qualquer ambiente:
# aponta um build existente para outro backend
cp config/homolog.json dist/config.json
Isso viabiliza promover exatamente o artefato testado em homologação para produção, sem recompilar.
Consequência: o config.json do build não é a verdade final. Confirme o que está no servidor,
não o que foi buildado.
Deploy ISAPI
O backend Curio é servido por cxIsapiClient.dll sob IIS. O front é um SPA estático publicado no
mesmo IIS, normalmente num diretório virtual ao lado do gateway.
Passos:
-
npm run build(oubuild:homolog) - Copiar o conteúdo de
dist/para o diretório publicado no IIS - Ajustar
dist/config.jsonse o destino diferir do ambiente do build - Validar: abrir a aplicação, fazer login, executar uma tela que chame o backend
Rewrite para SPA
O React Router usa BrowserRouter (history API). Uma URL profunda como
/cadastro/fornecedor/incluir chega ao IIS como um caminho que não existe em disco — e retorna 404.
O IIS precisa de uma regra de rewrite que devolva index.html para qualquer caminho que não seja
arquivo real:
<!-- web.config no diretório publicado -->
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="SPA fallback" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Sintoma de rewrite ausente: a aplicação funciona navegando pelo menu, mas F5 numa tela interna dá 404.
É comum uma implementação de referência não versionar um
web.config. Se o projeto novo for publicado em IIS, versione-o junto do código — configuração de servidor não deve viver só na memória de quem publica.
base do Vite
Se a aplicação for servida em subcaminho (https://servidor/sistema/ em vez da raiz), configure:
// vite.config.ts
export default defineConfig({ base: "/sistema/" });
Sem isso, os assets/ são requisitados da raiz e não carregam. A referência assume publicação na raiz
(base não é definido).
CI/CD — o que existe e o que falta
É comum encontrar .gitlab/ na raiz só com templates de issue e merge request:
.gitlab/
├── issue_templates/default.md
└── merge_request_templates/default.md
Sem .gitlab-ci.yml, não há pipeline. Se o template de MR pede "Pipeline passando" e "Testes
escritos ou atualizados" sem que o projeto tenha como cumprir nenhum dos dois, é checklist
aspiracional — alinhe o texto ao que existe de verdade.
Recomendação para o projeto novo
Um pipeline mínimo cobre o que hoje depende de disciplina individual:
# .gitlab-ci.yml
image: node:22
stages: [verify, build]
cache:
key: "$CI_COMMIT_REF_SLUG"
paths: [node_modules/]
verify:
stage: verify
script:
- npm ci
- npm run lint
- npx tsc --noEmit
- npm run format:check
build:
stage: build
script:
- npm ci
- npm run build
artifacts:
paths: [dist/]
expire_in: 1 week
Ajuste os caminhos se o projeto web for submódulo de um monorepo (cd caminho/do/modulo antes dos comandos).
Se adotar CI, alinhe o checklist do template de MR ao que o pipeline realmente verifica. Checklist que pede o que não existe treina o time a marcar caixas sem ler.
No Comments