materials

Vite

Introducción

Cuando crece el tamaño de un proyecto y tenemos más ficheros de código (cómo al trabajar con clases) es necesario organizarlos de forma que sea fácil encontrarlos y que no haya problemas de dependencias.

Sin embargo tener muchos ficheros hace que tengamos que importarlos todos, y en el orden adecuado, en nuestro index.html (mediante etiquetas <script src="...">) lo que empieza a ser engorroso y reduce el rendimiento al tener el navegador que hacer muchas peticiones HTTP.

Además muchas veces incluimos en el código características del lenguaje que aún no están soportadas por todos los navegadores.

Para evitar este problema se utilizan las herramientas de construcción de proyectos o module bundlers que unen todo el código de los distintos ficheros javascript en un único fichero que es el que se importa en el index.html y hacen los mismo con los ficheros CSS.

Además proporcionan otras ventajas:

Nosotros usaremos el bundler Vite que es el más usado en entorno frontend y mejora el rendimiento de su predecesor webpack. Proporciona:

Para poder usar Vite debemos instalarlo. Como lo usaremos en muchos proyectos lo podemos instalarlo global con

npm install -g vite

Crear un nuevo proyecto

Vite se utiliza con npm que es el gestor de paquetes de Node.js por lo que debemos tenerlo instalado. Para crear un nuevo proyecto haremos:

npm create vite@latest

Al crear el proyecto nos pregunta qué framework vamos a utilizar (le diremos que Vanilla, es decir, Javascript sin framework) y si como lenguaje usaremos Javascript o Typescript.

Esto crea un directorio con el nombre de nuestro proyecto que contiene el scaffolding del mismo, con la siguiente estructura: Esto crea una carpeta con la siguiente estructura:

nombre-proyecto/
├── index.html
├── package.json
├── public/
└── src/
    ├── main.js
    ├── style.css
    └── assets/
        └── vite.svg

Lo que tenemos en cada uno de los ficheros y carpetas es:

NOTA: todos los ficheros javascript de un proyecto con Vite son módulos y en ellos, igual que en las clases, no es necesario poner 'use strict' porque por defecto los módulos ya funcionan así.

package.json

Aquí se configura nuestra aplicación. Contiene varios apartados importantes:

Añadir nuevas dependencias

Si queremos usar un nuevo paquete en nuestra aplicación lo instalaremos con npm:

npm install nombre-paquete

Este comando además de instalar el paquete en node-modules lo añade a las dependencias del package.json. La opción --save o -S lo añadirá como dependencia de producción y --dev o -D como dependencia de desarrollo. Si no ponemos nada se añade como una dependencia de producción. Ej.:

npm install -S bootstrap

Para usarlo debemos importarlo y registrarlo tal y como se indique en su documentación. Lo normal es hacerlo en el main.js (o en algún fichero JS que importemos en main.js como en el caso de los plugins) si queremos poder usarlo en cualquier módulo.

Desarrollar nuestro proyecto

Para empezar a trabajar ejecutamos desde la terminal el script

npm run dev

