Migration depuis Vue 1.x

FAQ

Wow ! C’est une super longue page ! Est-ce que ça veut dire que la version 2.0 est complètement différente, que je vais devoir réapprendre les bases depuis le début, et que la migration est pratiquement impossible ?

Ravi que vous posiez la question ! La réponse est non. Environ 90% de l’API reste la même et le cœur des concepts reste inchangé. C’est long car nous avons voulu offrir des explications très détaillées et inclure beaucoup d’exemples. Et soyez rassuré(e), cette page n’est pas quelque chose que vous devez lire complètement de haut en bas !

Comment dois-je m’y prendre pour commencer ma migration ?

  1. Commencez par lancer l’outil d’aide à la migration sur un projet courant. Nous avons soigneusement minifié et compressé un développement Vue dans une simple interface en ligne de commande. À chaque fois qu’il va reconnaitre une fonctionnalité obsolète, il va vous le faire savoir, vous offrir des suggestions et vous fournir des liens pour plus d’informations.

  2. Après cela, parcourez la table des matières de cette page dans la barre de navigation. Si vous voyez un sujet qui vous concerne, mais que l’outil d’aide à la migration ne l’a pas repéré, vérifiez-le.

  3. Si vous avez des cas de test, exécutez-les et voyez ce qui ne fonctionne plus et échoue. Si vous n’avez pas de cas de test, ouvrez simplement votre application dans votre navigateur et gardez un œil sur les avertissements et erreurs que vous trouverez en faisant un tour de l’application.

  4. Maintenant, votre application devrait être pleinement migrée. Si vous n’êtes toujours pas satisfait de divers points, vous pouvez lire le reste de cette page (ou juste plonger dans le nouveau guide de démarrage). Beaucoup de parties seront vite parcourues puisque vous êtes familier aux concepts de base.

Combien de temps va prendre la migration d’une application Vue 1.x vers une application Vue 2.0 ?

Cela dépend de plusieurs critères comme :

Si je passe à Vue 2, dois-je aussi mettre à jour Vuex et Vue Router ?

Seul Vue Router 2 est compatible avec Vue 2, donc oui, vous allez devoir également suivre le guide de migration pour Vue Router. Heureusement, un grand nombre d’applications n’ont pas beaucoup de code en lien avec le routeur, cela ne devrait donc pas prendre plus d’une heure.

En ce qui concerne Vuex, la version 0.8 est compatible avec Vue 2, vous n’êtes donc pas obligé de le mettre à jour. La seule raison pour que vous souhaitiez faire la mise à jour dès maintenant serait de tirer parti des nouvelles fonctionnalités de Vuex 2, comme les modules ou les codes préconçus (« boilerplate ») moins verbeux.

Templates

Instances fragmentées supprimées

Tous les composants doivent avoir seulement un seul élément racine. Les instances fragmentées ne sont plus permises. Si vous aviez un template comme ceci :

<p>foo</p>
<p>bar</p>

Il est recommandé d’entourer simplement le contenu complet dans un nouvel élément, comme cela :

<div>
<p>foo</p>
<p>bar</p>
</div>

Comment procéder ?

Lancez votre suite de tests ou votre application après mise à jour et vérifiez les avertissements de console à propos d'éléments multiple à la racine dans un template.

Hooks de cycle de vie

beforeCompile supprimé

Utilisez le hook created à la place.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver toutes les occurrences de ce hook.

compiled remplacé

Utilisez le hook mounted à la place.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver toutes les occurrences de ce hook.

attached supprimé

Utilisez une vérification du DOM dans les autres hooks. Par exemple, remplacez :

attached: function () {
doSomething()
}

par :

mounted: function () {
this.$nextTick(function () {
doSomething()
})
}

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver toutes les occurrences de ce hook.

detached supprimé

Utilisez une vérification du DOM dans les autres hooks. Par exemple, remplacez :

detached: function () {
doSomething()
}

par :

destroyed: function () {
this.$nextTick(function () {
doSomething()
})
}

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver toutes les occurrences de ce hook.

init renommé

Utilisez le nouveau hook beforeCreate à la place. Il fait la même chose. Il a été renommé pour plus de consistances avec les autres méthodes du cycle de vie.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver toutes les occurrences de ce hook.

ready remplacé

Utilisez le hook mounted à la place. Il est a noté qu’avec mounted, il n’y a aucune garantie de présence dans le document (DOM réel). Pour s’en assurer, il faut inclure Vue.nextTick / vm.$nextTick. Par exemple :

mounted: function () {
this.$nextTick(function () {
// code vous assurant que `this.$el` est dans le document.
})
}

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver toutes les occurrences de ce hook.

v-for

Ordre des arguments de v-for pour les tableaux changé

Quand vous utilisiez un index, l’ordre des arguments pour les tableaux était (index, value). Cet ordre est maintenant (value, index) pour plus de consistances avec les méthodes natives des tableaux JavaScript comme forEach et map.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples d'ordre des arguments obsolètes. Notez que si le nom de votre index est quelque chose de non habituel comme position ou num, l'outil d'aide ne les trouvera pas.

Ordre des arguments de v-for pour les objets changé

