Prototipo de projecto con JS, Bootstrap, Vite, Deta i Supabase

De Jose Castillo Aliaga
Ir a la navegación Ir a la búsqueda

Para hacer una web moderna hay infinidad de opciones y combinaciones. En el módulo de DWEC de DAW se imparte una porción de lo necesario para hacer la parte del "Frontend" de una aplicación web. Falta, sobretodo, un "Backend". Por eso, este manual pretender dar unas indicaciones mínimas para hacer un prototipo vertical. Lo haremos con unas tecnologías que nos ayudarán a tener un backend mínimo para poder probar nuestras aplicaciones de cliente.

Veamos los requisitos y qué tecnología nos los cubrirá:

  • Una API REST para poder hacer peticiones CRUD a una base de datos relacional: Supabase.
  • Un servidor que nos registre y permita hacer login a los usuarios, además de gestionar el perfil: Supabase y Supabase Storage
  • Un servidor para guardar imágenes o documentos que los usuarios suban a la web: Supabase Storage o Deta Drive.
  • Una librería de estilos para no tener que hacer lo que se hace en DIW todo el tiempo: Bootstrap
  • Un bundle JS para empaquetar todo al pasar a producción: Vite
  • Un servidor en Internet para enviar a producción la web: Deta
  • Un servidor de desarrollo en local que permita hacer empaquetar y refrescar en tiempo real con cada cambio: Vite y Deta
  • Una suite de test: Jasmine. También podría ser Vitest, pero no es el que usa Angular, que es el framework que usaremos más adelante.
  • Algún control de versiones: Git en Github

Ahora argumentaremos los motivos para la elección de estas tecnologías, desde el punto de vista de un profesor o alumno de DWEC:

  • Supabase es un Backend as a Service muy interesante que tiene por debajo una base de datos PostgreSQL, lo que lo convierte en algo muy parecido a lo que puedan hacer en DWES. Tiene su propio SDK (que no usaremos) y una API REST. Usaremos la API REST para que el frontend pueda cambiar de backend más fácilmente, por si se quiere unir al proyecto de DWES. Además, ya nos soluciona todo el tema de la autenticación de usuarios de forma segura y cómoda. Podría ser Firebase, pero una base de datos NoSQL puede marear a los alumnos si no la han tratado todavía.
  • Bootstrap es una librería de estilos y de interfaz. Es muy fácil de usar desde el principio. El objetivo de un proyecto en DWEC no suele ser estético, pero con esta librería al menos no queda demasiado feo.
  • Vite es una herramienta fundamental, ya que empaqueta y sirve los archivos para pasar a producción. Escogemos esta por su facilidad y porque es la que usa Angular a partir de la versión 16.
  • Deta es uno de tantos servicios en la nube para desplegar cómodamente. Ofrece un servicio gratuito bastante completo con frontend y backend (que no usaremos en principio), incluso con base de datos y ficheros. Es un poco raro para empezar a trabajar, pero en realidad en pocos pasos se despliega una web como la que queremos hacer y se puede consultar desde Internet.
  • Jasmine será nuestra suite de test porque es la que usa Angular y porque permite hacer test en el cliente.


Instalación de todo

Este manual pretende ser corto, una guia de referencia. Las descripciones largas y manuales completos estan en cada web oficial.

En nuestro sistema, crearemos una carpeta para ponerlo todo dentro.

Configurar Vite

Manual: [1]

Dentro de esa carpeta, crearemos un proyecto de Vite con su comando:

npm create vite@latest proyecto -- --template vanilla
cd proyecto
npm install

Esta aplicación ya funciona de por sí y la podemos probar con npm run dev, pero primero configuraremos Deta:

Configurar Deta

Manual: [2]

Lo primero es darse de alta en Deta, crear un token y ejecutar los comandos que su manual oficial recomienda:

curl -fsSL https://get.deta.dev/space-cli.sh | sh
space login
space new

Aquí creamos el proyecto de deta.

El fichero principal es Spacefile. En este se definen las distintas partes funcionales de una aplicación web. Empezaremos con un frontend mínimo que crearemos con Vite. Este código servirá:

v: 0
micros:
  - name: frontend
    src: ./proyecto
    engine: static
    primary: true
    commands:
      - npm run build
    serve: dist
    dev: npm run dev -- --port $PORT

Si nos fijamos, veremos que el frontend estará en la carpeta proyecto y que, para poner en producción, se ejecutará npm run build, que es el comando que necesita Vite para poner el producción.

