Server: npm run dev
Web: npm run dev
Mobile: npm run start
obs: Lembrar sempre de trocar as variáveis de ambiente quando for trocar entre o front pro web e pro mobile.
- Comandos iniciais
-
npm init -y
-> criando o package.json -
npm i typescript -D
-> instalando o typescript no projeto -
npm i @types/node -D
-> permite que o typescript saiba que está dentro de um projeto node -
npx tsc -init
-> configurando o typescript no projeto (tsconfig.json) obs: Aqui trocamos o target para es2020 no arquivo tsconfig.json
-
Criamos a pasta source na raiz do projeto
-
Criamos um arquivo chamado server.ts dentro da pasta source
npm i tsx -D
-> O node não entende typescript por padrão e esse comando é uma biblioteca que automatiza o processo de conversão para javascript
- Criamos o script no package.json para rodar o comando de execução do server.ts com
npm run dev
obs: Excutando com o watch fique executando e é atualizada caso o código altere (veja o script no package.json)
npm i fastify
-> instalando o fastify (interpretando requisições HTTP)
- Criamos a configuração do arquivo server.ts para que possua as rotas da nossa APIRestful obs: Diego recomendou o uso do httpie (uma espécie de postman/insomnia para o terminal)
-
npm i eslint -D
-> instalando o eslint para ajudar na padronização do código do projeto obs:npx eslint --init
-> para criar o proprio padrão No projeto ele usou um próprio da rocketseat -
npm i @rocketseat/eslint-config -D
-> instalando o eslint da rocketseat
-
Criamos o arquivo .eslintrc.json e apontamos para a configuração da rockeseat obs: Importante ter configurado no settings.json a linha (quando salvar o arquivo ele corrige os erros de eslint):
"editor.codeActionsOnSave": { "source.fixAll.eslint": true },
-
Configuramos no package.json um script para corrigir todos os erros de eslint de uma vez com o comando
npm run lint
-
npm i prisma -D
-> instalando o prisma para poder acessar o banco -
npm prisma init --datasource-provider SQLite
-> configurando o prisma para usar o SQLiteobs: Dentro da pasta prisma agora temos um arquivo de schema que é possivel criar as tabelas do nosso banco(models)
- Indicou a configuração no settings.json para que ao salvar um arquivo do prisma ele formate corretamente conforme as convenções:
"[prisma]": { "editor.formatOnSave": true },
-
npx prisma migrate dev
-> criando a tabela no banco de dados (gerando uma migration de acordo com o arquivo schema) obs: O nome da migration dado foi create users table -
npx prisma studio
-> gerenciar tabelas do banco de dados por uma GUI, como por exemplo adicionamos um usuário -
npm i @prisma/client
-> liberando o prisma para ser importado no nosso server.ts
- Criamos a configuração para conseguir obter todos os usuários do nosso banco
-
npx create-next-app@latest web --use-npm
-> comando para criar o projeto com nextjs (selecionou sim para todas as opções) -
npm run dev
-> comando para rodar o projeto
-
Deletou o README.md, os svgs na pasta public, o favicon da pasta app, editou o globals.css deixando só as 3 primeiras linhas e apagou no arquivo page.tsx todo o conteudo html no return e substituiu por Hello World
-
Criamos a pasta components e incluimos o componente Button la dentro
-
Repassou os conceitos importantes como o de componentes, propriedades, tipagem de propriedades.
-
Explicou sobre roteamento com Next.js (todo arquivo que for um page.tsx dentro de uma pasta automaticamente será uma rota "com o nome da pasta/componente" da nossa aplicação) -> Tudo isso deverá estar dentro da pasta app
-
Apresentou o tailwind e exemplificou como usar
-
Rodou o comando
npm i @rocketseat/eslint-config -D
para utilizarmos a configuração do eslint da rocketseat para react -
Instalou o plugin
npm i prettier-plugin-tailwindcss -D
que é responsavel por organizar as classes do tailwind de maneira semantica e configurou o arquivo prettier.config.js
-
Rodamos o comando
npx create-expo-app mobile
para criar o projeto -
Trocamos o App.js para App.tsx e rodamos o comando
npm run start
e ele identificou que o projeto tem typescript e perguntou se gostariamos de configurar, só selecionar que sim. -
Explicou sobre as tags para o ambiente mobile, sobre como estilizar e sobre a unidade de medida dp que é diferente do px para web.
-
Instalamos o nativewind com o comando:
npm i nativewind
enpm i tailwindcss -D
. -
Rodamos o comando
npx tailwindcss init
para criar o arquivo taildwind.config.js e depois adicionamos no arquivo criado a seguinte linha:content: ["./App.tsx", "./app/**/*.tsx"],
-
Editamos o arquivo babel.config.js e adicionamos a linha (abaixo de presets):
plugins: ["nativewind/babel"],
-
Editamos também o arquivo tsconfig.json dentro de compilerOptions ficou assim:
"compilerOptions": { "types": ["nativewind/types"] },
-
Aprendemos a estilizar com tailwind no mobile
-
Instalamos o eslint com
npm i eslint @rocketseat/eslint-config -D
-
Instalou o plugin
npm i prettier-plugin-tailwindcss -D
que é responsavel por organizar as classes do tailwind de maneira semantica e configurou o arquivo prettier.config.js
-
Configurando fontes com nextjs e tailwind: a) ir no arquivo layout.tsx e importar as fontes conforme abaixo:
import { Bai_Jamjuree as BaiJamjuree, Roboto_Flex as Roboto, } from 'next/font/google'
b) atribuir elas as variaveis conforme abaixo:
const roboto = Roboto({ subsets: ['latin'], variable: '--font-roboto' }) const baiJamjuree = BaiJamjuree({ subsets: ['latin'], weight: '700', variable: '--font-bai-jamjuree', })
c) tailwind.config.js alterar no tema para ficar conforme abaixo:
theme: { extend: { fontFamily: { sans: 'var(--font-roboto)', alt: 'var(--font-bai-jamjuree)', }, }, },
d) O html do layout.tsx deve ficar assim:
<html lang="en"> <body className={`${roboto.variable} ${baiJamjuree.variable} bg-gray-900 font-sans text-gray-100`} > {children} </body> </html>
-
Importamos as cores do figma, copiei a paleta de cores do github da rocketseat e salvei no arquivo tailwind.config.js
-
Baixamos o favicon renomeando para icon.png e colocando na pasta app que automaticamente o next já reconhece como favicon
-
Para redefinir o title da pagina editar no layout.tsx conforme abaixo:
export const metadata = { title: 'NLW Spacetime', description: 'Uma capsula do tempo construída com React, Next.js, TailwindCSS e Typescript', }
-
Começamos a criar o layout da home dividindo em coluna esquerda e direita e suas devidas estilizações.
-
Instalamos o pacote de icones
npm i lucide-react
-
Copiamos as cores do tailwind.config.js do projeto web
-
Instalamos o Expo Google Fonts
npx expo install @expo-google-fonts/roboto @expo-google-fonts/bai-jamjuree expo-font
a) Importamos as fontes no arquivo App.tsx:
import {
Roboto_400Regular,
Roboto_700Bold,
useFonts,
} from '@expo-google-fonts/roboto'
import { BaiJamjuree_700Bold } from '@expo-google-fonts/bai-jamjuree'
b) Garantimos que as fontes só serão carregadas no App.tsx com:
const [hasLoadedFonts] = useFonts({
Roboto_400Regular,
Roboto_700Bold,
BaiJamjuree_700Bold,
})
if (!hasLoadedFonts) {
return null
}
c) Configuramos o fontFamily no tailwind.config.css:
fontFamily: {
title: 'Roboto_700Bold',
body: 'Roboto_400Regular',
alt: 'BaiJamjuree_700Bold',
},
obs: Pronto agora basta usar as fontes com font-title, font-body ou font-alt. Lembrando que tem que remover o font-bold que estava antes.
- Criamos o blur e os stripes com imagem porque o css do react native é limitado e agora vamos instalar uma biblioteca para importar svgs
a) Resolvemos o import da imagem do blur que tava dando erro com o arquivo assets.d.ts para reconhecer arquivos *.png
declare module '*.png'
b) Instalamos o React Native SVG Transformer: npx expo install react-native-svg
e npm i react-native-svg-transformer -D
c) Criamos um arquivo na raiz chamado metro.config.js com o seguite conteudo:
const { getDefaultConfig } = require("expo/metro-config");
module.exports = (() => {
const config = getDefaultConfig(__dirname);
const { transformer, resolver } = config;
config.transformer = {
...transformer,
babelTransformerPath: require.resolve("react-native-svg-transformer"),
};
config.resolver = {
...resolver,
assetExts: resolver.assetExts.filter((ext) => ext !== "svg"),
sourceExts: [...resolver.sourceExts, "svg"],
};
return config;
})();
d) Inserir mais um bloco de código no addets.d.ts:
declare module "*.svg" {
import React from 'react';
import { SvgProps } from "react-native-svg";
const content: React.FC<SvgProps>;
export default content;
}
e) Apresentou o comando de limpar o cashe do expo sendo: npx expo start --clear
- Habilitamos como usar o tailwind no svg dos stripes com:
import { styled } from 'nativewind'
const StyledStripes = styled(Stripes)
obs: Trocando o componente do svg Stripes por StyledStripes
- Importamos o logo que é diferente do web e terminamos de estilizar o mobile com tailwindcss
-
Configuramos as tabelas e relacionamentos do banco de dados e depois disso rodamos o comando npx prisma migrate dev e ao encontrarmos um erro executamos o
npx prisma migrate reset
por conta do usuário que haviamos criado na aula passada que gerou conflito por não possuir todos os campos. Novamente depois isso executamos onpx prisma migrate dev
e nomeamos a migration como: create memories table. -
Separamos a estrutura do projeto em relação as rotas e o prisma em lib, routes e server
-
Criamos a rota de obter todas as memórias pegando só os 115 primeiros caracteres do conteudo
-
Instalamos o zod pra poder usar validação na rota de pegar uma memória por id com o comando
npm i zod
-
Explicou sobre como validar campos da requisição de obter uma memória pelo id conforme abaixo:
const paramsSchema = z.object({ id: z.string().uuid(), }) const { id } = paramsSchema.parse(request.params)
-
Começamos a rota do post e explicou as validações para o post:
const bodySchema = z.object({ content: z.string(), coverUrl: z.string(), isPublic: z.coerce.boolean().default(false) }) const { content, coverUrl, isPublic } = bodySchema.parse(request.body)
obs: O coerce serve para converter o valor boolean que viria do formulario como (0, undefined...) em true e false
-
Criando o metodo para delete copiando praticamente tudo do getById.
-
Criando o metodo de put que foi uma mistura do post com o getById.
-
Diferentemente do diego validei tudo pelo meu insomnia.
-
Instalando o plugin de CORS
npm i @fastify/cors
e adicionamos as seguintes linhas no server.ts:import cors from '@fastify/cors' app.register(cors, { origin: true, // todas URLs de front-end poderão acessar nosso back-end })
-
Criamos a aplicação OAuth no github
-
Configuramos as variaveis de ambiente para autenticar via github nos .env.local (web) e .env (server)
-
Configuramos para obter o github code, fomos no page.tsx e configuramos o href do sign in para a seguinte rota:
href={`https://github.com/login/oauth/authorize?client_id=${process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID}`}
obs: Ali obtemos de volta no nosso callback o seguinte endereço:
http://localhost:3000/api/auth/callback?code=bb36402d85cd68ab0a55
sendo depois do ? o codigo que precisamos!!!
-
Componentizamos a parte web da aplicação
-
Para o backend (server) reconehcer suas respectivas variáveis de ambiente, precisamos instalar o pacote
npm i dotenv -D
obs: Também adicionamos no arquivo server o seguinte import:import 'dotenv/config'
-
Instalamos o axios com o comando
npm i axios
e configuramos a rota para obter o codigo de autenticação -
Salvamos o usuario no banco de dados caso ele ainda não seja registrado
-
Instalamos o
npm i @fastify/jwt
a) Registramos o jwt no server.ts conforme abaixo:
import jwt from '@fastify/jwt' app.register(jwt, { secret: 'spacetime', })
b) Agora retornaremos o token ao em vez do usuario na rota de autenticação:
const token = app.jwt.sign({ name: user.name, avatar: user.avatar }, { sub: user.id, expiresIn: '30 days', })
-
Agora todas as rotas são autenticadas no backend.
-
Instalamos o axios no frontend com
npm i axios
para podermos obter o codigo da página de callback do sign in. -
Tive que corrigir o retorno do register para um objeto com token, pois estava retornando undefined quando tentava obter o token no frontend.
-
Terminamos de configurar o arquivo route.ts para que ele redirecione o usuario para uma rota e salve nos cookies o token, liberando o acesso dele em todas as rotas com uma validade de 30 dias
-
Permitir que todas as páginas acessem os cookies e verificar se existe um cookie com o token informando assim que o usuario estaria logado
import { cookies } from 'next/headers'
const isAuthenticated = cookies().has('token')
-
Para decodificar o token jwt presente nos cookies instalamos a biblioteca
npm i jwt-decode
-
Criando o componente de profile para aparecer apenas quando o usuario estiver logado
-
Precisamos permitir no next.config.js quais dominios podem carregar imagens externas com:
const nextConfig = {
images: {
domains: ['avatars.githubusercontent.com'],
},
}
-
Configuramos demais elementos do profile como nome e link para quero sair que ainda não possui rota.
-
Agora indo pro projeto mobile instalamos o pacote
npx expo install expo-auth-session expo-crypto
e adicionar no app.json a linha"scheme": "nlwspacetime",
-
Para poder pegar nossa redirect url de desenvolvimento usamos o seguinte console.log:
console.log( makeRedirectUri({ scheme: 'nlwspacetime', }), )
-
Instalamos o axios com
npm i axios
e colocando o base url com o ip da minha máquina no momento. -
Obtemos o token no mobile e depois instalamos o
npx expo install expo-secure-store
porque no ambiente mobile não temos cookies -
Salvamos o token o secure store
-
Instalamos o expo router
npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar react-native-gesture-handler
-
Criamos o arquivo index.js na raiz do projeto contendo apenas:
import 'expo-router/entry'
-
Fizemos algumas alterações no package.json do projeto como por exemplo: a) Trocamos o main:
"main": "index.js",
b) Inserimos no final:
"overrides": {
"metro": "0.76.0",
"metro-resolver": "0.76.0"
},
- Configuramos o plugin do babel.config.js:
plugins: ['nativewind/babel', require.resolve('expo-router/babel')],
obs: Adicionando o segundo plugin
- Configurando a rota de redirect após login do usuário para ser a tela de memories e ajustando o App.tsx dentro da pasta app como index.tsx e criando o memories.tsx também.
-
Aqui separamos o que é fixo de toda pagina(layout) e o que muda de acordo com a rota.
-
Criamos a função de deslogar
-
Estilizamos a tela de nova memória e precisamos instalar um pacote para editar o css do checkbox com o comando:
npm i @tailwindcss/forms -D
e adicionando esse require no fim do arquivo tailwind.config.jsplugins: [require('@tailwindcss/forms')],
-
Criamos o restante do layout da página de nova memória
-
Criamos uma proteção de rotas para as rotas que não podem ser acessadas sem estar logado com o middleware.ts
-
Ajustamos os redirects para que o usuario consiga ir para onde estava indo caso queira acessar a tela de criação de nova memória não esteja logado, ele é redirecionado para login e depois novamente para nova memória.
-
Adicionamos a funcionalidade do cadastrar lembrança.
-
Trocamos pro projeto mobile e agora vamos configurar o layout por lá também.
-
Definimos as rotas iniciais e testamos se o usuario está logado ou não para sofrer um redirect
-
Criamos a tela de nova memória do mobile
-
Partimos para o back para trabalhar com upload de arquivos e pra isso instalamos um plugin com o comando
npm i @fastify/multipart
-
É possivel visualizar toda a lógica no arquivo upload.ts e acredito ser necessário revisar mais pra frente
-
Instalamos um pacote com o seguinte comando
npm i @fastify/static
para que seja possivel acessar as imagens pela rota delas
-
Vamos criar o preview da imagem anexada na aplicação web
-
Agora estamos logando os dados do formulário para confirmar que vamos salvar de maneira correta nossa memória
-
Confirmamos que o arquivo está sendo salvo em uploads, e tinha faltado criar essa pasta no server
-
Agora vamos instalar o
npm i js-cookie
para facilitar buscar cookies em arquivos que estão usando o 'use client' do next. obs: Devemos instalar os tipos desse pacote para poder funcionar com typescript com o comando:npm i --save-dev @types/js-cookie
-
Obtemos o cookie e finalizamos o post de uma memória na aplicação web
-
Agora passamos para a aplicação mobile para fazer o mesmo processo
-
Para funcionar corretamente precisamos instalar o
npx expo install expo-image-picker
-
Estilizamos e configuramos para quando selecionarmos uma imagem a mesma aparecer no preview do mobile
-
Configuramos para agora conseguir salvar uma memoria via app mobile
-
Agora vamos para a listagem tanto na web quanto no mobile
-
Para formatação de datas no ambiente mobile e web nos usamos o
npm i dayjs
-
Corrigi o link da primeira tela escrito "criar agora" no web para ir para tela de cadastrar lembrança
-
Criei a página para ler mais sobre uma memória no web
-
Criar tela de ler mais sobre uma memória no mobile
-
Criar um datepicker para selecionar a data da memória quando for cadastrar uma memória (web e mobile)
-
Responsividade do projeto web