Quand vous utilisez une key, l’ordre des arguments pour les objets était (key, value). Cet ordre est maintenant (value, key) pour plus de consistances avec les itérateurs d’objet communs comme lodash.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples d'ordre des arguments obsolètes. Notez que si le nom de votre clé est quelque chose comme name ou property, l'outil d'aide ne les trouvera pas.

$index et $key supprimés

Les variables implicites $index et $key ont été enlevées à la faveur de leur définition explicite dans v-for. Ceci rend le code plus simple à lire pour les développeurs moins expérimentés avec Vue. Il en résulte également des comportements plus prévisibles dans les cas de boucles imbriquées.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences de ces variables retirées. Si vous en oubliez certaines, vous devriez voir des erreurs console comme Uncaught ReferenceError: $index is not defined.

track-by remplacé

track-by a été remplacé par key. Il fonctionne comme n’importe quel autre attribut : avec ou sans les préfixes v-bind: ou : il est traité comme une chaine de caractères standards. Dans la plupart des cas, vous souhaiterez une liaison dynamique demandant une expression à la place d’une clé. Par exemple, à la place de :

<div v-for="item in items" track-by="id">

vous aurez maintenant :

<div v-for="item in items" v-bind:key="item.id">

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences de track-by.

v-for et plage de valeurs changé

Précédemment, v-for="number in 10" devait avoir number qui commençait à 0 et qui finissait à 9. Maintenant il commence à 1 et finit à 10.

Comment procéder ?

Cherchez dans votre code avec l'expression régulière /\w+ in \d+/. Partout ou cette expression sort dans du code v-for, vérifiez si cela vous affecte.

Props

Option de prop coerce supprimée

Si vous voulez coercer une prop, mettez en place une propriété calculée basée dessus. Par exemple au lieu de :

props: {
username: {
type: String,
coerce: function (value) {
return value
.toLowerCase()
.replace(/\s+/, '-')
}
}
}

utilisez plutôt :

props: {
username: String,
},
computed: {
normalizedUsername: function () {
return this.username
.toLowerCase()
.replace(/\s+/, '-')
}
}

Cela a plusieurs avantages :

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences de l'option coerce.

Option de prop twoWay supprimée

Les props sont maintenant toujours unidirectionnelles et descendantes. Pour produire une modification dans la portée parente, un composant a besoin d’explicitement émettre un évènement au lieu de créer une liaison implicite. Pour plus d’informations, consultez :

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences de l'option twoWay.

Modificateur .once et .sync de v-bind supprimé

Les props sont maintenant toujours unidirectionnelles et descendantes. Pour produire une modification dans la portée parente, un composant a besoin d’explicitement émettre un évènement au lieu de créer une liaison implicite. Pour plus d’informations, consultez :

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences des modificateurs .once et .sync.

Mutation de prop déprécié

Muter une prop localement est maintenant considéré comme un anti-pattern, c.-à-d. déclarer une prop et l’affecter ainsi this.myProp = 'someOtherValue' dans le composant. À cause du nouveau mécanisme de rendu, à chaque nouveau rendu du composant parent, les changements locaux du composant enfant seront écrasés.

Dans la majorité des cas, muter une prop peut être remplacé par une de ces solutions :

Comment procéder ?

Lancez votre suite de tests ou votre application après mise à jour et vérifiez les avertissements de console à propos des mutations du prop.

props sur l’instance racine remplacée

Sur une instance racine de Vue (c.-à-d. crée avec new Vue({ ... })), vous devez utilisez propsData à la place de props.

Comment procéder ?

Lancez votre suite de tests si vous en avez. Les tests en échec devraient vous alerter du fait que les props de l'instance racine ne sont plus passées.

Propriétés calculées

cache: false dépréciée

L’invalidation de cache pour les propriétés calculées va être retirée dans les futures versions majeures de Vue. Remplacez toutes les propriétés calculées avec invalidation de cache par des méthodes, cela produira le même résultat.

Par exemple :

template: '<p>message : {{ timeMessage }}</p>',
computed: {
timeMessage: {
cache: false,
get: function () {
return Date.now() + this.message
}
}
}

Devient dans une méthode :

template: '<p>message : {{ getTimeMessage }}</p>',
methods: {
getTimeMessage: function () {
return Date.now() + this.message
}
}

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences de l'option cache: false.

Directives intégrées

Évaluation à vrai ou faux avec v-bind changée

Quand elles sont utilisées dans v-bind, seules les valeurs null, undefined et false sont évaluées à false. Cela signifie que 0 ou une chaine vide sera rendue à vrai. Donc par exemple v-bind:draggable="''" va donner draggable="true".

Pour les attributs énumérés, en plus des valeurs précédentes évaluées à false, la chaine de caractères "false" sera aussi rendue comme attr="false".

Notez que pour les autres directives (par ex. v-if et v-show), l’évaluation JavaScript normale est utilisée.

Comment procéder ?

Lancez votre suite de tests si vous en avez. Les tests en échec devraient vous alerter si des parties de votre application sont affectées par ce changement.

Écoute des évènements natifs sur les composants avec v-on changé

Quand vous utilisez un composant, v-on n’écoutera que les évènements $emit émis par ce composant. Pour écouter les évènements natifs du DOM sur l’élément racine, vous devez utiliser le modificateur .native. Par exemple :

