Configurando React com Typescript sem CRA
Davi Firmino
Posted on October 26, 2020
Escrevo esse post pois não é fácil encontrar algum material que explique de forma eficiente como se montar um boilerplate com react e typescript sem o CRA (Create-React-App).
Embora a grande maioria dos casos o cra atenda perfeitamente, pode existir um determinado caso que em função da sua arquitetura você queira fazer um setup manual.
O cra é muito útil e longe de mim querer criticá-lo porém ele pode deixar sua arquitetura um pouco engessada.
Esse post irá explicar de forma detalhada cada passo do projeto, caso você não queira ler pule para o final do arquivo com o link do repositório.
Padrões
Antes de começarmos de fato, vamos definir alguns padrões para que o projeto não vire a casa da mãe joanna.
Para os commits utilizaremos o conventional commits
Começando
Primeiro vamos criar a nossa pasta para iniciar o projeto
mkdir boilerplate && cd boilerplate
Agora vamos iniciar o package.json
npm init -y
Vamos iniciar o git
git init
Vamos adicionar um biblioteca para ajudar a gente a manter o padrão das mensagens de commit.
git-commit-msg-linter
npm i -D git-commit-msg-linter
Vamos agora criar o .gitignore
echo "node_modules\ncoverage\npublic/js" > .gitignore
Vamos instalar o typescript
npm i -D typescript
Agora o types do node (para garantir a tipagem do node)
npm i -D @types/node
Vamos agora criar o arquivo de configuração do typescript
touch tsconfig.json
dentro dele vamos digitar o seguinte:
{
"compilerOptions": {
"target": "es6",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"rootDir": "src",
"baseUrl": "src",
"allowJs": true,
"resolveJsonModule": true,
"isolatedModules": false,
},
"include": [
"src"
],
"exclude": []
}
Caso você não entenda essas configurações você pode consultar aqui.
Agora vamos configurar o eslint, existem algumas formas para fazer isso eu vou escolher a que eu considero a mais fácil.
npx eslint --init
Vamos marcar a opção:
To check syntax and find problems
o code style será feito pelo prettier daqui a pouco
Depois marcamos:
JavaScript modules (import/export)
React
yes
Browser
JSON
yes
Vamos adicionar um plugin para que nosso lint consiga trabalhar com hooks:
npm i -D eslint-plugin-react-hooks
Agora vamos configurar o prettier:
npm i -D prettier eslint-config-prettier eslint-plugin-prettier
Agora vamos editar nosso .eslintrc.json:
{
"env": {
"browser": true,
"es2021": true
},
"settings": {
"react" : {
"version": "detect"
}
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint",
"react-hooks"
],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react/prop-types": "off",
"@typescript-eslint/explicit-function-return-type": "error",
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error"
}
}
referências aqui
Vamos criar nosso .eslintignore
echo "node_modules\njest.config.js\ncoverage\npublic\nwebpack.config.js\n*.scss" > .eslintignore
Vamos criar nosso .prettierrc:
touch .prettierrc
Dentro dele vamos colocar:
{
"trailingComma": "none",
"semi": false,
"singleQuote": true
}
referências aqui
Vamos adicionar um script de lint no nosso package.json para facilitar o trabalho:
"lint": "eslint src"
Vamos agora adicionar o lint-staged para poder executar ações em nossos arquivos que estão na staged area do git
npm i -D lint-staged
Vamos adicionar também o husky para criarmos hooks no git
npm i -D husky
vamos criar nosso arquivo .lintstagedrc
touch .lintstagedrc.json
dentro dele vamos colocar
{
"*.{ts,tsx}" : [
"eslint 'src/**' --fix ",
"npm run test:staged"
]
}
vamos criar agora nosso huskyrc:
touch .huskyrc.json
dentro dele vamos colocar:
{
"hooks": {
"pre-commit": "lint-staged && npm run test:ci",
}
}
Vamos agora configurar o jest para nossos testes
npm i -D jest @types/jest ts-jest
Vamos criar o arquivo de configuração do jest
touch jest.config.js
dentro dele
module.exports = {
roots: ['<rootDir>/src'],
collectCoverageFrom: ['<rootDir>/src/**/*.{ts,tsx}', '!**/*.d.ts'],
coverageDirectory: 'coverage',
testEnvironment: 'jsdom',
transform: {
'.+\\.(ts|tsx)$': 'ts-jest'
},
moduleNameMapper: {
'\\.scss$': 'identity-obj-proxy'
}
}
referências aqui
Vamos adicionar agora alguns scripts pra teste no package.json
"test": "jest --passWithNoTests --no-cache --verbose --runInBand",
"test:watch": "npm run test -- --watch",
"test:staged": "npm run test -- --findRelatedTests",
"test:ci": "npm run test -- --coverage",
Finalmente React \o/
Antes de prosseguir vamos certificar que seu projeto está igual ao meu:
Vamos começar instalando o react e o react dom
npm i react react-dom
e o types deles
npm i -D @types/react @types/react-dom
na raiz do projeto vamos criar uma pasta com o nome de public
mkdir public
dentro dessa pasta vamos criar um index.html com o seguinte conteudo
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="js/bundle.js"></script>
</body>
</html>
dentro de public vamos criar uma pasta js
vamos instalar e configurar o webpack agora
npm i -D webpack webpack-cli webpack-dev-server
vamos criar o arquivo do webpack.config.js na raiz do projeto
e dentro dele vamos adicionar o seguinte
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = env => {
const mode = env.development ? 'development' : 'production'
return {
mode,
entry: path.join(__dirname, 'src', 'index.tsx'),
output: {
path: path.join(__dirname, 'public', 'js'),
publicPath: path.join('public', 'js'),
filename: 'bundle.js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.scss', '.css'],
},
module: {
rules: [{
test: /\.ts(x?)$/,
loader: 'ts-loader',
exclude: /node_modules/
}, {
test: /\.(s)css$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
modules: true
}
}, {
loader: 'sass-loader'
}]
}]
},
devServer: {
contentBase: path.join(__dirname, 'public'),
writeToDisk: true,
historyApiFallback: true,
open: true
},
plugins: [
new CleanWebpackPlugin(),
]
}
}
vamos adicionar os plugins necessários pra fazer o webpack funcionar:
npm i -D clean-webpack-plugin node-sass sass-loader css-loader style-loader ts-loader
Analisando dependências:
- clean-webpack-plugin - Plugin para limpar a pasta de build (ajuda com o cache).
- node-sass - Para conseguir usar sass dentro do node
- css-loader - Para que o webpack entenda algumas coisas como: @import, url()...
- style-loader - para o webpack consiga colocar o style no DOM.
- sass-loader - Loader para que o webpack consiga trabalhar com sass
- ts-loader - Para o webpack entender o typescript
Vamos criar uma pasta src e dentro dela um arquivo sass-module.d.ts com o seguinte:
declare module '*.scss' {
const content: { [className: string]: string }
export = content
}
dentro de src vamos criar o arquivo index.tsx com o seguinte conteúdo:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App'
ReactDOM.render(<App />, document.getElementById('app'))
dentro de src vamos criar a pasta components e criar o App.tsx
com o seguinte conteúdo:
import React from 'react'
import Styles from './App-styles.scss'
const App: React.FC = () => {
return (
<h1 data-testid="teste" className={Styles.h1}>
Glória a Deuxxx
</h1>
)
}
export default App
ainda dentro de components vamos criar o App-styles.scss:
.h1 {
color: tomato;
}
E vamos criar um arquivo App.spec.tsx vazio por enquanto.
Por fim adicionamos o script de start e build no package.json:
"start": "webpack serve --env development",
"build": "webpack --env production",
Preparando os testes no react
antes da gente começar a configurar os testes temos que instalar um pacote identity-obj-proxy para que o jest não "encrenque"com o sass.
npm i -D identity-obj-proxy
Nosso conf do jest já está configurado para utilizar essa dependências você pode ir lá rever o arquivo caso ache necessário.
Vamos adicionar o testing-library
npm i -D @testing-library/react
Agora dentro do App.spec.tsx vamos adicionar:
import React from 'react'
import { render } from '@testing-library/react'
import App from './App'
describe('teste do boilerPlate', () => {
test('App', () => {
const { getByTestId } = render(<App />)
const h1 = getByTestId('teste')
expect(h1.innerHTML).toBe('Glória a Deuxxx')
})
})
Tudo pronto
Foi um post longo acho que ninguém vai ler tudo mas a minha intenção foi mais explicar em detalhes do que simplesmente um código pra copiar e colar.
Esse é o respositório do boilerplate:
https://github.com/dfirmino/react-boilerplate
Qualquer dúvida, sugestão ou xingamento é só mandar lá no git.
Valeu Falou
Dicas
Podemos configurar o lint para ser executado após o save do arquivo, vou colocar um exemplo do meu settings do vscode mas aconselho da uma pesquisada na internet e ajustar no seu:
Posted on October 26, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.