Jamstack in Action
Tags: javascript, webdev, tutorial, spanish
Published: 2022-06-17 04:59:46

Herramientas:
- [Node.js](https://nodejs.org/es/)
- [TypeScript](https://www.typescriptlang.org/)
- [Next.js](https://nextjs.org/)
- [Next Auth](https://next-auth.js.org/)
- [Tailwind](https://tailwindcss.com/)
- [Prisma](https://www.prisma.io/)
- [Yarn](https://yarnpkg.com/)

Requisitos:
- Ganas de aprender

Objetivo:
Veras en acción con este rápido tutorial practico las mejores herramientas para desarrollar sitios de ultima generación. Escalables, resilientes y de fácil desacople. Desde 0 a producción.

[Repositorio](https://github.com/ushieru/Jamstack-2022). Por si te llegas a perder en el camino 👀

> Daré por sentado que ya saben que pueden seguir este tutorial con npm, yarn o pnpm; que ya cuentas con Node.js instalado y que haz trabajado con este runtime anteriormente. 


>> ⚠️ Esto no significa que no puedas comentar tus dudas. La comunidad es muy grande y mas de uno te vamos a poder ayudar si te atoras con algo o quieres profundizar un poco más. ⚠️

## Que es Jamstack?
[Jamstack](https://jamstack.org/) es una arquitectura diseñada para que la web sea más rápida, más segura y más fácil de escalar. Se basa en muchas de las herramientas y flujos de trabajo que los desarrolladores adoran y que aportan la máxima productividad.

Los principios básicos de pre-renderización y desacoplamiento permiten que los sitios y las aplicaciones se entreguen con mayor confianza y resistencia que nunca.

## Let's do it
Iniciaremos creando todo lo necesario para nuestro proyecto.
Dejare enlaces a la documentación por si quieren profundizar un poco mas pero este tutorial puede ser seguido 100% desde aquí.

### Next.js
El framework de react para produccion. Next.js le brinda la mejor experiencia de desarrollador con todas las funciones que necesita para la producción: renderizado híbrido estático y de servidor, compatibilidad con TypeScript, agrupación inteligente, búsqueda previa de ruta y más. No se necesita configuración.
[Doc](https://nextjs.org/docs/getting-started)

````sh
$ yarn create next-app jamstack-2022 --typescript
```


### Tailwind
Cree rápidamente sitios web modernos sin tener que abandonar su HTML. Un marco CSS de primera utilidad repleto de clases como flex, pt-4, text-center y giratorio-90 que se pueden componer para crear cualquier diseño, directamente en su marcado.
[Doc](https://tailwindcss.com/docs/guides/nextjs)
```sh
$ yarn add -D tailwindcss postcss autoprefixer
$ yarn tailwindcss init -p
```
```js
// tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```
```css
/* styles/globals.css */

@tailwind base;
@tailwind components;
@tailwind utilities;
```

> Puedes borrar styles/Home.module.css

### Prisma
Cree e itere aplicaciones de JavaScript y TypeScript basadas en datos en menos tiempo.
[Doc](https://www.prisma.io/docs/getting-started/setup-prisma/add-to-existing-project)
[VSCode extention](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma)

```sh
$ yarn add -D prisma
$ yarn prisma init
$ yarn add @prisma/client
```

> Haremos un pequeño ajuste en la DB que usaremos. Puedes usar la que quieras. Para fines prácticos usaremos SQLite. Si te interesa un tutorial con [Mongo Atlas](https://www.mongodb.com/atlas/database), [Planet Scale](https://planetscale.com/) (MySQL), [Cockroach](https://www.cockroachlabs.com/) (Postgres) ó con Docker. Házmelo saber en los comentarios.

```ts
// prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}
```

```env
; .env

DATABASE_URL="file:./dev.db"
```

Usaremos las [mejores practicas de Prisma + Next.js](https://www.prisma.io/docs/support/help-articles/nextjs-prisma-client-dev-practices#problem) en tiempo de desarrollo.

````ts
// lib/prisma.ts

// globals.d.ts
import { PrismaClient } from '@prisma/client'

declare module global {
    let prisma: PrismaClient;
}

let prisma: PrismaClient;

if (process.env.NODE_ENV === 'production') {
    prisma = new PrismaClient()
} else {
    if (!global.prisma) {
        global.prisma = new PrismaClient({ log: ['info', 'query'] })
    }
    prisma = global.prisma
}

export default prisma;
```

### Next Auth
Autenticación para Next.js. Código abierto. Full Stack. Seguro por defecto. Eres dueño de tus datos.
[Doc](https://www.prisma.io/docs/getting-started/setup-prisma/add-to-existing-project/relational-databases-typescript-postgres)
```sh
$ yarn add next-auth @next-auth/prisma-adapter
```
```ts
// prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String?
  access_token      String?
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String?
  session_state     String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}
```

```tsx
// pages/_app.tsx

import '../styles/globals.css'
import type { AppProps } from 'next/app'

import { SessionProvider } from "next-auth/react"
export default function App({
  Component,
  pageProps: { session, ...pageProps },
}: AppProps) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}
```

```ts
// pages/api/auth/[...nextauth].ts

import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import prisma from './../../../lib/prisma'

export default NextAuth({
  adapter: PrismaAdapter(prisma),
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
    }),
  ],
})
```
> Comenta si quieres ver como ligar otros servicios o consulta directamente la doc de [Next-Auth](https://next-auth.js.org/providers/).

> Para crear las credenciales para google como proveedor lo puedes hacer desde la [consola de GCP](https://console.cloud.google.com/apis/credentials).
Algo asi deberia de verse:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8nhgjpibrly9hadg4l8k.png)
 

```env
; .env

DATABASE_URL="file:./dev.db"
GOOGLE_CLIENT_ID=<Lo que te tire GCP console>
GOOGLE_CLIENT_SECRET=<Lo que te tire GCP console>
```

```tsx
// pages/index.tsx

import { useSession, signIn, signOut } from "next-auth/react"

export default function Component() {
  const { data: session } = useSession()

  if (session) {
    return <>
      <p>Signed in as <span className='font-bold'>{session!.user!.email}</span></p>
      <button onClick={() => signOut()} className='bg-blue-500 py-1 px-3 text-white rounded'>Sign out</button>
    </>
  }

  return <>
    <p>Not signed in</p>
    <button onClick={() => signIn()} className='bg-blue-500 py-1 px-3 text-white rounded'>Sign in</button>
  </>
}
```

## A echarlo a volar 🚀🚀
Generamos la base de datos
```sh
$ yarn prisma db push
```

Iniciamos el proyecto
```sh
$ yarn start
```

Y listo, tienes tu proyecto con las mejores y mas nuevas tecnologías. Pero que dices? lo llevamos un poco mas allá?

Mucha suerte en tus proyectos y Happy Hacking 🎉🧑‍💻