<my-component v-on:click.native="doSomething"></my-component>

Comment procéder ?

Lancez votre suite de tests si vous en avez. Les tests en échec devraient vous alerter si des parties de votre application sont affectées par ce changement.

Paramètre d’attribut debounce pour v-model supprimé

Une fonction de rétention (« debounce ») est utilisée pour limiter la fréquence d’exécution des requêtes Ajax et des autres opérations couteuses. L’attribut debounce de Vue pour le paramètre v-model est taillé pour des cas simples, mais en fait il fait la rétention des mises à jour d’état plutôt que des opérations lourdes elles-mêmes. C’est une différence subtile, mais cela amène des limitations quand l’application grandit.

Ces limitations peuvent être mises en évidence avec un indicateur de recherche, comme celui de cet exemple :

{{ searchIndicator }}

Utiliser l’attribut debounce ne donne aucun moyen de détecter l’état « … Frappe en cours » car nous perdons l’accès à l’état en temps réel du champ. En découplant la fonction debounce de Vue cependant, nous sommes capables de faire la rétention seulement des opérations que nous souhaitons limiter, enlevant ainsi l’utilité de la fonctionnalité interne :

<!--
En utilisant la fonction `debounce` de loadash ou d'une autre
bibliothèque dédiée, nous savons que l'implémentation spécifique
de `debounce` sera la meilleure possible et sera utilisable partout.
Pas seulement dans nos templates.
-->
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.js"></script>
<div id="debounce-search-demo">
<input v-model="searchQuery" placeholder="Type something">
<strong>{{ searchIndicator }}</strong>
</div>
new Vue({
el: '#debounce-search-demo',
data: {
searchQuery: '',
searchQueryIsDirty: false,
isCalculating: false
},
computed: {
searchIndicator: function () {
if (this.isCalculating) {
return '⟳ Fetching new results'
} else if (this.searchQueryIsDirty) {
return '... Typing'
} else {
return '✓ Done'
}
}
},
watch: {
searchQuery: function () {
this.searchQueryIsDirty = true
this.expensiveOperation()
}
},
methods: {
// C'est ici que la fonction `debounce` est actuellement utilisée.
expensiveOperation: _.debounce(function () {
this.isCalculating = true
setTimeout(function () {
this.isCalculating = false
this.searchQueryIsDirty = false
}.bind(this), 1000)
}, 500)
}
})

Un autre avantage de cette approche est que parfois la rétention n’est pas la méthode de limitation d’exécution la plus appropriée. Par exemple, quand vous interrogez une API pour des suggestions de recherche, attendre que l’utilisateur se soit arrêté de taper pour commencer à lui offrir des suggestions n’est pas une expérience utilisateur idéale. Ce que vous souhaiteriez probablement à la place est une fonction de découplage (« throttle »). Maintenant, avec l’utilisation d’une bibliothèque comme loadash, refactoriser le code en utilisant la fonction throttle ne prend que quelques secondes.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences du paramètre d'attribut debounce.

Paramètre d’attribut lazy ou number pour v-model remplacés

Les paramètres d’attribut lazy et number sont maintenant des modificateurs, pour rendre cela plus clair. Cela signifie qu’au lieu de :

<input v-model="name" lazy>
<input v-model="age" type="number" number>

Nous utiliserons :

<input v-model.lazy="name">
<input v-model.number="age" type="number">

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences des paramètres d'attributs lazy ou number.

Attribut value avec v-model supprimé

v-model ne se préoccupe plus de la valeur initiale de l’attribut value. Pour plus de prédictibilité, il utilisera toujours la donnée utilisée dans l’instance de Vue comme source de vérité.

Cela signifie que cet élément :

<input v-model="text" value="foo">

lié par cette donnée :

data: {
text: 'bar'
}

va être rendu avec une valeur à "bar" au lieu de "foo". La même chose se passe pour les <textarea> avec du contenu existant. Au lieu de :

<textarea v-model="text">
hello world
</textarea>

vous devrez vous assurer que la valeur initiale pour text est "hello world".

Comment procéder ?

Lancez votre suite de tests ou votre application après mise à jour et vérifiez les avertissements de console à propos d'éléments des valeurs de l'attribut value avec v-model.

Itération de valeur primitive avec v-model et v-for supprimé

Les cas de figure comme celui-ci ne fonctionnent plus :

<input v-for="str in strings" v-model="str">

La raison est que le JavaScript équivalent après compilation de <input> est :

strings.map(function (str) {
return createElement('input', ...)
})

Comme vous pouvez le voir, la liaison bidirectionnelle de v-model n’a plus de sens ici. Définir str avec une autre valeur dans une fonction itérateur ne fera rien car ça ne sera qu’une variable locale dans la portée de la fonction.

À la place, vous pourriez utiliser un tableau d’objet et ainsi v-model pourra mettre à jour le champ avec l’objet. Par exemple :

<input v-for="obj in objects" v-model="obj.str">

Comment procéder ?

Lancez votre suite de tests si vous en avez. Les tests en échec devraient vous alerter si des parties de votre application sont affectées par ce changement.

v-bind:style avec la syntaxe objet et !important supprimé

