El frontend cambia muchísimo, cada día salen frameworks nuevos, herramientas,… y por ello estar al día de todo es imposible. Pero eso no deja de lado que me apetezca mejorar mis habilidades de frontend y aprender un un poco como se trabaja con javascript más hallá de JQuery y de hacer Stackoverflow Driven Development.

Así que me he propuesto ir aprendiendo VueJS, porque creo que tiene una curva de aprendizaje bastante asequible y voy a ver resultados pronto sin demasiada frustración. Además hace tiempo que me encontré con este magnifico libro «Desarrolla aplicaciones con VueJS«, con el curso de CodelyTV sobre hacer TDD con VueJS y Jest y tuve la suerte de cruzarme con Dani Latorre de coding stones en la conferencia «Madrid Software Crafters» y charlar sobre VueJS, frontend actual y las charla que dieron en Codemotion.
Bueno pues es hora de empezar a darle caña a VueJS, la idea del post de hoy es montar un pequeño escaparate de productos, algo así como una tienda online pero sin botón de comprar y sin llamadas a ninguna API. El objetivo es crear una aplicación en VueJS, con una jerarquía de componentes (un componente padre y al menos un hijo) y familiarizarnos con la manera de crear compoentes y la estructura de un proyecto en VueJS.
Para desarrollar vamos a utilizar WebStorm, pero podría hacerse con Siblime o similar porque el objetivo es familiarizarnos con todo esto del frontend.
Lo primero es crear la estructura de carpetas del proyecto, para ello lo mejor es
utilizar vue-cli, para ello instalamos la herramienta desde un terminal y con la opción -g hacemos que sea global (que se pueda ejecutar en cualquier carpeta.
npm install -g vue-cli
Creamos una carpeta, que será donde tengamos el proyecto y ejecutamos vue-cli
mkdir aprendiendoVUEJS
cd aprendiendoVUEJS
vue init webpack-simple .
y seguimos las instrucciones de poner el nombre del proyecto y todo lo demás.
Al terminar tendremos una serie de ficheros, los más importantes son:
- package.json es como composer.json de PHP, es donde están todas las dependencias del proyecto. También es donde podemos crear scripts para automatizar procesos, ahora tenemos 2 scripts
dev
ybuild
- webpack.config.js es la configuración de webpack, el encargado de tratar con el JS, unirlos, mininimificarlo,…
- La carpeta src que es donde estará el código de nuestra aplicación, ahora tenemos un pequeño ejemplo.
- index.html que es el punto de entrada de la aplicación.
Lo primero que tenemos que hacer es instalar todas las dependencias con npm
npm install
Una vez que ha terminado, se habrá creado un fichero package-lock.json que es parecido a composer.lock y además tendremos una carpeta node_modules con todas las dependencias. Ahora ejecutando npm run dev
se abrirá el navegador en http://localhost:8080 y aparecerá la página de VueJS de ejemplo funcionando.
¡Ya tenemos un ejemplo hecho en VueJs! Ahora vamos a seguir ampliándolo un poco.
Vamos a sacarle un poco más de partido a Vue añadiendo unos módulos muy útiles: vue-router y vuex.
- vue-router: nos permite definir rutas para manejar dinámicamente los componentes de nuestra aplicación.
- vuex: es un adminitrador de estados. Está inspirado en redux y lo que nos permite es que los componentes vayan cambiando de estado.
- vuex-router-sync: sirve para inyectar información parte de la información de nuestro enrutador directamente en nuestro estado vuex, tranquilos, de momento lo instalamos que usandolo se e más fácil.
- copy-webpack-plugin: para copiar los assets de un sitio a otro fácilmente
Suena complicado, pero no os preocupéis, poco a poco vamos a ir viendo como utilizarlos e integrándolos en nuestros componentes. Para instalarlos:
npm install --save vue-router
npm install --save vuex
npm install --save vuex-router-sync
npm install --save copy-webpack-plugin
La opción --save
es para que npm descargue la ultima versión estable.
Empezando a escribir código
Ya tenemos todo instalado, ahora es hora de empezar a escribir código. La idea es hacer un pequeño catalogo online para así aprender un poco de Vue, routing y Vuex.
Como es una aplicación de ejemplo no vamos a liarnos usando una api externa, así que vamos a tener datos estáticos en un fichero. Para ello vamos a crear en src una carpeta llamada store y dentro un fichero llamado state.js que contendrá un array con los datos que mostraremos en el catálogo
export const state = {
products: [
{
id: 1,
name: 'Tortas Inés Rosales',
price: 80.00,
description: 'Tortas de Aceite Inés rosales',
image: '/dist/images/products/tortas.jpg'
},
{
id: 2,
name: 'Mojama',
price: 120.00,
description: 'Mojama de Atún',
image: '/dist/images/products/mojama.jpg'
},
{
id: 3,
name: 'Vino',
price: 100,
description: 'Vino de naranja',
image: '/dist/images/products/vino_naranja.jpg'
}
]
}
Este fichero será como nuestra “base de datos”, en una aplicación real aquí podríamos montar las llamadas a una API.
Las fotos de nuestros productos las pondremos en una carpeta llamada /dist/images/products/
, si preferimos podemos utilizar url’s de imágenes o algún servicio de imágenes ramdom como https://picsum.photos/200/300/?random
Ahora dentro de store creamos un fichero llamada getters.js que es donde vamos a definir nuestras funciones de búsqueda
export const getters = {
getProductById: (state, getters) => (id) => {
return state.products.find(product => product.id == id)
}
}
En un primer momento solo vamos a tener una búsqueda por id, así que lo que definimos es la función getProductById
Esta función busca dentro del array de products el product que coincida con el id
Por último creamos index.js dentro de store que es donde unimos el fichero state.js y getters.js
import Vue from 'vue'
import Vuex from 'vuex'
import { state } from './state.js'
import { getters } from './getters.js'
Vue.use(Vuex)
export default new Vuex.Store({
state,
getters
})
Para ampliar más información: https://medium.com/js-dojo/vuex-for-the-clueless-the-missing-primer-on-vues-application-data-store-33fa51ffc3af
Ya tenemos a Vuex funcionando, ahora vamos a por las rutas.
Construyendo las rutas
Básicamente vamos a tener una homepage con el listado de productos y tendremos también otra página para cada producto en detalle.
Así que registraremos 2 rutas.
Para ello creamos un directorio llamado router y dentro un fichero index.js
import VueRouter from 'vue-router'
import Vue from 'vue'
import ProductDetails from './../components/ProductDetails.vue'
import Home from './../components/Home.vue'
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{ path: '/products/:id', component: ProductDetails },
{ path: '/', component: Home },
]
})
Instanciamos un nuevo VueRouter y añadimos las 2 rutas y que componente se instancia en cada ruta.
Todavía no hemos creado ni un componente, pero no tenemos que preocuparnos.
Uniéndolo todo
Ya tenemos store y router así que ahora tenemos que unirlo todo. Para ello editamos el fichero main.js que viene incluido en el ejemplo.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { sync } from 'vuex-router-sync'
import store from './store'
sync(store, router)
new Vue({
store,
router,
render: h => h(App)
}).$mount('#app')
Lo que estamos haciendo es crear una nueva app de Vue que colgará de un div que tanga un id #app
Creando los componentes
Así que ahora viene lo divertido y es crear los componentes. Tenemos los datos de los productos en state y tenemos 2 rutas una principal y otra de detalle creadas en route , así que vamos a crear 3 componentes:
- Home: que será el componente principal
- Product: que será un componente hijo de Home para ver los productos en la pagina principal.
- ProductDetail: que será el componente donde mostremos toda la información en detalle.
- TopContext: será el componente de arriba
Un pequeño esquema de como quedará todo sería más o menos así:
Dentro de la carpeta components vamos a crear los 4 componentes:
Top Context
Nuestro primer componente será solo un link a la página principal
<template>Vue.js Demo Store</div> </template> export default { name: 'TopContext', }
Como vemos todos los componentes siempre tienen una parte template que es donde se escribe el HTML y/o codigo VueJS de templates (v-if, v-for, router….) y otra parte script que es donde escribimos el código javascript de ese componente.
En este caso en la parte de script solo declaramos un nombre. en la parte de template lo único que estamos haciendo es llamar a router y decirlo que queremos ir a la ruta / siempre.
ProductDetails
Ahora vamos con el componente de ProductDetails donde vamos a mostrar todos los datos que guardamos el el fichero state.js
<template>
{{ product.name }} {{product.description}} Su precio aproximado es de {{product.price}}$</div> </template> export default { name: 'ProductDetails', computed: { id () { return this.$store.state.route.params.id }, product () { return this.$store.getters.getProductById(this.id) }, }, }En la parte script lo que tenemos son 2 funciones, una llamada id que lo que devolver el id del producto que viene a través de la URL y otra llamada product que devuelve el elemento que tenemos guardado en el array.
Por otro lado tenemos el template que lo único que hace es ir mostrando los datos del producto en elementos html usando la sintaxis de VueJS.HomePage
Este componente lo que hace es iterar por elarray de producot e ir llamando al componente Product.
<template></div> </template> import Product from './../components/Product.vue' export default { name: 'home', components: {Product}, computed: { products () { return this.$store.state.products }, }, }Tenemos la función product() que devuelve los productos almacenados, lo que hacemos es ir iterando los productos y llamar al componente Product
Product
Este componente solo imprime algunos datos de un producto y llama a Vue-router para generar la ruta hacia el detalle de producto.
<template></template> export default { name: 'Product', props: ['product'], computed: { url () { return `/products/${this.product.id}` }, }, }{{ product.name }} Ver
En la parte de script tenemos declarada una función que devuelve URL relativa hacia el producto.
Creando la App de Vue
Tenemos 4 componentes, que en realidad no hacen nada. Tenemos que modificar la App de Vue (App.vue) para indicarle al framework que componentete instanciar.
Por lo que abrimos el fichero App.vue y escribimos<template></template> import TopContext from './components/TopContext.vue' export default { name: 'app', components: {TopContext}, }El componente TopContext no es realmente importante; solo actúa como una cabecera.
La parte clave es el router-view one.Para que todo termine de funcionar tenemos que hacer que las imágenes se copien, para ello solo tenemos que configurar el
pluginCopyWebpackPlugin
que instalamos al principio. Abrimoswebpack.config.js
y justo antes de ‘resolve’ copiamosplugins: [ new CopyWebpackPlugin([{ from: 'src/static',to:'images' }]), ],
Todo está listo para empezar a funcionar. Solo tenemos que ejecutar
npm run dev
y listo se abrirá el navegador y veremos algo como esto así:
El proyecto está alojado en GitHub https://github.com/go-to-next-level/learning-VueJS y como solo tenemos HTML, javascript y CSS podemos alojarlo en github pages en https://go-to-next-level.github.io/learning-VueJS
Conclusiones
Es un primer acercamiento a VueJS. Después de haber leído unos cuantos tutoriales y revisar el típico ejemplo de TodoList no terminaba de quedarme claro como hacer una pequeña app desde 0 con sus dependencias y demás. Además estaba algo abrumado por la cantidad de documentación, librerías, tooling, post… por la mucha información que hay sobre JS y con la cantidad de herramientas que llegan cada día.
Así que la idea era dejar de lado toda la información y ponerme manos a la obra con una pequeña app e ir aprendiendo a medida que iba escribiendo código.
Al final con este pequeño escaparate online, he aprendido a como se estructura el código de una aplicación pequeñita en VueJS, como ir separando responsabilidades por componentes, como usar el store para acceder a los datos y como declarar pequeñas funciones Javascript de «manera moderna».
Todavía queda mucho por aprender: como hacer test con alguna tool, como darle caña al linter para que el codestyle sea consistente, como sacarle partido al IDE, aprender una serie de herramientas (npm, scripts, linter,…) y descubrir plugins tan útiles como CopyWebpackPlugin.