Tutoriel pour apprendre à utiliser le framework Vue.js version 2

Plus loin


précédentsommairesuivant

I. On s'organise !

Dans tous les exemples qu'on a vus dans précédent tutoriel on a placé le code JavaScript sur la page, on pourrait évidemment le mettre dans un fichier spécifique, ce qui ne changerait rien au principe. Tant qu'on n'a pas trop de code, c'est parfait, simple et léger, mais quand le code s'accumule on aurait envie de pouvoir l'organiser plus efficacement.

D'autre part on voudrait aussi des fois effectuer d'autres actions : utiliser Babel pour coder en ES6, utiliser Pug dans notre template, utiliser Sass pour notre style, minifier notre JavaScript en production…

Le développement rapide du codage côté client a vu l'apparition d'une multitude d'outils : Grunt, Gulp, Browserify, Webpack, Lint… On finit par s'y perdre ! On a des tasks runners, des bundlers, et autres… Il est grand temps qu'une normalisation voie le jour…

Je ne vais pas clarifier tout ça dans ce tutoriel, ce n'est pas le but. On va juste voir un plugin bien pratique de vue.js : vue-loader. Ce plugin permet :

  • d'écrire chaque composant dans un fichier avec le template, le script et le style ;
  • d'écrire le code JavaScript en ES6 ;
  • d'utiliser Webpack avec simplicité ;
  • d'offrir un serveur de développement avec mise à jour en temps réel des modifications ;
  • de générer les fichiers de productions…

Le fondement de tout ça c'est Webpack, alors pour ceux qui ne connaissent pas je vais en parler un peu.

I-A. Webpack

Webpack est un module bundler (je ne trouve pas de traduction satisfaisante). Le but premier est de pouvoir organiser le code (css, images, polices, JavaScript…) en modules pour simplifier le développement. Il a tendance à détrôner Grunt et Gulp dans cette tâche.

En gros, on crée des modules interdépendants, Webpack traite tout ça pour les transformer en fichiers statiques tout prêts pour le Web :

Image non disponible

Webpack est capable de charger à peu près n'importe quoi à partir du moment où on lui explique comment faire (en pratique il faut un loader dédié). En plus il est assez intelligent pour pouvoir séparer le résultat en plusieurs paquets pour améliorer les performances.

Le seul reproche qu'on peut faire à Webpack c'est qu'il n'est pas vraiment facile à prendre en main, mais une fois qu'on le connait bien on peut vraiment tout faire !

Dans le contexte de ce tutoriel, on va voir que le plugin vue-loader a bien préparé le terrain et que l'utilisation en est grandement facilitée. Si vous voulez vraiment vous lancer dans Webpack, il y a le tutoriel officiel qui est bien fait.

I-B. Installer vue-loader

On va installer un outil en ligne de commande (vue-cli) pour pouvoir ensuite utiliser vue-loader.

Mais à la base il vous faut node.js. Si vous ne l'avez pas, alors commencez par l'installer globalement, il vous servira pour bien d'autres choses !

Le gestionnaire de dépendances de node.js est npm. C'est l'équivalent de composer, mais pour JavaScript. Lui aussi il vous le faut, mais vous pouvez l'installer en même temps que node.js.

Une fois que vous avez tout ça, vous pouvez installer le plugin avec ces commandes dans votre console :

 
Sélectionnez
1.
2.
3.
4.
5.
npm install -g vue-cli (1)
vue init webpack-simple test (2)
cd test (3)
npm install (4)
npm run dev (5)

Voyons cela de plus près :

  • (1) on commence par installer le plugin avec npm ;
  • (2) on initialise le plugin dans le dossier test, acceptez les valeurs par défaut ;
  • (3) on se positionne dans le dossier test ;
  • (4) on installe toutes les dépendances (ça peut être long, ça crée un dossier node_modules bien garni), vous devriez vous retrouver avec tout ça :
Image non disponible
  • (5) on lance le serveur de développement (en localhost:8080).

Si tout se passe bien, votre navigateur préféré s'ouvre avec ça :

Image non disponible

Il ne vous reste plus qu'à coder votre application !

Nota : j'utilise ici le template simplifié webpack-simple, mais il existe aussi la version complète webpack avec plein de choses détaillées sur la page github.

I-C. État des lieux

Pour fonctionner, Webpack a besoin d'un fichier de configuration webpack.config.js. Vous en trouvez un à la racine avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
var path = require('path')
var webpack = require('webpack')
 
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'build.js'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue',
        options: {
          // vue-loader options go here
        }
      },
      {
        test: /\.js$/,
        loader: 'babel',
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file',
        options: {
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue'
    }
  },
  devServer: {
    historyApiFallback: true,
    noInfo: true
  },
  devtool: '#eval-source-map'
}
 
