Durante o processo de desenvolvimento de aplicações web com React, é gasto um bom tempo configurando ESLint, Prettier, lint-staged e husky, o que acaba sendo muito custoso e repetitivo. De forma a agilizar isso, nesse artigo busco apresentar como utilizando os snippeets do GitLab é possível automatizar isso.
De acordo com a documentação do GitLab:
Com os snippets do GitLab, você pode armazenar e compartilhar trechos de código e texto com outros usuários. É possível comentar, clonar e utilizar controle de versão em snippets. Eles podem conter vários arquivos. Além disso, suportam realce de sintaxe, incorporação, download, e você pode gerenciar seus snippets com a API de snippets
Como o snippets podem ser clonados, é possível clonar trechos de códigos e arquivos para dentro de seu projeto. Utilizando essa funcionalidade, podemos dividir partes das configurações iniciais do projeto em alguns snippets e depois clonar por partes dentro do nosso projeto. Além disso, vamos criar um script em bash para criar o projeto React com vite e clonar os snippets dentro do nosso projeto.
Criando os snippets
Neste artigo, abordaremos os seguintes snippets: start react project, react project configs, language config e react resets config. Cada snippet possui uma função específica, o que é necessário devido à limitação de 10 arquivos por snippet. Essa separação também facilitará a criação do script bash
. A seguir, explico a função de cada um:
- start react project: esse é o snippet principal, a ideia dele é que o usuário possa fazer clone nele e executar o script bash;
- react project configs: esse arquivos contém os arquivos de configuração geral da aplicação React.
- language config: esse snippet contém os arquivos de configuração de internacionalização utilizando a biblioteca react-intl;
- react reset config: ao iniciar um projeto React, o vite gera alguns arquivos de exemplo que geralmente acabamos deletando. O objetivo deste snippet é fornecer um projeto “limpo” para evitar esse retrabalho.
React project configs
Os arquivos que estão presentes nesse snippet são os arquivos de configurações do projeto que ficam normalmente na raiz do projeto. São eles:
-
.env.development
: arquivo de variáveis de ambiente para o modo de desenvolvimento; -
.env.production
: arquivo de variáveis de ambiente para o modo de produção; -
.eslintrc.yml
: arquivo de configuração do ESLint. A nova versão 9 do ESLint tem usado um arquivo.js
para essas configurações, no entanto, nem todas as bibliotecas de linting que nós utilizamos tinha suporte a versão 9, portanto, estamos utilizando a versão 8 que permite usar YAML; -
.prettierrc.yml
: arquivo de configuração de formatação do Prettier; -
gitlab-ci.yml
: arquivo de configuração de CI/CD do GitLab; -
Dockerfile
: arquivo de instruções para gerar uma imagem Docker do projeto React; -
nginx/default.conf.template
: arquivo de configuração default para iniciar um servidor NGINX. Estamos utilizando a extensão .template, pois, com ela é possível utilizar variáveis de ambiente. Essa feature foi introduzida na versão 25 do NGINX; -
nginx/nginx.conf
: arquivo de configuração do NGINX que inclui as configurações default donginx/default.conf.template
; -
tsconfig.app.json
: arquivo de configuração do TypeScript, configurado para habilitar o uso de aliases dentro da aplicação. O alias que utilizamos é o@
que faz referência ao diretóriosrc
; -
vite.config.ts
: e por fim, o arquivo de configuração do vite, que além de habilitar e resolver os aliases na hora de empacotar, ele está configurado para utilizar o import de SVG como componentes utilizando o pluginvite-plugin-svgr
.
É importante notar que os arquivos que iniciam com nginx/
quando forem clonados via Git serão adicionados a mesma pasta nginx/
.
React reset config
Como dito anteriormente, quando um projeto React é criado, por padrão, vem bastante código “poluído” de template. Normalmente, umas das primeiras fases do desenvolvimento do projeto é remover esse código template e organizar os arquivos App.tsx
e o main.tsx
. Para isso, utilizamos os seguintes arquivos:
-
app.tsx
: componente principal da aplicação React;
export const App = () => {
return <div></div>
}
-
main.tsx
: componente que renderiza todo o projeto;
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { App } from './app'
const container = document.querySelector('#root')!
const root = createRoot(container)
root.render(
<StrictMode>
<App />
</StrictMode>
)
-
env.d.ts
: arquivo de configuração de definição das variáveis de ambiente para serem expostas aoimport.meta
.
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string
readonly VITE_APP_VERSION: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
Language config
Alguns projetos que desenvolvemos possuem como requisito ter dois idiomas: espanhol e português. Dessa forma, para manter um padrão, foi criado um snippet só com os arquivos necessário para agregar esse requisito nas nossas aplicações. Os arquivos desse snippet são:
-
translations/es-PY.json
: arquivo JSON com todas as labels em espanhol; -
translations/pt-BR.json
: arquivo JSON com todas as labels em português; -
utils/lang.ts
: arquivo com a função para pegar o idioma preferido do usuário; -
types/lang.ts
: arquivo contendo os tipos e interfaces necessárias para a aplicação; -
translations/index.tsx
: arquivo que exporta o objeto de messages utilizados pelo provider doreact-intl
, contendo as labels em português e espanhol. -
hooks/lang.ts
: arquivo que exporta o hookuserUserLanguage
; -
app.tsx
: neste caso, o arquivoapp.tsx
contém o provider doreact-intl
utilizando as messages do arquivotranslations/index.tsx
;
No futuro, pretendo criar uma artigo explicando desde o começo como
aplicamos internacionalização nas aplicações React que desenvolvemos.
Start react project
E por fim, esse é o principal snippet desse artigo. Ele contém somente dois arquivos, um README.md
, explicando como utiliza-lo, e o arquivo bash
para criar o projeto React. O script é divido em várias funções, irie apresentar uma por vez neste artigo.
#!/bin/bash
initial_branch="main"
remote_address=""
project_name=""
template=""
parse_params(){
while getopts ":b:r:n:t:" opt; do
case ${opt} in
b )
initial_branch=$OPTARG
;;
r )
remote_address=$OPTARG
;;
n )
project_name=$OPTARG
;;
t )
template=$OPTARG
;;
\? )
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
: )
echo "Invalid option: -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
shift $((OPTIND -1))
if [ -z "$project_name" ]; then
echo "Error: Project name is required." >&2
exit 1
fi
}
O script aceita 4 parâmetros para ser executado:
n
: nome do projeto React a ser criado (Obrigatório);
b
: nome da branch inicial (Opcional);
r
: endereço do repositório remoto (Opcional);
t
: template que utilizamos, neste caso, um deles é o i18n
, para sistemas internacionalizados (Opcional);
start_vite_project(){
echo "Starting Vite project with React TS template..."
npm create vite@latest "$project_name" -- --template react-ts --silent
cd "$project_name" || { echo "Failed to change directory to $project_name"; exit 1; }
}
A função acima é responsável por inicializar um projeto utilizando a ferramenta vite, passando como nome do projeto, o nome informado como parâmetro. Após isso, é realizado um comando cd
para entrar dentro do diretório do projeto.
install_dependencies(){
echo "Installing dependencies..."
npm install --silent
npm i -D eslint@8.53.0 --silent
npm i -D prettier --silent
npm i -D husky --silent
npm i -D lint-staged --silent
npm i -D vite-plugin-svgr
npm i -D @types/node
npx husky init --silent
npm i -D @typescript-eslint/eslint-plugin --silent
npm i -D @typescript-eslint/parser --silent
npm i -D eslint-config-prettier --silent
npm i -D eslint-import-resolver-typescript --silent
npm i -D eslint-plugin-import --silent
npm i -D eslint-plugin-react --silent
npm i -D eslint-plugin-react-hooks --silent
npm i -D eslint-plugin-react-refresh --silent
npm i -D eslint-plugin-sonarjs --silent
npm i -D eslint-plugin-unicorn --silent
npm i -D eslint-plugin-unused-imports --silent
npm i -D eslint-plugin-prettier@latest --silent
}
A função install_dependencies
instala todas as dependências adicionadas pelo vite as dependências esperadas pelo arquivo de configuração do ESLint e Prettier. Além disso, também é instalado e iniciado o Husky para adicionar rotinas de pré commit para o projeto.
set_scripts(){
echo "Configuring formatting, type checking, and linting scripts..."
npm pkg set scripts.lint="eslint \"src/**/*.{ts,tsx}\" --quiet"
npm pkg set scripts.lint:fix="eslint \"src/**/*.{ts,tsx}\" --quiet --fix"
npm pkg set scripts.type:check="tsc --noEmit"
npm pkg set scripts.format="prettier --write \"src/**/*.{ts,tsx}\""
npm pkg set scripts.prepare="husky install"
}
De modo a facilitar o uso do ESLint e do Prettier, criamos alguns scripts para realizar linting e formatação do código. Além disso, ao refatorar código, nem sempre a IDE mostra todo os erros de tipo no código, portanto, criamos um script para verificar os tipos.
-
lint
: realiza as verificações de linting baseado na configuração do.eslintrc.yml
; -
lint:fix
: realiza as verificações e corrige os erros de linting; -
type:check
: executa a verificação de tipos sem gerar o código compilado;format
: formata todo o código baseado nas configurações definidas em.prettierrc.yml
.
set_lint_stage(){
npm pkg set lint-staged='{"./src/**/*.{ts,tsx}": ["npm run format", "npm run lint:fix"]}' --json
npm pkg set husky='{"hooks": {"pre-commit": "lint-staged"}}' --json
echo -n "" > ./.husky/pre-commit
echo "npx lint-staged && npm run type:check" >> ./.husky/pre-commit
}
Essa função configura os Git hooks criados pelo Husky e utilizando o lint-staged
. Neste caso, estamos utilizando somente um hook que é para ser executado antes de realizar o commit.
import_default_templates(){
echo "Importing default templates..."
rm -rf src/*
rm -rf vite.config.ts
rm -rf tsconfig.app.json
git clone https://gitlab.com/snippets/156.git ./src/ --quiet
git clone https://gitlab.com/snippets/154.git ./temp --quiet
mv ./temp/nginx . || exit
mv ./temp/.eslintrc.yml . || exit
mv ./temp/.prettierrc.yml . || exit
mv ./temp/.gitlab-ci.yml . || exit
mv ./temp/.env.development . || exit
mv ./temp/.env.production . || exit
mv ./temp/Dockerfile . || exit
mv ./temp/tsconfig.app.json . || exit
mv ./temp/vite.config.ts . || exit
rm -rf eslint.config.js
rm -rf temp
rm -rf src/.git
}
Nesta função são importados os templates padrão das aplicações React. Após criar um snippet, no lado superior direito, há um botão clone que mostra a URL para fazer o clone do snippet. Cada snippet possui um ID sequência e é clonado com base nisso. Os snippets react reset config e react project config representam os IDs 154 e 156, respectivamente.
O primeiro passo é remover todo o contéudo do diretório src
, o arquivo de configuração do vite e o do TypeScript. Após isso, são clonados os snippets, um deles dentro do src
(react reset config) e outro dentro de uma pasta temporária temp
. Como não é possível fazer clone em um diretório com conteúdo, fazemos o clone em um pasta vazia e depois movemos para seus respectivos lugares. Todos os arquivos do diretório temp
são movidos para a raiz do projeto. Por fim, é excluído a pasta temp
e a pasta .git
criado dentro de src
, criada ao executar o clone do snippet.
import_i18n_template(){
echo "Importing i18n template..."
npm i react-intl --quiet
npm i react-hook-form --quiet
npm i jotai --quiet
npm i flat --quiet
git clone https://gitlab.com/snippets/155.git ./temp --quiet
rm -rf ./src/app.tsx
mv ./temp/* ./src/ || exit
rm -rf ./temp
}
import_templates(){
if [ "$template" = "i18n" ]; then
import_i18n_template
fi
}
Caso o usuário tenha informado o parâmetro de template, esta função é responsável por importar os templates dentro do projeto. Neste caso, existe somente um template i18n
. Novamente, como não podemos fazer o clone em um repositório não vazio, é necessário utilizar uma pasta temp
.
start_git_repository(){
echo "Initializing Git repository..."
git init --initial-branch="$initial_branch"
npm run prepare --silent
git add .
echo "Making initial commit..."
git commit -m "feat: initial commit"
if [ -n "$remote_address" ]; then
echo "Adding remote repository..."
git remote add origin "$remote_address"
echo "Pushing initial commit..."
git push origin "$initial_branch"
fi
}
O script bash
também inicializa um repositório Git e inicializando as rotinas de pré-commit definidas pelo Husky. Além disso, o script também realiza o commit inicial e, se for informado um repositório remoto, a função irá adiciona-lo como origin na lista de repositórios remotos e realizar push para aquele repositório remoto na branch inicial.
run(){
parse_params "$@"
start_vite_project
install_dependencies
set_scripts
set_lint_stage
import_default_templates
if [ -n "$template" ]; then
import_templates
fi
start_git_repository
echo "Project setup completed successfully!"
}
run "$@"
Por último, mas não menos importante, a função run
é responsável por chamar todas as funções apresentadas acima na ordem correta. Caso tenha sido informado um template, ela irá importá-lo também. Em Bash, $@
é uma variável especial que representa todos os argumentos passados para um script ou função, como uma lista separada por espaços. Cada argumento é tratado como uma string
individual.
Executando o script
Antes de executar o script, é necessário dar permissão para executa-lo. Para usuários de Linux, basta executar o seguinte comando.
$ chmod +x start-react-project.sh
Após torna-lo executável, rode o seguinte comando:
$ ./start-react-project.sh -n <NOME_DO_PROJETO> -b <BRANCH_INICIAL> -r <REPO_REMOTO> -t <TEMPLATE>
A execução do script pode demorar alguns segundos até instalar todas as bibliotecas e fazer clones de todos os snippets. Neste artigo, irie considerar o template i18n
. A estrutura do projeto será a seguinte:
./
├── nginx/
│ ├── default.conf.template
│ └── nginx.conf
├── node_modules/
├── public/
│ └── vite.svg
├── src/
│ ├── hooks/
│ │ └── lang.ts
│ ├── translations/
│ │ ├── es-PY.json
│ │ ├── index.ts
│ │ └── pt-BR.json
│ ├── types/
│ │ └── lang.ts
│ ├── utils/
│ │ └── lang.ts
│ ├── app.tsx
│ ├── env.d.ts
│ ├── main.tsx
│ └── vite-env.d.ts
├── Dockerfile
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
Conclusão
Neste artigo busquei mostrar um pouco de como, utilizando uma ferramenta simples, é possível criar automações para facilitar no desenvolvimento de aplicações. Espero que tenham gostado desse artigo, este é o meu primeiro artigo aqui no dev.to, espero que seja o primeiro de muitos. Muito obrigado pela atenção!
Top comments (0)