No soy partidario de utilizar siempre un framework JS para construir nuestras aplicaciones pero, sin duda, todos los desarrolladores front estamos de acuerdo en que elegir uno entre tantas opciones disponibles no es tarea fácil.

Pero si decidimos usarlo, podríamos reducir los argumentos de esta elección a una sola afirmación: queremos que el framework nos simplifique la vida. Es decir, poder hacer más con menos y no necesitar un máster en [inserte nombre framework] JS para conseguirlo.

Hoy vengo a hablar de nuevo de VueJS (sí, qué pesado, otra vez). Sin entrar en el caluroso debate sobre qué framework utilizar, he de decir que a estas alturas estoy contento con mi elección e intento no convertirme en un fanboy.

Porque la verdad es que nos está simplificando muchísimo las cosas en nuestros proyectos. Y cuando una tecnología nos encaja en nuestro día a día, podemos decir que hemos acertado con la elección.

Vamos a ver cómo podemos enfrentarnos a la eterna problemática de crear nuestra librería de componentes con VueJS, y voy a intentar que este post sea lo más corto y sencillo posible. ¡Ya os adelanto que no va a ser difícil conseguirlo!

¿Para qué nos sirve una librería de componentes?

Cuando comenzamos un nuevo proyecto, sea una SPA o páginas independientes, nuestros primeros desarrollos serán principalmente la creación de los componentes base que vamos a utilizar.

Ya partimos de una serie de elementos que nos otorga HTML5, pero lo normal es que estos inputs, botones, tablas, modales, etc… requieran de código extra HTML, JS y CSS para cumplir con el diseño y funcionamiento de nuestra aplicación.

En ocasiones podremos optar por elegir utilizar una librería ya creada al estilo de Bootstrap o Bulma y agilizar el tiempo de desarrollo, pero dependiendo de la naturaleza del proyecto estas librerías pueden no adaptarse a nuestros requisitos.

Aquí es donde entra en juego crear nuestra propia librería. Pueden utilizarse principalmente con los siguientes objetivos:

  1. No queremos desarrollar los mismos componentes una y otra vez cada vez que iniciemos un proyecto. Si creamos nuestra librería de componentes, podremos reutilizarlos en diferentes proyectos ajustando principalmente estilos para adaptarlos a nuestro diseño. De esta forma ya dispondremos de componentes con funcionalidad y testeados, listos para usar.
  2. Nuestro proyecto se basa en N subproyectos diferentes, es decir, diferentes aplicaciones o páginas que comparten componentes, por lo que queremos evitar la duplicidad de código y agilizar el desarrollo.

En cualquiera de los casos e independientemente de la tecnología (Vue, React, Angular, VanillaJS, VanillaJS) tener una librería ya creada nos simplificará enormemente la vida y evitará que esas primeras fases del desarrollo se alarguen demasiado en el tiempo.

Paso 1: Creamos nuestros componentes

En primer lugar, creamos un nuevo proyecto de Vue gracias a la herramienta Vue-cli, y damos forma a tres componentes que nos servirán de prueba.

El primero será un botón simple, el segundo será un botón con un color diferente, y el tercero será una agrupación de ambos, de forma que podamos probar nuestra librería cuando existan componentes anidados. Creamos los componentes dentro del directorio ‘./src/components’.

<template lang="html">
  <button type="button" name="button">{{ buttonText }}</button>
</template>

<script>
export default {
  name: 'ButtonComponent',
  props: {
    buttonText: String
  }
}
</script>

<style lang="css">
  button {
    background-color: green;
    color: white;
    border: none;
    min-height: 3em;
    min-width: 5em;
    border-radius: .3em;
    margin: 0.2em;
  }
</style>

<template lang="html">
  <button type="button" name="button">{{ buttonText }}</button>
</template>

<script>
export default {
  name: 'OtherButtonComponent',
  props: {
    buttonText: String
  }
}
</script>

<style lang="css" scoped>
  button {
    background-color: red;
    color: white;
  }
</style>

<template lang="html">

    <button-component buttonText="Example button"></button-component>
    <other-button-component buttonText="Other button"></other-button-component>