if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  // http://vue-loader.vuejs.org/en/workflow/production.html
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
}

On ne va pas détailler tout ça, mais au moins le minimum :

  • entry : là on définit le fichier qui est le point d'entrée de l'application : src/main.js ;
  • output : là on définit le fichier de sortie, ça ne sert pas pour le développement, mais pour la distribution : dist/build.js ;
  • module : là on met les modules dont on va avoir besoin, les loaders, on a par défaut vue, babel et file.

Pour le moment on va se contenter de ça.

Les fichiers de développement de notre application sont dans le dossier src (source) :

Image non disponible

Un fichier qui contient un composant a comme suffixe vue, ici on n'en a qu'un : App.vue. Voici son code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
    <ul>
      <li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
      <li><a href="https://gitter.im/vuejs/vue" target="_blank">Gitter Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
      <li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
      <li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
      <li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
    </ul>
  </div>
</template>
 
<script>
export default {
  name: 'app',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>
 
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
 
h1, h2 {
  font-weight: normal;
}
 
ul {
  list-style-type: none;
  padding: 0;
}
 
li {
  display: inline-block;
  margin: 0 10px;
}
 
a {
  color: #42b983;
}
</style>

On a trois blocs :

  • template : pour le template HTML ;
  • script : pour le code JavaScript, on peut utiliser ES6 parce que par défaut babel est activé, c'est pour ça qu'il est prévu un export dans le code du composant ;
  • style : pour le style CSS.

vue-loader sera chargé d'extraire ces blocs, de transformer le code avec les loaders prévus, et enfin de les assembler en un module qui pourra être pris en charge par Webpack.

On a vu que le point d'entrée est main.js :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
import Vue from 'vue'
import App from './App.vue'
 
new Vue({
  el: '#app',
  render: h => h(App)
})

On importe Vue évidemment et aussi le seul composant App. Ne vous inquiétez pas de la syntaxe avec le render, on verra ça peut-être dans un autre chapitre.

Au niveau de index.html on a du classique :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>test</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="/dist/build.js"></script>
  </body>
</html>

I-D. Le panier encore revisité

Maintenant qu'on a toute l'intendance, on va à nouveau coder le panier qu'on a vu lors du précédent tutoriel, mais cette fois à la mode vue-loader.

On va conserver inchangé le fichier main.js.

I-D-1. index.html

On va adapter index.html essentiellement pour intégrer Bootstrap :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Test vue.js</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/united/bootstrap.min.css">
  </head>
  <body>
    <div class="container">
        <br>
        <div id="app"></div>
    </div>
    <script src="/dist/build.js"></script>
  </body>
</html>

I-D-2. Le composant Panier

On va créer un fichier Panier.vue pour le composant du panier :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
<template>
<div class="panel panel-primary">
  <div class="panel-heading">Panier</div>        
  <table class="table table-bordered table-striped">
    <thead>
      <tr>
       <th class="col-sm-4">Article</th>
       <th class="col-sm-2">Quantité</th>
       <th class="col-sm-2">Prix</th>
       <th class="col-sm-2">Total</th>
       <th class="col-sm-1"></th>
       <th class="col-sm-1"></th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(item, index) in panier">
        <td>{{ item.article }}</td>
        <td>{{ item.quantite }}</td> 
        <td>{{ item.prix }}</td>
        <td>{{ (item.quantite * item.prix).toFixed(2) }}</td>
        <td><button class="btn btn-info btn-block" @click="modifier(index)"><i class="fa fa-edit fa-lg"></i></button></td>
        <td><button class="btn btn-danger btn-block" @click="supprimer(index)"><i class="fa fa-trash-o fa-lg"></i></button></td>
      </tr> 
      <tr>
        <td colspan="3"></td>
        <td><strong>{{ total }}</strong></td>
        <td colspan="2"></td>
      </tr> 
      <editeur :article="article" @add="ajouter"></editeur>
    </tbody>       
  </table>
</div>
</template>
 
<script>
import Editeur from './Editeur.vue'
 
export default {
  props: ['panier'],
  data: function () {
    return {
      article: { article: '', quantite: 0, prix: 0 }
    }
  },
  computed: {
    total: function () {
      let total = 0;
      for(let el of this.panier) {
        total += el.prix * el.quantite
      }
      return total.toFixed(2)
    }
  },
  methods: {
    modifier: function(index) {
      this.article = this.panier[index]
      this.panier.splice(index, 1)
    },
    supprimer: function(index) {
      this.panier.splice(index, 1)
    },
    ajouter: function(input) {
      this.panier.push(input)
      this.article = { article: '', quantite: 0, prix: 0 }
    }
  },
  components: {
    Editeur
  }
}
</script>

Je n'ai rien changé au template.

Pour le JavaScript on sait qu'il faudra importer le composant Editeur :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
import Editeur from './Editeur.vue'
 
...
 
components: {
  Editeur
}

D'autre part je profite de la mise à disposition de ES6 pour voir si babel fonctionne bien :

 
Sélectionnez
1.
2.
3.
4.
let total = 0;
for(let el of this.panier) {
  total += el.prix * el.quantite
}

I-D-3. Le composant Editeur

De la même manière, j'ai créé le fichier Editeur.vue pour le composant Editeur :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
<template>
<tr>
  <td><input type="text" class="form-control" v-model="input.article" ref="modif" placeholder="Article"></td>
  <td><input type="text" class="form-control" v-model="input.quantite" placeholder="Quantité"></td>
  <td><input type="text" class="form-control" v-model="input.prix" placeholder="Prix"></td>
  <td colspan="3"><button class="btn btn-primary btn-block" @click="ajouter()">Ajouter</button></td>
</tr>
</template>
 
<script>
export default {
  props: ['article'],
  computed: {
    input: function() {
      return this.article;
    }
  },
  methods: {
    ajouter: function() {
      this.$emit('add', this.input);
    }
  }  
}
</script>

Là je n'ai rien changé.

I-D-4. Le composant principal

Pour terminer, il faut modifier le composant App.vue :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
<template>
  <div id="app">
    <panier :panier="panier"></panier> 
  </div>
</template>
 
<script>
import Panier from './Panier.vue'
 
export default {
  name: 'application',
  data () {
    return {
      panier: [
        { article: "Cahier", quantite: 2, prix: '5.30' },
        { article: "Crayon", quantite: 4, prix: '1.10' },
        { article: "Gomme", quantite: 1, prix: '3.25' }
      ]
    }
  },
  components: {
    Panier
  }
}
</script>

On importe le composant Panier.

À la fin vous devez avoir ces fichiers :

Image non disponible

Et normalement le panier à l'écran :

Image non disponible

Si ce n'est pas le cas, relisez l'article pour voir le code que vous avez raté ! Ou lisez les informations fournies par les outils de développement du navigateur (je rappelle qu'il y a une extension pour vue.js dans Chrome).

I-E. Jouer avec les templates et les styles

I-E-1. Les templates

On va voir qu'on peut vraiment faire beaucoup de choses, par exemple utiliser un outil de template comme Pug. On va commencer par l'installer avec npm :

 
Sélectionnez
npm install pug --save-dev

Ensuite, changez ainsi le code du template du composant Editeur.vue :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
<template lang="pug">
tr
  td
    input(type="text" class="form-control" v-model="input.article" ref="modif" placeholder="Article")
  td
    input(type="text" class="form-control" v-model="input.quantite" placeholder="Quantité")
  td
    input(type="text" class="form-control" v-model="input.prix" placeholder="Prix")
  td(colspan="3")
    button(class="btn btn-primary btn-block" @click="ajouter()") "Ajouter"
</template>

On déclare le système de template utilisé avec un attribut dans la balise template. Ensuite on l'utilise dans le code.

Si tout passe bien le bon code HTML doit être généré. Pratique non ?

I-E-2. Le style

On peut aussi ajouter du style au composant Editeur.vue. Là aussi on peut utiliser un préprocesseur comme Sass. On va d'abord l'installer :

 
Sélectionnez
npm install sass-loader node-sass --save-dev

Et ensuite, ajouter un bloc de style :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
<style lang="sass">
$fond: lightblue;
.bleu {
  background-color: $fond !important;
}
</style>

Il faut quand même préciser où agit la classe dans le template :

 
Sélectionnez
tr(class="bleu")

Avec ce résultat :

Image non disponible

Le CSS a été correctement généré !

I-F. La production

Le but c'est quand même de générer les fichiers de production. Là c'est tout simple :

 
Sélectionnez
npm run build
Image non disponible

Voyons le dossier dist :

Image non disponible

Si vous ouvrez le fichier build.js vous verrez que le code a été « uglifié » et minimisé. Mais maintenant est-ce que ça fonctionne ? Il suffit d'ouvrir index.html dans votre navigateur. Il faudra peut-être changer la référence du fichier build.js si vous n'êtes pas avec un hôte virtuel :

 
Sélectionnez
<script src="dist/build.js"></script>

Normalement tout fonctionne bien, même le style ajouté à l'éditeur, le tout dans un fichier de 580 Ko !

Si vous voulez voir le code produit sans la compression, commentez ces lignes dans webpack.config.js :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
new webpack.optimize.UglifyJsPlugin({
  compress: {
    warnings: false
  }
}),
new webpack.LoaderOptionsPlugin({
  minimize: true
})

Si vous voulez voir ce que ça donne, je l'ai mis en ligne ici.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2017 Vue.js. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.