Hay que tener en cuenta que aquí hay dos servidores de desarrollo. El de Deta y el de Vite. El que pondremos en funcionamiento es el de Deta, ya que permitirá la comunicación con un backend y con el servicio de Deta. Este pone el marcha el de Vite mediante su comando dev

Si queremos ponerla ya en producción en el servidor en la nube, pondremos:

space push

Si funciona, ya podemos añadir ese proyecto a nuestro Horizon, que es como un escritorio virtual que tiene Deta. También la podemos acceder a la aplicación en su propia URL una vez publicada.

Configurar Boostrap

Manual: [3]

Boostrap y Vite funcionan perfectamente juntos. Boostrap necesita que se importe su scss y su librería javascript, por lo que ejecutaremos dentro de la carpeta proyecto:

npm i --save bootstrap @popperjs/core
npm i --save-dev sass

Crearemos un fichero styles.scss con este contenido:

@import "../node_modules/bootstrap/scss/bootstrap";

Finalmente, en main,js o el que sea el fichero principal de .js:

import './styles.scss'
import * as bootstrap from 'bootstrap'

Configurar Supabase

Aunque Deta tenga su base de datos, esta es NoSQL. Por otra parte, no está preparado específicamente para gestionar usuarios. Por eso, podemos usar Supabase como Backend as a Service. De hecho, podría hacerse un proyecto sin Deta, usando Supabase como único Backend. Pero en ese caso, se necesitaría un servidor HTTP para servir el Frontend. En resumen, algunas de las posibles arquitecturas que se pueden hacer:

 ------------
|    DETA    | HTML, CSS, JS    -------------       Usuarios, JSON         ----------
|  Frontend  | --------------->| Cliente Web | <------------------------> | Supabase |  
|    Vite    |                  -------------     CRUD API REST            ----------
 ------------
--------------------------
| Azure, AWS, Hosting... |
|  ------------          |
| |   Apache   |         |   HTML, CSS, JS   -------------       Usuarios, JSON         ----------
| |  Frontend  |         |  --------------->| Cliente Web | <------------------------> | Supabase |  
| |    Vite    |         |                   -------------     CRUD API REST            ----------
|  ------------          |
 ------------------------
 ------------
|   DETA     | HTML, CSS, JS    -------------      
|  Frontend  | --------------->| Cliente Web |
|    Vite    |                  -------------
|  Backend   |   API REST CRUD        |
|  Node.js   | <-----------------------
| Deta Base  |   Usuarios(más difícil)          
 ------------
 ------------
|    DETA    | HTML, CSS, JS    -------------                               ----------
|  Frontend  | <--------------->| Cliente Web |                            | Supabase |   <-----
|    Vite    |    API REST       -------------                              ----------         |
| Node.js    | <--------------------------------------------------------------------------------
 ------------                    API REST o SDK, Usuarios, JSON     

Este manual está pensado para la primera situación. Esta puede ser ampliada con nuevas conexiones en un futuro, si se necesita calcular alguna cosa en backend que no pueda hacerse en Supabase.

Para comenzar, nos damos de alta en Supabase, creamos un nuevo proyecto y, dentro de él, las tablas que queremos consultar.

Las tablas, inicialmente, son accesibles con la API Key pública. Si queremos establecer políticas de seguridad, debemos crear reglas Row Level Security (RLS). El manual de Supabase es muy bueno en ese sentido.

Otra cosa que se recomienda hacer es habilitar la autenticación, al menos por correo y contraseña. Esta funciona con un token que se envía al hacer login. Tanto el login como el registro se hacer fácilmente mediante peticiones a su API REST.

Para hacer las peticiones al API REST, entraremos en la sección API Docs y miraremos los ejemplos que auto documenta Supabase para cada tabla y para la autenticación. En vez de mirar el ejemplo en JS, lo miraremos en Bash. Esa petición Bash (con curl) no usa el SDK, por lo que se parece más a lo que podemos hacer en Postman o con fetch. Aquí hay un ejemplo de una "traducción" de Bash a JS Vanilla:

curl 'https://bqhnvwfovmcxrqrsmfxr.supabase.co/rest/v1/graphs?select=id' \
-H "apikey: eyJhbGciOiJIUzI1NiIsI...k4MTg1NTgwNn0.jVhmEO__GFSxqRlbzdCxyeb_VxWWD7Bqk9sj3Po8xtM" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpX...cCI6MTk4MTg1NTgwNn0.jVhmEO__GFSxqRlbzdCxyeb_VxWWD7Bqk9sj3Po8xtM"
fetch('https://bqhnvwfovmcxrqrsmfxr.supabase.co/rest/v1/graphs',{
           method: 'get',
           headers: {
               "apiKey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS...HJxcnNtZnhyIiwicm9sZSI6ImFu...4MTg1NTgwNn0.jVhmEO__GFSxqRlbzdCxyeb_VxWWD7Bqk9sj3Po8xtM",
               "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzd...yNzk4MDYsImV4cCI6MTk4MTg1NTgwNn0.jVhmEO__GFSxqRlbzdCxyeb_VxWWD7Bqk9sj3Po8xtM"
           }
       })