Ceci ne fonctionne plus :

<p v-bind:style="{ color: myColor + ' !important' }">hello</p>

Si vous voulez vraiment réécrire un autre !important, vous devrez utiliser la syntaxe de chaine de caractères :

<p v-bind:style="'color: ' + myColor + ' !important'">hello</p>

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences des liaisons de style avec !important.

v-el et v-ref remplacés

Pour plus de simplicité, v-el et v-ref ont été fusionnés dans l’attribut ref, accessible depuis l’instance d’un composant via $refs. Cela signifie que v-el:my-element devient ref="myElement" et que v-ref:my-component devient ref="myComponent". Quand il est utilisé sur un élément normal, le ref se réfère à l’élément du DOM, et quand il est utilisé sur un composant, le ref se réfère à l’instance du composant.

Puisque v-ref n’est plus une directive, mais un attribut spécial, il peut également être défini dynamiquement. Ceci est particulièrement utile en combinaison avec v-for. Par exemple :

<p v-for="item in items" v-bind:ref="'item' + item.id"></p>

Précédemment, v-el / v-ref utilisé avec un v-for produisait un tableau d’éléments ou de composants, car il n’y avait aucun moyen de donner un nom unique à chaque élément. Vous pouvez toujours reproduire ce comportement en donnant à chaque élément la même ref :

<p v-for="item in items" ref="items"></p>

À la différence de la 1.x, les $refs ne sont pas réactives, car elles sont enregistrées / mises à jour durant le processus de rendu lui-même. Les rendre réactives demanderait de dupliquer le rendu à chaque changement.

D’un autre côté, $refs est conçu avant tout pour un accès programmatique en JavaScript, il n’est donc pas recommandé de les relier dans les templates, car cela signifierait de se référer à un état qui n’est plus en phase avec l’instance elle même. Cela violerait le vue-modèle piloté par les données de Vue.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences de v-el ou de v-ref.

v-else avec v-show supprimé

v-else n’est plus supporté avec v-show. Utilisez v-if avec une expression négative à la place. Par exemple, au lieu de :

<p v-if="foo">Foo</p>
<p v-else v-show="bar">Pas foo, mais bar</p>

Vous pouvez utiliser :

<p v-if="foo">Foo</p>
<p v-if="!foo && bar">Pas foo, mais bar</p>

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des occurrences de v-else avec v-show.

Directives personnalisées simplifiées

Les directives ont une portée de responsabilité grandement réduite : elles sont maintenant uniquement utilisées pour appliquer des manipulations de DOM de bas niveau. Dans la plupart des cas, il faut utiliser des composants comme principale abstraction de codes réutilisables.

Certaines des différences les plus notables incluent :

Heureusement, puisque les nouvelles directives sont plus simples, vous pouvez les maitriser plus facilement. Lisez le nouveau guide des directives pour en apprendre plus.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de directives définies. L'outil d'aide va toutes vous les pointers, comme dans la plupart des cas vous allez devoir les refactoriser dans un composant.

Modificateur de directive .literal supprimé

Le modificateur .literal a été supprimé, la même chose peut être facilement réalisée en fournissant une chaine de caractères littérale en tant que valeur.

Par exemple, vous pouvez mettre à jour :

<p v-my-directive.literal="foo bar baz"></p>

avec :

<p v-my-directive="'foo bar baz'"></p>

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de modificateurs .literal sur les directives.

Transitions

Attribut transition remplacé

Le système de transition de Vue a changé drastiquement et maintenant il faut utiliser les éléments <transition> et <transition-group> au lieu de l’attribut transition. Il est recommandé de lire le nouveau guide des transitions pour en apprendre plus.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples d'attribut transition.

Vue.transition pour les transitions réutilisables remplacé

Avec le nouveau système de transition, vous pouvez maintenant utiliser les composants pour des transitions réutilisables.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples d'attribut de Vue.transition.

Attribut de transition stagger supprimé

Si vous avez besoin d’échelonner les transitions, vous pouvez contrôler le timing en accédant ou changeant une data-index ou attribut similaire sur un élément. Consultez un exemple ici.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples d'attribut de transition. Au cours de votre mise à jour, vous pouvez également passer à la nouvelle stratégie d'échelonnage.

Évènements

Option events supprimée

L’option events a été retirée. Les gestionnaires d’évènements doivent maintenant être abonnés dans le hook created à la place. Consultez le guide $dispatch et $broadcast pour plus de détails.

Vue.directive('on').keyCodes remplacé

La nouvelle, et plus concise, manière de configurer keyCodes à travers Vue.config.keyCodes. Par exemple :

// enable v-on:keyup.f1
Vue.config.keyCodes.f1 = 112

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vieilles configurations de syntaxe keyCode.

$dispatch et $broadcast remplacés

$dispatch et $broadcast ont été remplacés en faveur d’une communication plus explicite entre composants et des solutions de gestion d’état plus maintenables, comme Vuex.

Le problème est que le flux d’évènement dépend de la structure de l’arbre des composants qui peut être dur à appréhender et très fragile quand l’arbre devient large. Il ne s’adaptait pas correctement et nous ne voulons pas qu’il amène plus de mal que de bien. $dispatch et $broadcast ne résolvaient pas non plus la communication entre les composants voisins.

