Criando e compartilhando componentes Vue.js

Tecnologia

Encontrar um componente que bata 100% com os requisitos do nosso layout sem termos que modificar ele em nosso próprio projeto não é nada fácil. Em 99,99% dos casos precisamos replicar e manter estas mesmas modificações em outros projetos nossos, tornando a manutenção um trabalho árduo e cansativo.

A forma mais fácil de manter um componente deste porte seria criando nosso próprio componente. Além de podermos usar em outros projetos vamos estar a poucos passos de disponibilizá-lo online e ajudarmos outras pessoas que possam ter tido o mesmo problema.

Este artigo engloba as seguintes tecnologias:

Obs.: Eu uso o Yarn mas caso você prefira o NPM e quer usá-lo, fique atento apenas aos comandos que utilizam yarn e adeque conforme for necessário.

Vou procurar ser bem didático para que vocês não fiquem em um loop infinito de dúvidas.

Então, sem mais delongas, Let’s Go!

Tendo em mente que vocês já possuem o Yarn/NPM devidamente instalados, vamos seguir para a instalação do Vue Cli

Abra o terminal e digite o seguinte comando:

yarn global add @vue/cli

Verifique se foi instalado corretamente com o comando:

vue --version

Se tudo ocorreu bem vamos visualizar a versões do Vue Cli conforme este exemplo

@vue/cli 4.3.1

Ainda com o terminal aberto, navegue até o diretório onde você quer criar o seu componente.

Para este exemplo vamos criar um componente de um botão bem simples, porém, você poderá seguir este artigo para criar coisas mais complexas.

Seguindo, tendo navegado até o diretório desejado digite o seguinte comando:

vue create my-simple-button

O Vue Cli vai perguntar qual preset queremos. Escolha o default. Ele já basta para este exemplo.

Vue CLI v4.3.1
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint) 
  Manually select features 

Ele vai fazer as instalações necessárias e, após finalizar, digite o seguinte comando para iniciar o projeto:

yarn serve

Verifique se está tudo funcionando e finalize a aplicação para que possamos alterar algumas coisas na configuração.

Vamos até o arquivo  package.json        

Na sessão de Scripts, inclua um novo chamado  build-lib  

E coloque o seguinte conteúdo:

vue-cli-service build --target lib --inline-vue --name nome-plugin [entry]

Altera onde está nome-plugin para o nome do nosso projeto que no caso é my-simple-button

Vamos precisar alterar também o [entry]. É nele que informamos qual será o ponto de entrada do componente.

Se não informarmos ficando [entry], o ponto de entrada vai ser  src/App.vue, mas precisamos que o ponto de entrada seja src/main.js.
Ficando mais ou menos assim a sessão de Scripts

"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build-lib": "vue-cli-service build --target lib --inline-vue --name my-simple-button src/main.js",
    "lint": "vue-cli-service lint"
}

Rodando o novo comando vamos obter uma resposta parecida com esta

DONE  Compiled successfully in 4866ms                                                                

  File                             Size                 Gzipped

  dist/plugin-button.umd.min.js    70.49 KiB            25.14 KiB
  dist/plugin-button.umd.js        222.08 KiB           60.92 KiB
  dist/plugin-button.common.js     221.69 KiB           60.81 KiB
  dist/plugin-button.css           0.33 KiB             0.23 KiB

  Images and other types of assets omitted.

✨  Done in 7.16s.

Isso significa que a construção foi bem-sucedida.
Olhando para a pasta dist podemos ver vários arquivos, precisamos definir qual vai ser usado por qualquer aplicação que importe nosso componente.

Vamos escolher o terminado com .common.js
Então voltando para o package.json adicione o a sessão main, ficando assim:

"main": "./dist/plugin-button.common.js",
"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build-lib": "vue-cli-service build --target lib --inline-vue --name my-simple-button src/main.js",
    "lint": "vue-cli-service lint"
}

Agora vamos desenvolver nosso botão.
Indo em components vamos criar um arquivo chamado MeuBotaopersonalizado.vue com este conteúdo:

<template>
  <div>
    <button @click="incremento">{{ texto }}</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      contador: 0
    }
  },
  computed: {
    vezes () {
      return this.contador === 1 ? 'vez' : 'vezes'
    },
    texto () {
      return `Clicado ${this.contador} ${this.vezes}`
    }
  },
  methods: {
    incremento () {
      this.contador += 1
    }
  }
}
</script>

Esse botão, ao ser acionado, informa a quantidade de vezes que já foi clicado.

Conforme falei, nada complexo e de fácil entendimento.
O Vue nos permite visualizar apenas este componente. Rode o seguinte comando:

Powered by Rock Convert
vue serve src/components/MeuBotaopersonalizado.vue

Ao rodar podemos obter o seguinte resultado

Agora, para que possamos usar este componente em outros lugares, temos que informar o que será exportado.Indo no main.js e apagando tudo que contem nele, cole o seguinte código:

import botaoSimples from './components/MeuBotaopersonalizado.vue'

export default {
  install (Vue, options) {
    Vue.component('simple-button', botaoSimples)
  }
}

Não podemos esquecer de fazer o rebuild sempre que terminar de atualizar alguma coisa.

Se o componente precisar trabalhar com Vuex, vamos precisar de um pouquinho mais de código.

Temos que ter em mente que o Vue só permite uma instância do Vuex, logo, não vamos poder instalar esse plugin em nosso componente.

Mas para usar a store precisamos apenas definir a estrutura dela e informar que nosso componente depende do Vuex instalado no projeto para funcionar.

Tanto faz se vamos usar a store de arquivo único ou modular. No final, será o mesmo processo de apenas informar o caminho do arquivo principal da store.

Para este exemplo, vou assumir a criação da store em um único arquivo para facilitar o entendimento.
Vamos entrar no diretório src e criar um arquivo chamado store.js com o seguinte conteúdo:

const store = {
  state: {
    contador: 0
  },
  getters: {
    contador: state => state.contador
  },
  mutations: {
    increment (state) {
      state.contador += 1
    }
  }
}
export default store

Volte para o arquivo MeuBotaopersonalizado.vue e altere seu código para este:

<template>
  <div>
    <button @click="incremento">{{ texto }}</button>
  </div>
</template>
<script>
export default {
  data () {
    return {}
  },
  computed: {
    vezes () {
      return this.$store.getters.contador === 1 ? 'vez' : 'vezes'
    },
    texto () {
      return `Clicado ${this.$store.getters.counter} ${this.vezes}`
    }
  },
  methods: {
    incremento () {
      this.$store.commit('increment')
    }
  }
}
</script>

Precisamos alterar o main.js para este código:

import botaoSimples from './components/MeuBotaopersonalizado.vue'

import store from './store.js'

export default {
  install (Vue, options) {
    // Precisamos que vuex seja passada como opção para que possamos registrar a vuex do componente
    if (!options || !options.store) {
      throw new Error('Inicie o componente com Vuex.')
    }

    options.store.registerModule('simplebutton', store)

    Vue.component('simple-button', botaoSimples)
  }
}

Devemos fazer o rebuild novamente.

Após fazermos o build, o componente já está pronto para ser usado em qualquer projeto nosso.

Se não publicarmos no NPM podemos usar da seguinte forma

Estando em um projeto que queremos usar o componente, devemos abrir um terminal neste diretório e rodar o comando:

yarn add ../my-simple-button

Não esquecer de passar o caminho correto. Esse foi somente para exemplo.

Depois devemos ir no arquivo main.js deste projeto e fazer a instalação do nosso componente.

import mySimpleButton from my-simple-button;

// Podemos usar assim, passando as opcoes
Vue.use(mySimpleButton, {algumaOpcao: algumValor})

// ou assim, sem opcoes
Vue.use(mySimpleButton)

Temos duas formas de usar: a com opção e a sem opção.

O nosso componente precisa da store, logo temos que usar a primeira opção.

import Vue from 'vue'
import App from './App.vue'
import store from './store';
import mySimpleButton from my-simple-button;

Vue.config.productionTip = false

Vue.use (mySimpleButton, { store });

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')

Desta forma, o nosso componente está definido no nível da aplicação como o Vuex e não no componente que formos usar ele dentro.

Lembrando: ele está global!

<template>
  <div id="app">
    <h1>Contato</h1>
    <p>Algum texto</p>

    <my-simple-button />
  </div>
</template>

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

O nome que ele vai ser chamado vai ser sempre o que definimos no main.js do nosso componente.

import botaoSimples from './components/MeuBotaopersonalizado.vue'

import store from './store.js'

export default {
  install (Vue, options) {
    if (!options || !options.store) {
      throw new Error('Inicie o componente com Vuex.')
    }

    options.store.registerModule('simplebutton', store)

    Vue.component('bolacha-doce', botaoSimples)
  }
}

Neste exemplo eu alterei o nome para bolacha-doce, logo, para usar:

<template>
  <div id="app">
    <h1>Contato</h1>
    <p>Algum texto</p>

    <bolacha-doce />
  </div>
</template>

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

Muito fácil criar e compartilhar componentes/plugins.

Desta mesma forma que criamos o nosso componente, poderíamos ter encapsulado o componente de outra pessoa, como por exemplo uma estilização diferente em um botão do Bootstrap com algumas ações ao clicar ou passar o mouse.

Podemos disponibilizar também com o componente mixins, hooks, filters e muitas outras coisas.

O que vimos aqui foi apenas uma das N’s configurações que podemos fazer no install do nosso componente.

Isso pode ser um plus para um outro artigo.

O que podemos fazer agora é publicar no NPM facilitando para disponibilizar para a comunidade usar.
Bom, isso foi tudo pessoal.

Até a próxima!