CI/CD Avançado para Projetos JavaScript com GitHub Actions
A automação de build, teste e implantação (CI/CD) é uma parte essencial do desenvolvimento moderno em JavaScript. Se você já domina os pipelines básicos do GitHub Actions, é hora de passar para o próximo nível. Neste artigo, abordaremos técnicas avançadas: cache de dependências, builds matriciais, execução paralela de tarefas, trabalho seguro com segredos e deploy automático em VPS e Docker. Todos os exemplos são voltados para projetos Node.js.
1. Otimização do tempo de build: cache e execuções condicionais
Um dos principais problemas dos pipelines básicos é a longa instalação de node_modules a cada execução. O GitHub Actions permite armazenar dependências em cache, reduzindo o tempo de execução em 2 a 4 vezes.
Use a action actions/cache para armazenar em cache node_modules ou ~/.npm:
name: CI Pipelineon: [push, pull_request]
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20'
- name: Cache node_modules uses: actions/cache@v3 id: npm-cache with: path: node_modules key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} restore-keys: | ${{ runner.os }}-node-
- name: Install dependencies if: steps.npm-cache.outputs.cache-hit != 'true' run: npm ciDicas avançadas:
- Use
hashFiles('package-lock.json')para invalidar o cache com precisão quando as dependências mudarem. - Para monorepositórios, armazene em cache cada pacote separadamente com
path: packages/*/node_modules. - Adicione execuções condicionais (
if: github.ref == 'refs/heads/main') para que tarefas pesadas (como build da versão de produção) sejam executadas apenas em pushes para a branch main.
2. Builds matriciais e tarefas paralelas
A estratégia de matriz permite executar o mesmo workflow com parâmetros diferentes. Isso é indispensável para testar em várias versões do Node.js ou sistemas operacionais.
jobs: test: strategy: matrix: node-version: [18, 20, 22] os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm ci - run: npm testPara execução paralela de tarefas independentes (como lint, testes unitários, testes de integração), use jobs separados. Eles são executados simultaneamente e não bloqueiam uns aos outros:
jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npm run lint
unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npm run test:unit
integration-tests: needs: [lint, unit-tests] # aguarda a conclusão de lint e unit runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npm run test:integrationImportante: Use needs para definir a ordem de execução de tarefas dependentes. Isso economiza tempo e recursos.
3. Deploy avançado: Docker e VPS usando artefatos
Após o teste bem-sucedido, é necessário implantar a aplicação. Vamos considerar dois cenários populares: deploy em imagem Docker e em VPS.
3.1. Build e publicação de imagem Docker
jobs: build-and-push: needs: [test] runs-on: ub