L’un des usages les plus communs de ces méthodes était la communication entre un parent et ses enfants directs. Dans ces cas, vous pouvez en fait écouter un $emit depuis un enfant avec v-on. Cela vous permet de garder la commodité des évènements en étant plus explicite.

Cependant, quand on communique entre descendant ou ancêtres distants, $emit ne nous aidera pas. À la place, le plus simple serait de centraliser les changements dans un canal d’évènements centralisé. Cela vous apporte la possibilité de communiquer entre composants sans vous soucier de là où ils sont dans l’arbre des composants (même entre voisins !). Parce que les instances de Vue implémentent une interface d’émission d’évènement, vous pouvez en fait utiliser une instance de Vue vide pour réaliser cela.

Par exemple, imaginons que nous avons une application de liste de tâches comme celle-là :

Todos
|-- NewTodoInput
|-- Todo
|-- DeleteTodoButton

Nous pourrions gérer la communication entre ces composants avec ce simple canal d’évènement :

// Ceci est le canal d'évènement que nous utiliserons dans
// tous les composants pour communiquer entre eux.
var eventHub = new Vue()

Maintenant dans nos composants, nous pouvons utiliser $emit, $on et $off pour respectivement émettre des évènements, écouter des évènements et nettoyer les écouteurs d’évènements :

// NewTodoInput
// ...
methods: {
addTodo: function () {
eventHub.$emit('add-todo', { text: this.newTodoText })
this.newTodoText = ''
}
}
// DeleteTodoButton
// ...
methods: {
deleteTodo: function (id) {
eventHub.$emit('delete-todo', id)
}
}
// Todos
// ...
created: function () {
eventHub.$on('add-todo', this.addTodo)
eventHub.$on('delete-todo', this.deleteTodo)
},
// Il est bon de nettoyer les écouteurs d'évènements avant
// la destruction du composant.
beforeDestroy: function () {
eventHub.$off('add-todo', this.addTodo)
eventHub.$off('delete-todo', this.deleteTodo)
},
methods: {
addTodo: function (newTodo) {
this.todos.push(newTodo)
},
deleteTodo: function (todoId) {
this.todos = this.todos.filter(function (todo) {
return todo.id !== todoId
})
}
}

Ce modèle peut servir de remplacement à $dispatch et $broadcast dans des scénarios simples. Pour des cas plus complexes, il est recommandé d’utiliser une couche de gestion d’état dédiée comme Vuex.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de $dispatch et $broadcast.

Filtres

Filtres en dehors des interpolations de texte supprimé

Les filtres peuvent maintenant seulement être utilisés à l’intérieur des interpolations de texte (Ouverture et fermeture {{ }}). Avant, il était possible d’utiliser ses filtres sur v-model, v-on, etc. mais cela menait à plus de complexité et d’inconvénient. Pour filtrer les listes sur v-for, il est plus logique de déplacer cela dans la partie propriétés calculées du JavaScript, ainsi cela peut-être réutilisé à travers votre composant.

En général, chaque fois que quelque chose peut-être fait en JavaScript, nous voulons éviter d’introduire une syntaxe spéciale comme les filtres pour prendre en charge les mêmes choses. Voici comment vous pouvez remplacer les directives de filtre de Vue :

Remplacer le filtre debounce

Au lieu de :

<input v-on:keyup="doStuff | debounce 500">
methods: {
doStuff: function () {
// ...
}
}

utilisez le debounce de lodash (ou également throttle) pour limiter directement l’appel des méthodes couteuses en ressource. Vous pouvez ainsi arriver au même résultat qu’au-dessus ainsi :

<input v-on:keyup="doStuff">
methods: {
doStuff: _.debounce(function () {
// ...
}, 500)
}

Pour en savoir plus sur les avantages de cette stratégie, regardez l’exemple ici avec v-model.

Remplacer le filtre limitBy

À la place de :

<p v-for="item in items | limitBy 10">{{ item }}</p>

Utiliser la méthode native .slice du JavaScript dans une propriété calculée :

<p v-for="item in filteredItems">{{ item }}</p>
computed: {
filteredItems: function () {
return this.items.slice(0, 10)
}
}

Remplacer le filtre filterBy

Au lieu de :

<p v-for="user in users | filterBy searchQuery in 'name'">{{ user.name }}</p>

Utiliser la méthode native .filter du JavaScript dans une propriété calculée :

<p v-for="user in filteredUsers">{{ user.name }}</p>
computed: {
filteredUsers: function () {
var self = this
return self.users.filter(function (user) {
return user.name.indexOf(self.searchQuery) !== -1
})
}
}

La fonction JavaScript native .filter peut également gérer des opérations de filtrage plus complexes, car vous avez accès à toute la puissance de JavaScript dans les propriétés calculées. Par exemple, si vous souhaitez trouver tous les utilisateurs actifs avec une concordance non sensible à la casse de leur nom et de leur email :

var self = this
self.users.filter(function (user) {
var searchRegex = new RegExp(self.searchQuery, 'i')
return user.isActive && (
searchRegex.test(user.name) ||
searchRegex.test(user.email)
)
})

Remplacer le filtre orderBy

Au lieu de :

