Skip to content

Proyecto Astro + Tailwind + Vue + Supabase

Esta guía te muestra cómo configurar un proyecto completo con Astro, TailwindCSS, Vue y Supabase desde cero.

Primero, genera el proyecto base:

Terminal window
npm create astro@latest mi-proyecto-astro
cd mi-proyecto-astro

Selecciona en el asistente:

  • Template: Empty o Minimal
  • TypeScript: Yes (recomendado)
  • Install dependencies: Yes
  • Git repository: Yes (opcional)

Agrega TailwindCSS al proyecto:

Terminal window
npx astro add tailwind

Agrega la integración de Vue:

Terminal window
npx astro add vue

Esto instalará:

  • @astrojs/vue
  • vue

Y actualizará automáticamente tu astro.config.mjs.

Abre astro.config.mjs y verifica que tenga ambas integraciones:

astro.config.mjs
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';
import tailwind from '@astrojs/tailwind';
export default defineConfig({
integrations: [vue(), tailwind()],
});

Instala el cliente de Supabase:

Terminal window
npm install @supabase/supabase-js

  1. Ve a https://supabase.com
  2. Crea una cuenta o inicia sesión
  3. Crea un nuevo proyecto:
    • Nombre del proyecto
    • Contraseña de base de datos
    • Región (elige la más cercana)

En el SQL Editor de Supabase, ejecuta:

create table mensajes (
id uuid primary key default uuid_generate_v4(),
texto text not null,
autor text not null,
created_at timestamp with time zone default timezone('utc'::text, now()) not null
);
-- Insertar datos de ejemplo
insert into mensajes (texto, autor) values
('¡Hola Mundo desde Supabase!', 'Sistema'),
('Vue + Astro funcionando perfectamente', 'Admin');

Copia tus claves desde Project Settings → API:

  • URL del proyecto
  • anon/public key

Crea un archivo .env en la raíz del proyecto:

.env
PUBLIC_SUPABASE_URL=https://tu-proyecto.supabase.co
PUBLIC_SUPABASE_ANON_KEY=tu-clave-publica-aqui

Crea el archivo src/lib/supabaseClient.ts:

src/lib/supabaseClient.ts
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.PUBLIC_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.PUBLIC_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);

Crea src/components/HolaMundo.vue:

src/components/HolaMundo.vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { supabase } from '../lib/supabaseClient'
interface Mensaje {
id: string
texto: string
autor: string
created_at: string
}
const mensajes = ref<Mensaje[]>([])
const loading = ref(true)
const error = ref('')
const cargarMensajes = async () => {
try {
loading.value = true
const { data, error: supabaseError } = await supabase
.from('mensajes')
.select('*')
.order('created_at', { ascending: false })
if (supabaseError) throw supabaseError
mensajes.value = data || []
} catch (err) {
error.value = 'Error al cargar mensajes'
console.error(err)
} finally {
loading.value = false
}
}
onMounted(() => {
cargarMensajes()
})
</script>
<template>
<div class="max-w-2xl mx-auto p-6">
<div class="bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg shadow-xl p-8 text-white mb-6">
<h1 class="text-4xl font-bold mb-2">🚀 Hola Mundo</h1>
<p class="text-lg opacity-90">Astro + TailwindCSS + Vue + Supabase</p>
</div>
<div class="bg-white rounded-lg shadow-lg p-6">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">📝 Mensajes desde Supabase</h2>
<div v-if="loading" class="text-center py-8">
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500 mx-auto"></div>
<p class="mt-4 text-gray-600">Cargando mensajes...</p>
</div>
<div v-else-if="error" class="bg-red-50 border border-red-200 rounded-lg p-4 text-red-700">
❌ {{ error }}
</div>
<div v-else-if="mensajes.length === 0" class="text-center py-8 text-gray-500">
No hay mensajes disponibles
</div>
<ul v-else class="space-y-3">
<li
v-for="mensaje in mensajes"
:key="mensaje.id"
class="border-l-4 border-blue-500 bg-gray-50 p-4 rounded-r-lg hover:bg-gray-100 transition"
>
<p class="text-gray-800 font-medium">{{ mensaje.texto }}</p>
<p class="text-sm text-gray-500 mt-1">— {{ mensaje.autor }}</p>
</li>
</ul>
<button
@click="cargarMensajes"
class="mt-6 w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-lg transition shadow-md hover:shadow-lg"
>
🔄 Recargar Mensajes
</button>
</div>
</div>
</template>

Edita src/pages/index.astro:

src/pages/index.astro
---
import HolaMundo from '../components/HolaMundo.vue';
---
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Astro + Vue + Supabase</title>
</head>
<body class="bg-gray-100 min-h-screen py-8">
<HolaMundo client:load />
</body>
</html>

Terminal window
npm run dev

Abre tu navegador en:

👉 http://localhost:4321


Limpia e reinstala dependencias:

Terminal window
rm -rf node_modules
npm install

En Windows:

Terminal window
rmdir /s /q node_modules
npm install

Verifica que:

  1. Las variables en .env sean correctas
  2. La tabla mensajes exista en Supabase
  3. Las políticas RLS (Row Level Security) permitan lectura pública:
alter table mensajes enable row level security;
create policy "Permitir lectura pública"
on mensajes for select
using (true);

Asegúrate de usar client:load en el componente:

<HolaMundo client:load />


Avanzado
  • Implementar autenticación con Supabase Auth
  • Crear formularios para insertar datos
  • Agregar suscripciones en tiempo real
  • Configurar políticas de seguridad (RLS)
  • Desplegar en Vercel o Netlify
🐝