Puesto que se trata de un proyecto educativo, no usaremos el SDK por dos razones: Para no depender de este servicio y para aprender a usar una API REST. Puesto que casi nadie usa supabase si el SDK, es más difícil de encontrar manuales y también de que te ayude la IA.


Configurar Jasmine

Jasmine tiene muchas maneras de ser usado. Normalmente es una herramienta que ejecutamos en tiempo de desarrollo, por lo que no debería subir a producción.

Puesto que estamos haciendo una web desde el punto de vista del frontend, necesitamos el jasmine-browser-runner. Otra cosa a tener en cuenta que es desarrollamos con módulos ESM, por lo que hay que hacer el init con --esm.

Estos serían los pasos para instalarlo en desarrollo de la manera más simple:

Asegurarse de que en package.json está esta línea:

"type" :"module"
npm install jasmine-browser-runner jasmine-core
npx jasmine-browser-runner init --esm

En ./spec/spec.mjs :

import { createArray } from "../src/functions.js";

describe('Array', function() {
   describe('createArray', function() {
     it('should return [0,0,0]', function() {
       expect(createArray(3)).toEqual([0,0,0]);
     });
   });
  });

En ./src/functions.js :

export {createArray}
function createArray(n) {
   return Array(n).fill(0);
}
npx jasmine-browser-runner serve

De esta manera, podemos ven en la url que nos proporciona el resultado de los tests.

Configurar Jasmine en producción

Ahora vamos a hacer un paso opcional y no recomendable. Vamos a publicar los tests también en el servidor de producción. No sería recomendable en cualquier otra situación, pero por motivos didácticos, es cómodo ver si se pasan los tests en la misma web.

Jasmine se puede ejecutar con jasmine-browser-runner fácilmente en el entorno de desarrollo, pero en producción hay algo que falla en Deta. Puede que sea por la versión de Node o porque es un sistema de ficheros de sólo lectura. Así que descartamos esa solución. Tenemos que recurrir a la otra opción sencilla, aunque menos elegante, que es la versión Standalone. Al no requerir Node, funciona. Pero hay que hacer algunos pasos:

Descargamos la última versión Standalone de Jasmine y la colocamos en una carpeta de nombre, por ejemplo, webtests. Esta carpeta ha de estar dentro de la de Deta, pero fuera de la del proyecto Vite. A esa carpeta le podemos eliminar los ficheros de tests i ejemplos de código que vienen con ella.

Luego modificamos el SpecRunner.html para que tenga de nombre index.html. Le cambiaremos las rutas de los ficheros. En nuestro ejemplo funciona este html:

  <link rel="shortcut icon" type="image/png" href="./lib/jasmine-5.1.2/jasmine_favicon.png">
  <link rel="stylesheet" href="./lib/jasmine-5.1.2/jasmine.css">

  <script src="./lib/jasmine-5.1.2/jasmine.js"></script>
  <script src="./lib/jasmine-5.1.2/jasmine-html.js"></script>
  <script src="./lib/jasmine-5.1.2/boot0.js"></script>
  <!-- optional: include a file here that configures the Jasmine env -->
  <script src="./lib/jasmine-5.1.2/boot1.js"></script>
  <!-- include source files here... -->
  <script type="module" src="/src/functions.js"></script>
  <!-- include spec files here... -->
  <script type="module" src="/spec/spec.mjs"></script>

Para que estas rutas funcionen hay que declararlas en Spacefile:

v: 0
micros:
  - name: frontend
    src: ./proyecto
    engine: static
    primary: true
    commands:
      - npm run build
    serve: dist
    dev: npm run dev -- --port $PORT
  - name: test
    src: ./webtests
    engine: static
    path: testing
    serve: .
    public_routes:
      - "/lib" 
  - name: source_code
    src: ./proyecto/src
    engine: static
    path: src
    serve: .
  - name: specs
    src: ./proyecto/spec
    engine: static
    path: spec
    serve: .

Se debe publicar src y spec' porque en el entorno de producción esas carpetas desaparecen del build de Vite. También publicamos webtests indicando que la carpeta lib es pública, para que pueda acceder a la librería.