<p v-for="user in users | orderBy 'name'">{{ user.name }}</p>

Utilisez le orderBy de lodash (ou également sortBy) dans une propriété calculée :

<p v-for="user in orderedUsers">{{ user.name }}</p>
computed: {
orderedUsers: function () {
return _.orderBy(this.users, 'name')
}
}

Vous pouvez même ordonner par plusieurs colonnes :

_.orderBy(this.users, ['name', 'last_login'], ['asc', 'desc'])

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de filtres utilisés dans les directives. Si vous en oubliez, vous devriez également voir des erreurs dans la console.

Syntaxe d’argument de filtre changée

La syntaxe pour les arguments de filtre est maintenant plus consistante avec l’invocation des fonctions JavaScript. Donc au lieu d’utiliser des délimitations avec espace pour les arguments :

<p>{{ date | formatDate 'YY-MM-DD' timeZone }}</p>

Nous entourons les arguments avec des parenthèses et les délimitons avec des virgules :

<p>{{ date | formatDate('YY-MM-DD', timeZone) }}</p>

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vieilles syntaxes de filtre. Si vous en oubliez, vous devriez également voir des erreurs dans la console.

Filtres de texte intégré supprimés

Bien que les filtres dans les interpolations de texte soient toujours autorisés, tous les filtres ont été retirés. À la place, nous recommandons d’utiliser des bibliothèques spéciales pour résoudre les problèmes dans chaque domaine (par ex. date-fns pour le format des dates et accounting pour le format des devises).

Vous trouverez de quoi remplacer chaque filtre de texte dans la liste ci-dessous. L’exemple de code peut exister dans des fonctions utilitaires personnalisées, méthodes ou propriétés calculées.

Remplacer le filtre json

Vous n’avez rien besoin de faire de ce point de vue, car Vue va joliment formater la sortie pour vous automatiquement, qu’il s’agisse d’une chaine de caractères, d’un nombre, d’un tableau ou d’un objet complet. Si vous voulez une fonctionnalité identique en JavaScript, c’est JSON.stringify. Vous pouvez donc utiliser cela dans une méthode ou dans une propriété calculée.

Remplacer le filtre capitalize

text[0].toUpperCase() + text.slice(1)

Remplacer le filtre uppercase

text.toUpperCase()

Remplacer le filtre lowercase

text.toLowerCase()

Remplacer le filtre pluralize

Le package pluralize sur npm adresse très bien ces problèmes, mais si vous voulez uniquement mettre au pluriel un mot spécifique ou que vous voulez une sortie spéciale pour dès cas comme 0, vous pouvez facilement définir votre propre fonction de mise au pluriel. Par exemple :

function pluralizeKnife (count) {
if (count === 0) {
return 'no knives'
} else if (count === 1) {
return '1 knife'
} else {
return count + 'knives'
}
}

Remplacer le filtre currency

Pour toutes les implémentations basiques, vous pouvez juste faire quelque chose comme ceci :

'$' + price.toFixed(2)

Dans beaucoup de cas cependant, vous allez toujours tomber sur des comportements étranges (par ex. : 0.035.toFixed(2) va être arrondi à l’entier supérieur alors que 0.045 va être arrondi à l’entier inférieur). Pour résoudre ces problèmes, vous pouvez utiliser la bibliothèque accounting pour des formats de devises plus solides.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de filtres obsolètes. Si vous en oubliez, vous devriez également voir des erreurs dans la console.

Filtres bidirectionnels remplacés

Beaucoup d’utilisateurs adorent utiliser des filtres bidirectionnels avec v-model pour créer des champs intéressants avec très peu de code. Si simple d’apparence, les filtres bidirectionnels peuvent aussi cacher un grand niveau de complexité et encourager une expérience utilisateur pauvre en rendant lente la mise à jour des états. À la place, la création d’un champ dans un composant est recommandée et permet de mieux appréhender son utilisation et d’y ajouter tout ce qu’il faut pour de la création de champs personnalisés.

Par exemple, nous allons migrer un filtre de devise bidirectionnel :

Il fonctionne plutôt bien, mais la rétention de mise à jour d’état peut causer des comportements étranges. Par exemple, cliquez sur l’onglet Result et essayez d’entrer la valeur 9.999 dans l’un des champs. Quand le champ perd le focus, sa valeur va être mise à jour à $10.00. Quand vous regardez le total calculé cependant, vous verrez que 9.999 est toujours stocké dans nos données. La version de la réalité que l’utilisateur voit est hors de synchro !

Pour commencer a utiliser une solution plus robuste en utilisant Vue 2.0, commençons par entourer ce filtre dans un nouveau composant <currency-input> :

Celui-ci nous permet d’ajouter des comportements qu’un filtre seul ne pourrait pas encapsuler, comme sélectionner le contenu d’un champ lors du focus. Maintenant, la prochaine étape va être d’extraire la logique métier du filtre. Ci-dessous, nous allons tout mettre dans un objet currencyValidator externe :

Cette augmentation de la modularité ne permet pas seulement de rendre plus facile la migration vers Vue 2, mais permet également à l’analyse et au formatage d’être :

