Se você conseguir aprender o recurso do Next. js que eu vou ensinar neste vídeo, você consegue aprender qualquer coisa que inventarem para esse framework daqui para frente. Fora que isso vai te libertar a construir websites com escalas enormes de conteúdos, seja um blog gigantesco, um portal gigantesco, um e-commerce gigantesco, tanto faz!
E o meu objetivo aqui é deixar a didática tão alinhada, mas tão alinhada, que qualquer pessoa que quiser vai conseguir aprender e vai poder levar esses conhecimentos até para outras linguagens, frameworks ou tecnologias num geral. Então, este vídeo aqui vai contar com quatro desafios ordenados naturalmente do mais fácil até o mais difícil, para levar você até o desafio final e eu quero ver se você consegue entendê-lo de primeira. Está preparado?
Massa! Então, começando pelo começo. Desafio #1: Onde páginas estáticas vão te limitar.
Caso você não esteja acompanhando, isso daqui é uma playlist sobre desenvolvimento de websites modernos, mas você não precisa vê-la inteira agora, porque em uma paulada só eu vou colocar todo mundo no mesmo trilho. Olha só. .
. Como a gente viu nos vídeos passados, o Next. js utiliza o File-system Routing para automaticamente gerar as rotas do seu site.
Então, a gente tem uma pasta especial chamada pages e todo arquivo JavaScript ou TypeScript colocado aqui dentro, automaticamente vai virar uma página web. Como exemplo, a gente tem o index. js que vai virar a home, a página raiz do site, a gente tem também o sobre.
js que vai virar o /sobre. . .
E também o tempo. js que vai virar o /tempo. E dentro dessa pasta especial pages, a gente tem uma outra pasta especial chamada API e a dinâmica é exatamente a mesma, só que ao invés de gerar páginas, o Next.
js gera rotas, como por exemplo o arquivo tempo. js, nesse caso será disponibilizado em uma rota chamada /api/tempo. E tanto o caminho preenchido na URL para chegar nessas rotas da API ou o caminho para chegar nas páginas tradicionais tipo /sobre, se chamam na verdade de Path.
É o caminho para conseguir acessar aquele recurso. E o legal é que a tradução de path é justamente caminho, então guarda esse nome path, porque vai ser importante para quando a gente chegar no último desafio. Show!
Mas daí você pode estar se perguntando: "Tá, mas onde disso que a gente viu até agora me limita? " E a resposta é bem simples. Desse jeito, usando arquivos fixos, a única forma de o seu site ter novas páginas é você indo lá no seu projeto e manualmente criar um novo arquivo.
Quer publicar um novo post no seu blog? Sem problemas, é só ir lá e criar um novo arquivo no projeto, e aí você já percebe que para criar um blog gigantesco com milhares de posts, se torna algo inviável. Mas e se a gente tivesse um parâmetro nesse path, nesse caminho.
. . E a página que abrir capturasse isso e mostrasse algo diferente na tela, que conseguisse puxar alguma coisa depois que ela já abriu?
Ótima pergunta, e agora entendendo onde páginas estáticas nos limitam, vamos aprender a como usar parâmetros dinâmicos. Ainda usando o file-system routing, criando arquivos normais no projeto mesmo, olha só o que a gente consegue fazer, mas agora usando o Dynamic Routes. Dentro da pasta especial pages, eu vou criar dessa vez uma pasta convencional chamada produtos, e se dentro dela eu criar um arquivo id.
js, a gente sabe o que vai acontecer, vai ser gerado um path fixo de produtos/id e que por ser fixo, não vai servir para muita coisa. Mas se eu abraçar esse id com square brackets ou colchetes, essa rota se torna dinâmica e eu consigo capturar qualquer valor que for colocado ali através de uma propriedade que vai se chamar justamente id. Ou seja, o arquivo /produtos[id].
js ao invés de se tornar uma página fixa/produtos/id, na verdade esse id vira um placeholder, um parâmetro que consegue receber qualquer valor, como por exemplo 10, e eu consigo acessar esse valor de dentro da minha página. Olha só. .
. Eu vou começar escrevendo um componente e o exportando como padrão para o Next. js saber que é com ele que eu quero gerar o HTML da minha página e até aí tudo normal.
Agora, eu vou importar um hook chamado useRouter do próprio Next. js, e se eu inicializá-lo dentro do meu componente, eu posso fazer várias coisas relacionadas à rota, incluindo capturar o que foi colocado naquele nosso parâmetro id. Por último, eu vou retornar um HTML bem simples que imprime esse valor.
E rodando o servidor local e acessando o site, no momento que eu digitar o endereço /produtos/ algum id qualquer, a nossa página vai capturá-lo com sucesso, seja qual for esse id. E com ele em mãos, eu posso usar lógica no client-side para fazer o que eu quiser com aquela página, seja imprimir o valor na tela como a gente fez, seja para pegar esse id e fazer uma consulta em qualquer outra API para puxar mais dados, pode ser até a própria API fornecida pelo Next. js, como a gente viu nos vídeos passados.
E aí, nesse caso para receber um parâmetro dinâmico por uma rota de API do Next. js, a dinâmica com o file-system routing continua exatamente a mesma coisa. Por exemplo, dentro da pasta especial API, vamos também criar uma pasta convencional chamada produtos e dentro dela vamos criar um outro [id].
js. Agora, eu vou rapidinho exportar e escrever uma função que aceite o request e o response da API e qualquer valor passado para o path ou rota/api/produtos e o id em questão, eu consigo acessar esse valor através do parâmetro dinâmico request. query.
id, onde novamente, o nome desse parâmetro id é herdado desse identificador colocado no nome do arquivo. Mas agora voltando para a versão página web, quando nós a acessamos, aconteceu algo na frente dos seus olhos que eu não sei se você percebeu. É uma coisa que pode machucar o seu SEO, o Search Engine Optimization, e se isso é importante para você, presta atenção no que vou mostrar agora, porque os buscadores podem não conseguir enxergar as informações que vierem dessa forma.
Bom, o número 42 está impresso todo bonitão aqui na nossa página, correto? Mas nota o que vai acontecer quando eu der refresh na página. .
. Viu? Ele piscou.
Se eu der um refresh de novo aqui, piscou. Isso acontece porque esse valor não vem junto com o HTML inicial da página, e ele é populado apenas no client-side, em tempo de execução desta página. Para provar isso é bem simples, basta acessar o código-fonte e ver que o HTML estático traz o que é de fato estático, previsível, vamos colocar assim.
. . E o que é dinâmico, não.
E isso vale para qualquer coisa que o site puxe dinamicamente no client-side e o final das contas, faz sentido. Como o sistema vai adivinhar o que eu vou colocar lá na URL, e o que vai ser carregado dinamicamente para já trazer isso junto do HTML, correto? Só que pensar dessa forma simplista nos revela uma coisa muito importante desse modelo.
No Next. js, páginas com rotas dinâmicas assim, no fundo no fundo, são iguais a páginas estáticas, iguaizinhas àquelas que a gente viu nos vídeos anteriores. Só que pelo fato de você ter especificado no sistema de arquivos qual o nome do parâmetro que você quer capturar através daqueles colchetes, agora você tem o benefício dessa URL aceitar parâmetros nas quais você consegue resgatar isso no client-side e somente lá, o que novamente pode penalizar o SEO.
Mas e se o site, ao acessarem uma rota lá no navegador, primeiro processasse tudo no servidor, e só depois disso mandasse para o navegador? Novamente, ótima pergunta. .
. E agora que a gente aprendeu a usar parâmetros dinâmicos, chegou a hora de aprender a como gerar páginas dinamicamente no servidor. Na minha visão bem sincera, usar o recurso que eu vou te ensinar agora, é dar um passo para trás em performance e disponibilidade.
É o jeito tradicional de fazer páginas web e a gente comentou sobre isso no primeiro vídeo desta playlist. Mas talvez você possa ter um caso de uso em que isso é necessário e não tem como escapar, fora que aprender a fazer isso vai te preparar a encarar o último desafio do vídeo, porque ele vai ser a junção de tudo o que a gente aprendeu até agora. Vai ser meio que a mistura de todas as formas de se criar páginas em um novo método que junta a performance e disponibilidade de páginas estáticas, com a flexibilidade de páginas dinâmicas e foi o que me vendeu de uma vez por todas uso do Next.
js. Mas antes, lembra que a gente vai aprender agora a usar o recurso desse framework que pode ser um passo para trás, justamente em questão de disponibilidade e performance chamado getServerSideProps. E o nome é meio confuso de início, mas faz sentido.
Olha só. . .
A gente voltou para a página de produtos que a gente fez antes e durante a playlist, aprendemos que isso daqui é um componente React tradicional. Ou seja, ele aceita a injeção de propriedades, de valores vindos de outros lugares. E nesse caso, esse "outros lugares" é o seu servidor, o server-side, antes de tudo consegue computar essas propriedades com o que você quiser e injetar isso no componente através do props, por isso do nome getServerSideProps, ele pega as props no servidor.
Então, para mostrar isso na prática, eu vou remover toda a implementação anterior que pegava o parâmetro pelo client-side e vou exportar uma função assíncrona, justamente chamada getServerSideProps. Com isso, a gente acabou de informar ao Next. js que antes de retornar à página, ele precisa rodar essa função aqui primeiro em toda e qualquer request contra esse caminho.
E essa função é bem esperta e recebe um parâmetro chamado context, que dentro dele tem várias coisas legais. Por exemplo, o request e response, muito que a gente já viu no vídeo da API. Mas para o nosso caso aqui, o mais importante é conseguir extrair o id que foi declarado na rota dinâmica e da mesma forma que das outras vezes, vamos acessar o query.
id. Agora que a gente aprendeu a capturar o valor, o mistério é entender como enviá-lo daqui para que no props do componente da página, e é super simples, basta retornar um objeto e dentro dele declarar o props que a gente quer que seja injetado no componente. Novamente, esses dois props são a mesma coisa.
Então, eu quero que o meu props seja um objeto e que dentro tenha um parâmetro chamado id com o valor id que foi extraído ali de cima. Pronto! Agora sabendo que isso vai ser injetado no props do componente, eu vou acessar o valor dele diretamente aqui na parte da renderização do HTML.
Salvando e pulando para o navegador, nota que quando eu dou refresh, tudo já vem em um único bloco de informação. E o motivo é que tudo isso está vindo no HTML que foi gerado dinamicamente pelo servidor nessa minha request. Dinâmico ao ponto de eu mudar o parâmetro aqui em cima e como esperado é refletido no HTML novamente.
E por ser uma função assíncrona e que roda somente no servidor, você pode fazer qualquer tipo de consulta, seja em uma outra API, seja fazer uma consulta diretamente no seu banco de dados usando dados sensíveis, porque novamente, nada disso aqui é enviado para o client-side. A única coisa que é enviada é o que você injetar pelo props. Mas caso você trabalhe com outras tecnologias que também fazem processamento de páginas dinâmicas no back-end, nenhuma novidade aqui, correto?
Correto! Incluindo os problemas de performance e disponibilidade. Imagina que a gente está na Black Friday e o seu produto recebe um pico de acessos.
Ou se essa página for um post no seu blog e que vai precisar puxar informações do back-end e você também recebe um pico de acessos ao ponto de "engargalar" a conexão de todo mundo. Meio que sorte a sua a página demorar para responder e o usuário ainda estar lá, porque na maioria dos casos o servidor vai dar um time out no seu banco de dados e retornar um erro para ele. .
. Ou o proxy que você vai usar vai dar um time out no seu servidor e ninguém vai ter acesso a nada. E a única coisa que seu usuário queria fazer era ler aquele post, e nem foi esse post que recebeu o pico de acesso.
Foi outro, mas que levou consigo todo o sistema. Mas então, como a gente consegue resolver o problema de poder ter virtualmente infinitas páginas onde eu não quero ter o trabalho de criar manualmente cada arquivo para que ele seja estático e tenha altíssima disponibilidade e performance, que possam ser conteúdos gerados dinamicamente por um CMS, como por exemplo, posts de um blog ou produtos de um e-commerce, mas que também não sejam puxados dinamicamente pelo client-side para não ferrar o SEO e que não sejam gerados dinamicamente pelo server-side a cada request para não ferrar a minha performance e disponibilidade? Excelentes perguntas!
Caramba, você bolou tudo isso sozinho? Muito bom! E como a gente aprendeu a gerar páginas dinamicamente no servidor, chegou a hora do último desafio.
. . Aprender como geração incremental de páginas estáticas vem para solucionar tudo isso.
Geração incremental de páginas estáticas ou Incremental Static Generation é um nome massa, difícil de engolir, mas massa porque ele une todos os conhecimentos dessa playlist e vai trazer um ótimo balanço entre disponibilidade, performance e flexibilidade. Então, para revisar, o Next. js tem três formas de buscar dados para gerar páginas.
O getStaticProps que serve para pegar as props no processo de build e somente lá para gerar uma página estática. . .
O getServerSideProps que também serve para pegar as props, mas em tempo de execução no back-end. . .
E por último, o getStaticPaths. Lembra que eu pedi para prestar atenção na palavra path? Ótimo.
Eu não sei se ficou claro, mas o foco principal tanto do getStaticProps e do getServerSideProps é gerar as props para serem passadas, injetadas nas páginas e o que muda somente é quanto que eles fazem isso. O primeiro caso roda uma única vez no processo de build antes de ser colocado em produção. Então, ou eu crio de forma antecipada os arquivos antes do build, ou não posso mais criar novas páginas estáticas com novos paths depois que tudo estiver em produção.
O segundo é o contrário. Ele não roda no processo de build, ele roda em produção, por exemplo, ou toda vez que é invocado. Então, eu posso ter paths infinitos, porque literalmente ele está criando páginas novas em tempo de execução, só que com o trade-off de ser menos disponível, menos performático, por não ser uma página estática que vai estar distribuída globalmente em várias CDNs.
A boa notícia é que o getStaticPaths serve para ser uma solução intermediária a tudo isso, ele consegue gerar em tempo de execução lá em produção mesmo, novas páginas estáticas assim que elas forem chamadas. Mas isso é o modo mais avançado dele, a gente vai chegar lá, porque a gente vai começar com o modo mais simples que é falar de uma forma antecipada, quais paths, quais caminhos na URL eu quero gerar páginas estáticas e o resto que ficou de fora gera um 404. É agora que a sua cabeça pode dar uma entortada, mas segura firme porque quanto mais você avançar neste vídeo, mais você vai entender.
Olha só que massa. . .
A gente está de volta no arquivo pages/produtos/[id]. js e a primeira coisa que eu vou fazer é remover dele a implementação anterior. Feito isso, lembra que apesar que isso é um arquivo, ele é especial, é uma rota dinâmica e as páginas resultantes podem assumir vários conteúdos no final das contas.
Aqui nesse id, por exemplo, cada página pode imprimir o seu próprio id e o que vai definir o valor dentro desse id é, na verdade, o path que está sendo chamado lá no navegador, como por exemplo, produtos/ e o id em questão. Então, como que o Next pode saber de uma rota dinâmica quais páginas ele deve construir de forma antecipada no processo de build? Simples, exportando de uma forma assíncrona uma função especial chamada getStaticPaths.
Ou seja, pegue os paths, os caminhos para gerar os estáticos. E agora, todos os paths que a gente retornar dessa função, o Next. js vai criar páginas estáticas na hora do build e para todas as outras, por enquanto, ele vai retornar 404.
Mas, na verdade, não é responsabilidade do getStaticPaths gerar as páginas estáticas. Ele só é responsável por definir quais serão os caminhos, os paths a serem antecipados no build. Isso porque quem tem a responsabilidade de gerar páginas estáticas de fato é o getStaticProps.
Olha que interessante a mistura dessas duas coisas. A primeira coisa que eu vou fazer é retornar um objeto e dentro desse objeto, eu vou declarar duas propriedades. A primeira é que define quais paths eu quero gerar de forma antecipada, páginas estáticas, e por enquanto, vou deixar um array em branco, mas eu já volto nele.
E a segunda propriedade é a que define o fallback, que por enquanto eu vou colocar como false, porque caminhos que fujam do que eu declarar ali na propriedade paths, eu quero que retorne 404. E a magia está dentro desse array no path, cada objeto que eu colocar aqui dentro é como se a gente tivesse de fato gerando um path, um caminho de verdade no final das contas. Vamos avançando que para entender de fato precisa ver o código inteiro feito.
Então, por enquanto eu vou definir manualmente nosso primeiro objeto de path. E a nossa URL tem um parâmetro dinâmico, o nosso id. Então, eu vou especificar aqui no nosso objeto params que eu quero que uma das páginas geradas seja como se eu tivesse passando o id com o valor 1 ali.
Agora, eu vou duplicar isso e criar um novo path, e simular alguém passando o id 2. E agora, com isso no processo de build, o getStaticPaths vai ser rodado uma vez e para cada objeto que ele encontrar no array de path, ele vai "acessar" essa página passando os parâmetros que foram declarados no objeto params e ele vai fazer isso para o array inteiro. E está na cara que você não vai preencher esse array de forma manual como eu fiz, você vai pegar essa lista de um banco de dados ou de alguma outra API.
Mas e se você estiver se perguntando: "E se eu tiver milhões de posts e ele ter que acessar esses milhões de posts num processo de build. . .
Vai demorar muito, não é mesmo? " É mesmo! E o fallback resolve justamente esse problema.
Mas a gente já vai chegar lá. Por enquanto, a gente nem gerou as páginas estáticas de fato. Isso mesmo!
Por enquanto, a gente só falou para o Next. js, meio que virtualmente, quais caminhos a gente quer que ele gere uma página estática, cada um com o seu parâmetro, por exemplo, produtos/1, produtos/2. .
. Aliás, agora que eu notei. .
. Sempre que um parâmetro é passado por uma rota, ele é uma string e não um number, porque pode ser um post-slug como produtos/teclado-mecanico. Bom, com isso ajustado, quando a gente exportar de forma assíncrona aquela função especial getStaticProps, para cada objeto de path encontrado no array lá em cima, ele vai rodar uma vez o getStaticProps, mas passando o contexto em cada vez.
E esse contexto é justamente qual o path, qual caminho o Next. js está trabalhando naquele momento e por isso que a gente consegue acessar o valor do parâmetro id, acessando o context. params.
id. Agora, como sempre, basta retornar isso como uma props, onde esses dois props são a mesma coisa, como a gente já viu, e declarar que a propriedade id tem o valor do id ali de cima. Salvando e acessando o navegador, a gente tem a página anterior com aquele id 20 ainda aberto.
. . Mas se a gente der o refresh fica "Not Found", porque não estava na lista dos paths.
E se a gente acessar o id 1, funciona. . .
O id 2, funciona. . .
E o id 3, não. Não é tudo, como a gente vai ver um pouco mais para frente, mas por enquanto bom, porque tanto no getStaticPaths quanto no getStaticProps, você pode programar código back-end real, fazendo acesso com informações sensíveis que nada disso vai para o client-side. Então, no getStaticProps ao invés de apenas tunelar o id para a página final, como eu estou fazendo ali, você pode consultar o banco de dados e buscar todas as informações do produto e retornar isso para o props, e aí sim gerar estaticamente uma página com todas as informações bonitonas e que dificilmente vai cair.
E no getStaticPaths, ao invés de manualmente ir declarando os caminhos, ou até pode ser manualmente, vai. . .
Você pode especificar quais caminhos no seu site ou do seu portal, você quer que seja gerada as páginas estáticas antes de tudo, porque você não quer que ela saia do ar por nada. . .
E aí, o restante pode ser gerado sob demanda. Mas esse sob demanda não está programado ainda, mas é bem fácil e é através do fallback. O fallback aceita três valores: o false, que vai desabilitar o fallback, ou seja, qualquer página que não estiver listada nos paths ali em cima vai retornar 404.
O true, que vai fazer o Next. js aceitar qualquer path que tentarem acessar no navegador para essa rota dinâmica e vai tentar gerar a página de forma assíncrona. E por último o blocking, que assim como no getServerSideProps, vai bloquear a requisição da página até que consiga com sucesso gerar a página final e assim retornar.
Mas uma coisa importantíssima de se destacar e é o que faz toda essa engenharia valer a pena. Uma vez gerando a página, seja por fallback assíncrono ou bloqueante, ela fica em cache. E se você estiver hospedando na Vercel, ela vai ser repicada globalmente para a CDN deles.
Ou seja, mesmo que sejam páginas demoradas para se gerar, que façam várias consultas para puxar informações de vários lugares, uma vez gerada, todas as próximas requisições serão retornadas instantaneamente. Olha que massa. .
. A primeira coisa que eu vou fazer é colar de novo um código aqui que eu peguei no Stack Overflow para simular um delay. E eu vou simular uma demora artificial de cinco segundos em toda tentativa de gerar uma página estática através desse novo fluxo.
Eu vou deixar como fallback bloqueante para ficar bem visível a demora do retorno. Acessando o nosso site, eu vou dar um refresh aqui e olha que massa essa demora de cinco segundos para daí ter algum retorno. E como a gente está em ambiente de desenvolvimento, mesmo que eu dê outro refresh, ele vai ignorar qualquer cache e começar a processar tudo de novo.
Mesmo comportamento para o produto 2, ele vai passar pelo exato mesmo delay também. Só que agora, lembra que o produto 3 não está na lista de paths? Mesmo assim, tentando acessar, ele vai cair no fallback e vai conseguir gerar a página mesmo com aquela demora artificial.
A mesma coisa para o produto 100, se assim você tivesse no seu catálogo, vai ser gerado sem problemas. E a magia do que acabou de acontecer não dá para ver aqui em localhost, a gente tem que mandar isso lá para a produção. Vamos ver como é que fica?
Isso a gente já fez inúmeras vezes ao longo dos vídeos da playlist, então eu vou acelerar até o ponto de ter terminado o deploy e eu estou aqui na home do site. Agora, olha que massa! Lembra que o id 1 estava na lista de paths, no getStaticPaths.
Ou seja, o custo de gerá-lo, mesmo com aquele delay bizonho de cinco segundos, foi pago lá no processo de build. E quando eu acesso a página aqui, ela retorna quase que instantaneamente e se eu der refresh aqui, mesma coisa. Se eu tentar com o id 2, a mesma coisa, retorna instantaneamente porque essa página já foi gerada no estágio de build por ter sido declarado também no paths.
Agora, o id 3 não estava. O Next. js lá em produção nem sabe dele nesse momento, mas quando eu acessar, vai ser identificado que ele não estava nos paths, vai cair no fluxo de fallback, passar pelo getStaticProps para gerar a página, pagar o custo do delay e retornar à página.
Olha só. . .
E pimba! O back-end está lutando com o delay e. .
. Retornou. Show!
Só que nesse exato momento, essa página já está cacheada e distribuída globalmente e qualquer refresh seguinte que eu fizer retorna instantaneamente, mal dá para ver o ícone de loading lá piscando. E agora, fica na sua mão escolher quais páginas você quer garantir a disponibilidade já lá no momento do build de forma antecipada. .
. E quais páginas você quer se arriscar de gerar em tempo de execução. Agora, uma coisa importante a se notar é que o fallback true, ao invés do blocking, vai dar uma experiência melhor para usuários que acessam uma página que nunca foi acessada antes.
Isso porque o fallback true, o Next. js instantaneamente vai retornar uma página estática em que você pode colocar um placeholder falando: "Carregando", por exemplo, e quando o back-end conseguir terminar de processar as props finais, ele empurra isso para o client-side e a página é atualizada automaticamente, tudo de forma transparente e sem refresh. E isso só acontece no primeiro acesso, porque nos bastidores, o Next.
js em paralelo, computou um versão estática e todo acesso seguinte vai receber uma resposta instantânea de uma página estática. isso é incrivelmente massa, mas nesse primeiro acesso, se for feito por alguns buscadores ou redes sociais na hora de eles tentarem puxar desse seu link a descrição ou alguma imagem, eles podem estranhar esse acesso assíncrono de informações. Então, ainda surgiro você usar a estratégia do blocking, porque isso acaba resolvendo esse tipo de problema, se ele é importante para você.
E assim, eu preciso ser sincero. . .
Eu estou de cara que você chegou até aqui! Meus sinceros parabéns, você matou a pau, mesmo entendendo ou não. .
. O importante é que você não está querendo deixar a peteca cair, só que o mais massa vem agora. Duas coisas.
Primeiro: marcar que o último desafio foi completado com sucesso para a full dopamina, e todos esses conhecimentos que eu passei aqui nos vídeos, eu vou usar um projeto pessoal meu que eu pretendo que se torne bastante grande. É uma coisa que eu sinceramente acredito que está faltando na nossa área. Eu vou fazer vídeos para o canal sobre ele com certeza, mas se você quiser ver esse projeto nascendo do zero, na forma mais bruta e real possível, para ver exatamente o que passa pela minha cabeça enquanto eu estou pensando e navegando dentro da ideia e do projeto, eu sugiro ver este vídeo aqui.
Ele é exclusivo para o Membros da Turma, porque é um material 100% cru e não editado, mas tem mais 60 pontos de interação que eu mesmo vou assistir de novo quando eu começar a colocar a mão na massa nesse projeto. Vale muito a pena. Fechado?
Valeu!