Vue.js2 : avec Laravel
Vendredi 28 octobre 2016 18:42
Comme ce blog est essentiellement consacré à Laravel il me faut évoquer l'utilisation de Vue.js 2 avec Laravel 5.3 puisque cette version a été enrichie de tout ce qu'il faut pour sceller ce mariage. J'en ai un peu parlé dans mon article sur les nouveautés de la version 5.3. je vais y revenir de façon plus précise maintenant en poursuivant l'exemple du panier dans le contexte de Laravel.
Etat des lieux
Dans l'article référencé ci-dessus j'avais présenté l'infrastructure en place lorsqu'on installe Laravel 5.3 : On a déjà :- un composant vue.js 2 : Exemple.vue
- une application de base : app.js
- un fichier d'initialisation : bootstrap.js
const elixir = require('laravel-elixir'); require('laravel-elixir-vue-2'); /* |-------------------------------------------------------------------------- | Elixir Asset Management |-------------------------------------------------------------------------- | | Elixir provides a clean, fluent API for defining some basic Gulp tasks | for your Laravel application. By default, we are compiling the Sass | file for our application, as well as publishing vendor resources. | */ elixir(mix => { mix.sass('app.scss') .webpack('app.js'); });On voit qu'on lance une tâche Webpack en référençant le fichier app.js qui est l'entrée de l'application. C'est donc Elixir qui se charge de tout de façon invisible (on a pas de fichier webpack.config.js mais on peut en créer un au besoin). Concernant npm on a ce fichier package.json :
{ "private": true, "scripts": { "prod": "gulp --production", "dev": "gulp watch" }, "devDependencies": { "bootstrap-sass": "^3.3.7", "gulp": "^3.9.1", "jquery": "^3.1.0", "laravel-elixir": "^6.0.0-11", "laravel-elixir-vue-2": "^0.2.0", "laravel-elixir-webpack-official": "^1.0.2", "lodash": "^4.16.2", "vue": "^2.0.1", "vue-resource": "^1.0.3" } }On voit qu'on charge vue ainsi que le plugin vue-resource dont je parlerai dans un autre article. On dispose aussi de deux scripts :
- dev : pour le développement avec une observation des modification (watch)
- prod : pour la production en compressant les fichiers
Installation
La première chose à faire est évidemment d'utiliser npm pour charger toutes les dépendances :npm installCe qui crée le dossier node_modules avec tous les fichiers : On sait qu'on aura besoin du système de template pug pour le panier, alors on l'ajoute :
npm install pugOn a ainsi tout ce qu'il faut au niveau des dépendances ! En faisant mes essais je me suis rendu compte que la transformation du code ES6 en ES5 avec Elixir n'était pas assurée par Babel mais par Bublé. Cela a certaines conséquences parce que ce n'est pas l'ensemble de ES6 qui est pris en charge, ce qui est justifié dans la documentation :
Bublé limits itself to ES features that can be compiled to compact, performant ES5Vous disposez d'ailleurs d'une page avec les fonctionnalités non supportées. En particulier on y trouve le for...of que j'ai utilisé dans le précédent article pour justement tester la transformation effectuée par Babel. C'est d'ailleurs comme ça que je m'en suis rendu compte, parce que je tombais sur une erreur et que j'ai dû un peu fouiller parce que rien n'est indiqué dans la documentation de Laravel... On peut tout de même changer les options de fonctionnement de Bublé mais pas d'une façon qui m'a semblé suffisamment claire et adaptable à la situation. On peut évidemment utiliser Babel mais le loader est codé en dur dans Elixir... Pour le présent article j'ai pris la configuration par défaut et enlevé le for...of du code, ce qui était le plus simple !
Le panier
Maintenant pour mettre en place le panier c'est tout simple. On crée une route pour le tester :Route::get('test', function () { return view('test'); });La vue test.blade.php :
<!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"> <app></app> </div> </div> <script src="/js/app.js"></script> </body> </html>On a :
- un identifiant app pour servir de référence à Vue.js
- une balise app pour notre application
- le chargement du fichier JavaScript de l'application /js/app.js
require('./bootstrap'); Vue.component('app', require('./components/App.vue')); const app = new Vue({ el: '#app' });On met en place nos trois composants et on supprime Exemple.vue : Pour rappel voici le code de App.vue :
<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>Le code de Panier.vue :
<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; this.panier.forEach(function(el) { 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>C'est là que j'ai supprimé le for...of. Et Editeur.vue :
<template lang="pug"> tr(class="bleu") 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> <script> export default { props: ['article'], computed: { input: function() { return this.article; } }, methods: { ajouter: function() { this.$emit('add', this.input); } } } </script> <style lang="sass"> $fond: lightblue; .bleu { background-color: $fond !important; } </style>
On lance Gulp
Il ne reste plus qu'à voir si ça fonctionne : Apparemment tout se passe bien en mode développement. On retrouve bien le panier : Et on est en mode watch pour que tous les changements soient pris en compte. Et voilà ce que ça donne en mode production : Cette fois le fichier /js/app.js est minifié et le panier fonctionne encore ! On voit donc que la mise en oeuvre de Vue.js2 avec Laravel 5.3 est assez facile. Reste toutefois à voir s'il est aussi facile de modifier la configuration selon les besoins. Je n'en ai pas l'expérience parce que je n'ai eu aucun projet qui justifie ce genre de mise en oeuvre.Par bestmomo
Aucun commentaire