Este script de Vite funciona como ya vismo en el bloque de Javascript: compila el código, muestra si hay errores, lanza un servidor web (normalmente en el puerto 5173) y carga el proyecto en el navegador (http://localhost:5173). Si cambiamos cualquier fichero del directorio src recompila y recarga la página automáticamente.

Módulos: import y export

Una de las razones de usar un bundler es que podemos repartir el código entre varios ficheros de forma que quede más organizado. Con Vite podemos dividir nuestro código en ficheros y comunicarlos usando la sintaxis estándar de módulos ES.

Para que un fichero pueda tener acceso a código de otro fichero hay que hacer 2 cosas:

  1. El fichero al que queremos acceder debe exportar el código que desea que sea accesible desde otros ficheros
  2. El fichero que quiere acceder a ese código debe importarlo a una variable

ES6 nos proporciona 2 formas de exportar/importar código:

Named export

De esta manera puedo exportar tantos elementos (funciones, variables, clases, …) de un fichero como quiera. Por ejemplo, si es un fichero con una única función a exportar:

// Fichero cuadrado.js
export function cuadrado (value) {
  return value * value
}

En el caso de querer exportar muchas funciones lo más sencillo es exportarlas juntas en un objeto como en el fichero functions.js:

function letras () {
  ...
}

function palabras () {
  ...
}

function maysc () {
  ...
}
...
export {
	letras,
	palabras,
	maysc
}

Para importarlo lo hacemos poniendo lo que queremos importar entre { }. Si se trata de una única función:

import { cuadrado } from './cuadrado.js'

console.log('El cuadrado de 2 es ' + cuadrado(2))

También podríamos usar un nombre diferente para lo que importamos:

import { cuadrado as cuad} from './cuadrado.js'

console.log('El cuadrado de 2 es ' + cuad(2))

Si es un fichero con muchas funciones exportadas a un objeto podemos importar sólo las que queramos o todas:

import { letras, maysc } from './functions.js'

console.log('Las letras de "Hola" son ' + letras("Hola"))

También podemos importarlas todas a un objeto sin indicar sus nombres, con *:

import * as myFunctions from './functions.js'

console.log('Las letras de "Hola" son ' + myFunctions.letras("Hola"))

Default export

De esta manera sólo puedo exportar un elemento por fichero, y a la hora de importarlo le doy el nombre que quiera. Por ejemplo, si es un fichero con una única función a exportar:

// Fichero cuadrado.js
export default function cuadrado (value) {
  return value * value
}

Y donde vaya a usarlo:

import myCuadrado from './cuadrado.js'

console.log('El cuadrado de 2 es ' + myCuadrado(2))

En el caso de una clase normalmente se hará de esta manera, exportando la clase por defecto:

export default class Product {
    constructor() {

    }
    ...
}

Y para importarla:

import Product from './product.class'

const myProd = new Product()

En resumen, si exporto con export importo con { } y si exporto con export default importo sin { } pero sólo puedo exportar 1 elemento.

Imágenes

Si se trata de imágenes estáticas lo más sencillo es ponerlas dentro de la carpeta public y hacer referencia a ellas usando ruta absoluta. Todo lo que está en public se referencia como si estuviera en la raíz de nuestra aplicación:

<img src="/vite.png" height="100px" alt="Logo de Vite">

También podemos poner las imágenes en la carpeta assets, pero antes de usarlas deberemos imnportarlas. Ejemplo:

import viteLogo from './assets/vite.png'
...
const logoHtml = `<img src="${viteLogo}" height="100px" alt="Vite logo">`
document.body.prepend(logoHtml)

Con Vite también podemos importarlas usando import.meta.url, lo que es útil si no conocemos previamente el nombre del fichero con la imagen (más información en la documentación de Vite):

function getImage(fileName, height, alt) {
  const imgUrl = new URL(fileName, import.meta.url).href
  const imgHtml = `<img src="${imgUrl}" height="${height}" alt="${alt}">`
  
  return imgHtml
}

Ejemplo: new URL(“../assets/logo.png”, import.meta.url).href // → “http://localhost:5173/assets/logo.png”

Bootstrap

Para usar Bootstrap en nuestro proyecto con Vite debemos instalarlo como dependencia de producción:

npm install bootstrap

y luego importarlo en nuestro fichero main.js, preferiblemente antes de importar nuestro propio CSS para que nuestras reglas tengan prioridad:

import 'bootstrap/dist/css/bootstrap.min.css'

Iconos

Para usar los iconos de Bootstrap debemos instalarlos:

npm install bootstrap-icons

y luego importarlos en nuestro fichero main.js:

import 'bootstrap-icons/font/bootstrap-icons.css'

Para usarlos en nuestro código HTML:

<i class="bi bi-alarm"></i>

Para más información sobre los iconos de Bootstrap podéis consultar la documentación oficial.

Variables de entorno

A veces necesitamos guardar valores que cambian entre entornos (desarrollo, producción): URLs de APIs, claves, etc. Para eso usamos ficheros .env:

# fichero .env
VITE_API_URL=https://api.ejemplo.com
VITE_API_KEY=mi-clave-secreta

IMPORTANTE: en Vite todas las variables de entorno que queramos usar en el código deben empezar por VITE_. Las accedemos así:

const url = import.meta.env.VITE_API_URL

El fichero .env nunca se sube a Git si contiene información sensible. En su lugar se sube un .env.example con los nombres de las variables pero sin los valores reales.

Paso a producción

Cuando lo hayamos acabado y queramos subirlo a producción ejecutaremos

npm run build

que crea la carpeta /dist con los ficheros que debemos subir al servidor web de producción:

Testear el proyecto

Si queremos testear el proyecto deberemos usar una herramienta de testing y crear los tests adecuados. Lo más sencillo es usar Vitest que es muy similar a Jest pero preparado para interacutar fácilmente con Vite.

Lo primero es importarlo como dependencia de desarrollo (no lo usaremos en producción)

npm install --save-dev vitest

o abreviado

npm i -D vitest

Debemos añadir un nuevo script en el package.json que le indique a vite que queremos usarlo para testear:

  "scripts": {
		...
    "test": "vitest"
  },

Crearemos los tests en una carpeta en la raíz de nuestro proyecto llamada /test y en ella crearemos los diferentes fichero cuya extensión será .spec.js o .test.js. Cada vez que queramos pasar los tests ejecutaremos

npm run test

Podéis obtener más información en infinidad de páginas de internet, como el Curso DWEC de Jose Castillo, y en la web oficial de vite.