Avec ce validateur extrait, nous sommes plus à l’aise pour construire une solution plus robuste. L’étrangeté de changement d’état a été éliminée et il est en fait impossible pour l’utilisateur d’entrer une valeur fausse, de la même manière que le fait le champ numérique natif des navigateurs.

Nous sommes toujours limités cependant, par les filtres et par Vue 1.0 en général. Donc terminons notre mise à jour vers Vue 2.0 :

Vous pouvez remarquer que :

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de filtres utilisant des directives comme v-model. Si vous en oubliez, vous devriez également voir des erreurs dans la console.

Slots

Slots dupliqués supprimés

Il n’est plus possible d’avoir deux <slot> avec le même nom dans le même template. Quand le rendu d’un slot est fait, il est réputé déjà rendu et son rendu ne doit plus être refait dans le même arbre de rendu. Si vous devez faire le rendu d’un même contenu, à des endroits différents, passez le contenu en tant que prop.

Comment procéder ?

Lancez votre suite de tests ou votre application après mise à jour et vérifiez les avertissements de console à propos de slots v-model dupliqués.

Attribut de stylisation slot supprimé

Le contenu inséré via un <slot> nommé ne préservera plus l’attribut slot. Utilisez un élément englobant pour le styliser, ou pour des cas avancés, modifiez le contenu inséré programmatiquement en utilisant des fonctions de rendu.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des sélecteurs CSS ciblant des slots nommés (par ex. : [slot="my-slot-name"]).

Attributs spéciaux

Attributs keep-alive remplacés

keep-alive n’est plus un attribut spécial, mais un composant enveloppant, similaire à <transition>. Par exemple :

<keep-alive>
<component v-bind:is="view"></component>
</keep-alive>

Cela permet d’utiliser <keep-alive> sur de multiples enfants conditionnels :

<keep-alive>
<todo-list v-if="todos.length > 0"></todo-list>
<no-todos-gif v-else></no-todos-gif>
</keep-alive>

Quand <keep-alive> a plusieurs enfants, ils devraient être évalués comme un seul enfant. Tout autre enfant autre que le premier sera simplement ignoré.

Quand vous les utilisez avec <transition>, assurez-vous de les imbriquer ainsi :

<transition>
<keep-alive>
<component v-bind:is="view"></component>
</keep-alive>
</transition>

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver les attributs keep-alive.

Interpolation

Interpolation dans les attributs supprimée

L’interpolation dans les attributs ne fonctionne plus. Par exemple :

<button class="btn btn-{{ size }}"></button>

Doit maintenant être mis à jour pour être utilisé dans une expression avec v-bind :

<button v-bind:class="'btn btn-' + size"></button>

Ou une propriété de data ou de computed :

<button v-bind:class="buttonClasses"></button>
computed: {
buttonClasses: function () {
return 'btn btn-' + size
}
}

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples d'interpolation utilisée dans les attributs.

Interpolation HTML supprimée

L’interpolation HTML ({{{ foo }}}) a été retirée. La directive v-html est maintenant préférée.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des interpolations.

Liaisons à un seul rendu remplacées

Les liaisons à un seul rendu ({{* foo }}) ont été remplacées par la nouvelle directive v-once.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des liaisons un seul rendu.

Réactivité

vm.$watch changé

Les observateurs créés via vm.$watch sont maintenant levés avant le rendu des composants associés. Cela vous laisse le temps de mettre à jour l’état avant le rendu du composant, retirant de fait les mises à jour inutiles. Par exemple, vous pouvez observer une prop d’un composant et mettre à jour les données de ce composant quand la prop change.

Si vous aviez précédemment relié vm.$watch à quelque chose du DOM après les mises à jour des composants, vous pouvez maintenant le faire dans le hook de cycle de vie updated.

Comment procéder ?

Lancez votre suite de tests si vous en avez. Les tests en échec devraient vous alerter du fait que les observateurs sont liés à un ancien comportement.

vm.$set changé

vm.$set est maintenant simplement un alias de Vue.set.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples d'utilisations obsolètes.

vm.$delete changé

vm.$delete est maintenant simplement un alias de Vue.delete.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples d'utilisations obsolètes.

Array.prototype.$set supprimé

Utilisez Vue.set à la place.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de .$set sur un tableau. Si vous en oubliez, vous devriez voir des erreurs console sur la méthode manquante.

Array.prototype.$remove supprimé

Utilisez Array.prototype.splice à la place. Par exemple :

methods: {
removeTodo: function (todo) {
var index = this.todos.indexOf(todo)
this.todos.splice(index, 1)
}
}

Ou encore mieux, passez simplement l’index de l’objet à retirer :

methods: {
removeTodo: function (index) {
this.todos.splice(index, 1)
}
}

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de .$remove sur un tableau. Si vous en oubliez, vous devriez voir des erreurs console sur la méthode manquante.

Vue.set et Vue.delete sur les instances de Vue supprimé

Vue.set et Vue.delete ne fonctionnent plus avec les instances de Vue. Il est maintenant obligatoire de déclarer toutes les propriétés de haut niveau en tant que propriétés réactives dans l’option data. Si vous voulez supprimer des propriétés d’une instance de Vue ou des $data, mettez-les à null.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de Vue.set ou Vue.delete sur une instance de Vue. Si vous en oubliez, vous devriez voir des erreurs console sur la méthode manquante.

