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 y cuantos más código usemos más se reduce el número de nevegadores que soportan nuestro código.
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, junto con webpack, son los más usados en entorno frontend. Junto a npm tendremos una forma fácil y práctica de empaquetar el código.
Además Vite incorpora un servidor de desarrollo para hacer más cómoda la creación y prueba de nuestros proyectos.
Para poder usar Vite debemos instalarlo. Como lo usaremos en muchos proyectos lo podemos instalarlo global con
npm install -g vite
Vite necesita Node.js versión 16 o superior aunque lo mejor es tenerlo actualizado para poder utilitzar todas sus plantillas. Para crear un nuevo proyecto haremos:
npm create vite@latest
(si no tenemos instalado el paquete create-vite nos preguntará si lo instala)
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 el scaffolding de nuestro proyecto que consiste en una carpeta con el mismo nombre que el proyecto y una serie de ficheros en su interior: Nos preguntará el nombre del proyecto, la plantilla (Vanilla para Javascript sin framework) y el lenguaje que queremos usar (Javascript/Typescript) y se crea una carpeta con el nombre de nuestro proyecto que contiene:
index.html
: html con un div con id app que es donde se cargará la app y una etiqueta script que carga un módulo llamado main.js
main.js
: es el punto de entrada a la aplicación .Importa los ficheros CSS, imágenes y ficheros JS con funciones o clases y establece el contenido de la página principalcounter.js
: módulo JS que exporta una función como ejemplo que es usada en el main.jsstyle.css
: fichero donde poner nuestros estilos, con CSS de ejemplopublic/
: carpeta donde dejar elementos estáticos que no pasarán por vite (como imágenes, ficheros CSS, …)node_modules
: librerías de las dependencias (si usamos alguna)package.json
: fichero de configuración del proyecto. Además del nombre y la versión incluye apartados importantes:
devDependences
: dependencias que se usan en desarrollo pero que no se incorporarán al código finaldependences
: dependencias que sí se incluirán en el código final (librerías que estemos usando)scripts
: para ejecutar el servidor de desarrollo (npm run dev
), generar el código final de producción (npm run build
) y previsualizarlo en modo producción (npm run preview
). Podemos añadir más para tests, etcSi nuestra aplicación no va a ser muy pequeña como la del ejemplo sino que tendrá diferentes ficheros Javascript, acceso a datos, interfaz de usuario, etc deberíamos organizar en código en carpetas para mejorar su legibilidad. Lo adecuando es dejar en el raíz de nuestro proyecto los ficheros index.html
y main.js
y crear una carpeta src
donde poner el resto de código. En función del tamaño de la aplicación podríamos crear dentro subcarpetas (os propongo un nombre para ellas aunque podéis llamarlas como queráis) para:
model
: el modelo de datos, es decir, las clasespages
o views
: las páginas que tendrá nuestra SPA a las que se navega desde el router (aunque en realidad sólo hay una)api
: acceso a la API que usemos. Sólo deben conectarse al servidor y transmitir los datos recibidos al resto de la aplicacióncomponents
: web components que usemos para cosntruir las páginasservices
: métodos síncronos que proporcionan funcionalidadusecases
donde guardarlos. Cada uno debería tener un único método llamado run
o execute
test
: carpeta donde guardar los ficheros de testNOTA: 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í.
Para empezar a trabajar ejecutamos desde la terminal el script
npm run dev
Esto hace que Vite lance un servidor web en el puerto 5173 donde podemos ver la ejecución de nuestro proyecto.
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.
Para que un fichero pueda tener acceso a código de otro fichero hay que hacer 2 cosas:
Esto es lo que hacíamos en el ejercicio de la frase para poder pasar los tests y lo que haremos con los ficheros donde declaremos clases.
ES6 nos proporciona 2 formas de exportar/importar código:
export
export default
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
}
Si es un fichero que define una clase la exportamos tal cual:
export class Product {
constructor() {
}
...
}
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"))
Para importar una clase:
import { Product } from './product.class'
const myProd = new Product()
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:
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.
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) {
imgUrl = new URL(fileName, import.meta.url).href
const imgHtml = `<img src="${viteLogo}" height="${height}" alt="${alt}">`
return logoHtml
}
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:
index.html
assets
con
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 producción (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.