Una vez creados los añadimos a nuestro componente HelloWorld.vue, que viene por defecto al crear el proyecto.

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <section>
      <p>Separate components</p>
      <p>
        <button-component buttonText="Example button"></button-component>
        <other-button-component buttonText="Other button"></other-button-component>
      </p>
    </section>
    <section>
      <p>Nested components</p>
      <button-group-component></button-group-component>
    </section>
  </div>
</template>

<script>
import ButtonComponent from '../components/ButtonComponent';
import OtherButtonComponent from '../components/OtherButtonComponent';
import ButtonGroupComponent from '../components/ButtonGroupComponent';

export default {
  name: 'HelloWorld',
  components: {
    ButtonComponent,
    OtherButtonComponent,
    ButtonGroupComponent
  },
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
section p{
  text-align: center;
}
</style>

 Figura 1: Componentes de nuestra librería en VueJSFigura 1: Componentes de nuestra librería en VueJS

Nuestro objetivo es crear una librería de componentes, es decir, un proyecto con componentes independientes que podamos usar en cualquier otro proyecto.

Esta librería se convertirá, por tanto, en una dependencia en el proyecto en el que la vayamos a usar. Queremos también que la librería, una vez compilada, tenga el formato necesario para subirla a npm (o Nexus en el caso de disponer de uno).

Para ello, necesitamos crear un punto de entrada o index.js que se encargará de registrar los componentes de nuestra librería globalmente.

Además, nos permitirá exportar la librería como un plugin que podremos usar en otro proyecto gracias a la función Vue.use().

Más adelante, podemos automatizar este proceso de construcción y generar este archivo de forma dinámica mediante un script de NodeJS.

/* eslint-disable */
import ButtonComponent from './components/ButtonComponent.vue'
import OtherButtonComponent from './components/OtherButtonComponent.vue'
import ButtonGroupComponent from './components/ButtonGroupComponent.vue'

// Exportación de los componentes individualmente
export { ButtonComponent, OtherButtonComponent, ButtonGroupComponent}

// Instalación de la librería como un plugin
export function install(Vue) {
  Vue.component('ButtonComponent', ButtonComponent)
  Vue.component('OtherButtonComponent', OtherButtonComponent)
  Vue.component('ButtonGroupComponent', ButtonGroupComponent)
}

if (typeof window !== 'undefined' &amp;&amp; window.Vue) {
  Vue.use({ install });
}

// Exportación de la librería como plugin
export default { install: install }

Paso 2: Compilando la librería

El siguiente paso es compilar nuestra librería para generar un archivo JS que podamos llevar a cada uno de nuestros proyectos.

Para ello, utilizaremos las herramientas que ya nos da Vue-cli (y la potencia de webpack por debajo) para compilar cada uno de los archivos que conforman nuestra librería de componentes.

En Vue viene incluida una tarea de construcción que permite especificar si nuestro objetivo es crear una librería. Para ello, ejecutaremos el siguiente comando con el argumento --target lib*,* el nombre que queramos para nuestra librería y nuestro punto de entradasrc/index.js’.

npx vue-cli-service build --target lib --name components-lib src/index.js

Veremos que en la carpeta ./dist se han generado una serie de archivos:

  1. components-lib.common.js: es la construcción de la librería que podremos utilizar en aplicaciones que funcionen con CommonJS, es decir, aplicaciones basadas en módulos.
  2. components-lib.umd.js: es la construcción de la librería que podemos utilizar en aplicaciones basadas en el estándar UMD. Esto nos permitirá utilizar nuestra librería en aplicaciones más antiguas en las cuales no existan módulos de javascript y se carguen los archivos por *.
  3. components-lib.css: por defecto, Vue extraerá el css de nuestros componentes en un archivo separado. Podemos desactivar esta opción mediante el archivo de configuración de vue/webpack.

A continuación, vamos a añadir manualmente un archivo package.json en la carpeta dist/, que nos servirá más adelante para poder subir el proyecto a npm o nexus y para poder importar nuestro módulo desde otra aplicación.

También podremos automatizar la creación de este archivo mediante un script en NodeJS.

Es importante introducir en la opción “main” el archivo de entrada de nuestra librería. En nuestro caso pondremos por defecto el archivo para sistemas modulares *.common.js.

{
  "name": "@jcarceller/components-lib",
  "description": "Components library based on vue-cli-3",
  "author": {
    "name": "Paradigma Digital"
  },
  "version": "0.0.1",
  "license": "MIT",
  "main": "components-lib.common.js",
  "unpkg": "components-lib.common.js",
  "jsdelivr": "components-lib.common.js",
  "peerDependencies": {
    "vue": ">=2.0.0"
  },
  "files": [
     "*"
  ]
}

Paso 3: Usando la librería en otro proyecto VueJS

Ya tenemos la librería compilada así que... ¡hora de probarla! En primer lugar, vamos a subirla a npm por lo que accederemos por consola a la carpeta ./dist y ejecutaremos el siguiente comando.

Es necesario crear una cuenta en npm si no la tenemos y loguearse primero mediante el comando npm login. ¡Ya tenemos la librería en npm!

npm publish --access=public

A continuación, vamos a crear de nuevo un proyecto Vue hello-world con Vue-cli que nos servirá como prueba. Una vez terminemos, instalamos nuestra librería como una dependencia apuntando al nombre que hemos puesto en el package.json mediante el comando:

npm install --save @jcarceller/components-lib

Finalmente, vamos a nuestro main.js e importamos la librería. Tendremos que indicarle a Vue que utilice nuestra librería como un plugin usando Vue.use(), así que añadimos las siguientes líneas de código.

De esta forma ya podemos usar nuestros componentes en cualquier sitio de la aplicación, dado que han sido registrados de forma global en el index.js de la librería.

import Vue from 'vue'
import App from './App.vue'
import '@jcarceller/components-lib/components-lib.css';
import * as ComponentsLib from '@jcarceller/components-lib';

Vue.config.productionTip = false

Vue.use({install: ComponentsLib.install});

new Vue({
  render: h => h(App)
}).$mount('--md-var-hashtag-app')

Vamos por ejemplo al archivo App.vue y añadimos la invocación de nuestros componentes en la template.

Recordemos que no es necesario indicar a App.vue los componentes que vamos a usar mediante components: {}, ya que ya han sido registrados globalmente.

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <section>
      <button-component buttonText="Ejemplo de botón"/>
      <other-button-component buttonText="Ejemplo de botón"/>
      <button-group-component />
    </section>
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>

Si deseamos únicamente importar un componente en lugar de toda la librería, sí será necesario registrar el componente en Vue.

Podremos hacerlo de la siguiente manera en nuestro archivo App.vue:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <section>
      <other-button-component buttonText="Ejemplo de botón"/>
    </section>
  </div>
</template>

<script>

import {OtherButtonComponent} from '@jcarceller/components-lib';

export default {
  name: 'app',
  components: {
    OtherButtonComponent
  }
}
</script>

Conclusiones

Cuando utilizamos un framework JS, no solo son importantes las mejoras técnicas y las facilidades que introducen en el desarrollo de nuestras aplicaciones, sino también el ecosistema alrededor del framework y la documentación que nos ofrecen.

Mi experiencia personal a la hora de abordar un problema complejo como la creación de una librería de componentes con VueJS ha sido tremendamente sencilla y potente.

La herramienta Vue-cli nos entrega procesos como este muy interesantes para construir nuestra arquitectura de forma sencilla, y así enfrentarnos a las distintas situaciones y problemáticas del mundo de desarrollo web.

Gracias a este proceso, podremos compartir nuestros componentes entre aplicaciones, evitar repetir código y agilizar enormemente nuestros desarrollos.

Pero no todo queda aquí, en la construcción de la librería. En otro post os contaré cómo podemos construir y publicar cada componente por separado y cómo podemos utilizar VueJS y nuestros componentes de forma independiente en aplicaciones no modulares o que no han sido desarrolladas con VueJS. ¡Las posibilidades son enormes!

Referencias y enlaces

Cuéntanos qué te parece.

Enviar.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.