Remplacement de vm.$data supprimé

Il est maintenant interdit de remplacer l’objet $data d’une instance racine de Vue. Cela permet d’éviter les effets de bord dans le système de réactivité et permet à l’état du composant d’être plus prévisible (spécialement avec les systèmes de vérification de type).

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$data écrasées. Si vous en oubliez, vous devriez voir des erreurs console.

vm.$get supprimé

Retrouvez simplement la donnée réactive.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$get. Si vous en oubliez, vous devriez voir des erreurs console.

Méthodes d’instance centrées sur le DOM

vm.$appendTo supprimé

Utilisez l’API native du DOM :

myElement.appendChild(vm.$el)

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$appendTo. Si vous en oubliez, vous devriez voir des erreurs console.

vm.$before supprimé

Utilisez l’API native du DOM :

myElement.parentNode.insertBefore(vm.$el, myElement)

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$before. Si vous en oubliez, vous devriez voir des erreurs console.

vm.$after supprimé

Utilisez l’API native du DOM :

myElement.parentNode.insertBefore(vm.$el, myElement.nextSibling)

ou si myElement est le dernier enfant :

myElement.parentNode.appendChild(vm.$el)

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$after. Si vous en oubliez, vous devriez voir des erreurs console.

vm.$remove supprimé

Utilisez l’API native du DOM :

vm.$el.remove()

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$remove. Si vous en oubliez, vous devriez voir des erreurs console.

Meta méthodes d’instance

vm.$eval supprimé

Pas réellement utile. Si vous avez des difficultés liées à cette fonctionnalité et que vous n’êtes pas certain de savoir comment faire autrement, vous pouvez poster sur le forum et partagez vos idées.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$eval. Si vous en oubliez, vous devriez voir des erreurs console.

vm.$interpolate supprimé

Pas réellement utile. Si vous avez des difficultés liées à cette fonctionnalité et que vous n’êtes pas certain de savoir comment faire autrement, vous pouvez poster sur le forum et partager vos idées.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$interpolate. Si vous en oubliez, vous devriez voir des erreurs console.

vm.$log supprimé

Utilisez le Devtools de Vue pour une expérience de débogage optimale.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de vm.$log. Si vous en oubliez, vous devriez voir des erreurs console.

Instance DOM Options

replace: false supprimé

Les composants remplacent maintenant les éléments sur lesquels ils sont liés. Pour simuler le comportement de replace: false, vous devez encadrer votre composant racine avec un élément similaire à celui que vous remplacez. Par exemple :

new Vue({
el: '#app',
template: '<div id="app"> ... </div>'
})

Ou avec une fonction de rendu :

new Vue({
el: '#app',
render: function (h) {
h('div', {
attrs: {
id: 'app',
}
}, /* ... */)
}
})

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de replace: false.

Configuration globale

Vue.config.debug supprimée

N’est plus nécessaire car les avertissements se trouvent dans la pile des traces par défaut maintenant.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de Vue.config.debug.

Vue.config.async supprimée

Async est maintenant requis pour les performances de rendu.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de Vue.config.async.

Vue.config.delimiters remplacée

Cela a été retravaillé en temps qu’option de composant. Cela vous permet d’utiliser un délimiteur alternatif dans votre application sans entrer en conflit avec des composants tiers.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de Vue.config.delimiters.

Vue.config.unsafeDelimiters supprimée

L’interpolation HTML a été retirée en faveur de v-html.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de Vue.config.unsafeDelimiters. Après cela, l'outil d'aide va aussi trouver les instances d'interpolation HTML, ainsi vous pourrez les remplacer avec `v-html`.

API globale

Vue.extend avec el supprimée

L’option el ne peut plus être utilisée avec Vue.extend. Elle est seulement valide en tant qu’option de création d’instances.

Comment procéder ?

Lancez votre suite de tests ou votre application après mise à jour et vérifiez les avertissements de console à propos de l'option el avec Vue.extend.

Vue.elementDirective supprimée

Utilisez des composants à la place.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de Vue.elementDirective.

Vue.partial supprimée

Les partiels ont été retirés en faveur d’un flux de donnée plus explicite entre les composants, en utilisant les props. Partout où vous utilisiez des partiels dans des zones de performances critiques, la recommandation est simplement d’utiliser un composant normal à la place. Au cas où vous liez dynamiquement le name du partiel, vous pouvez utiliser un composant dynamique.

Si vous utilisiez des partiels dans des parties de votre application aux performances critiques, vous devriez les améliorer avec des composants fonctionnels. Ils seront entièrement en JavaScript ou JSX dans un fichier dédié (plutôt que dans un fichier .vue) et seront sans état et sans instance, exactement comme les partiels. Cela rendra le rendu extrêmement rapide.

Le bénéfice des composants fonctionnels face aux partiels est qu’ils peuvent être bien plus dynamiques, car ils vous permettent d’accéder à toute la puissance de JavaScript. Il y a un cout à cette puissance cependant. Si vous n’avez jamais utilisé un framework avec des composants de rendu avant, cela peut prendre un peu de temps pour l’apprentissage.

Comment procéder ?

Lancez l'outil d'aide à la migration sur votre code pour trouver des exemples de Vue.partial.