web-dev-qa-db-fra.com

Comment faire en sorte que Flow fonctionne correctement avec Vue 2 (webpack)?

J'essaie d'ajouter Flow au modèle Webpack de Vue 2. Pour mémoire, je suis uniquement à l'exécution (les fichiers suivent le format/norme .vue).

Ma première tentative a été d’utiliser le flux à travers la cli, ce qui m’a permis de comprendre que cela ne fonctionnerait pas car elle ne savait pas comment gérer les fichiers .vue.

Ma deuxième tentative a été d'ajouter un chargeur Webpack (à savoir flow-status-webpack-plugin ) et d'exécuter le contrôle de flux dans le cadre de la construction (comme eslint fonctionne par exemple). Cela n'a pas fonctionné, alors j'ai examiné d'autres options.

Ma troisième tentative a été d'utiliser un plugin babel, ce qui a été assez réussi au début. J'ai utilisé babel-plugin-typecheck + babel-plugin-syntax-flow . Il n'y a pas de sortie dans Webpack, cependant une erreur de type endommagerait l'application. Je suis d'accord avec cette approche. ça va fonctionner avec un CI et casser la construction.

Voici à quoi ressemblait mon .babelrc:

{
  ...
  "plugins": [
    ...
    ["typecheck", {
      "disable": {
        "production": true
      }
    }],
    "syntax-flow",
    "transform-flow-strip-types"
  ],
  ...
}

À ce stade, Flow fonctionne comme prévu pour les méthodes globales, mais ne fonctionne pas dans un composant Vue:

<template>...</template>

<script>
/* @flow */
const flowIt = (a: number): number => {
  return a * 10
}

flowIt(20)
flowIt('bah') // Uncaught TypeError: Value of argument "a" violates contract. Expected: number Got: string

export default {    
  mounted: function () {
    flowIt(20)
    flowIt('bah') // Sees nothing wrong here
  }
}
</script>

<style>...</style>

En plus de cela, l'objectif est de ne pas changer le code de l'application à cause de Flow. Idéalement, j'utiliserais Vue comme normalement:

<template>...</template>

<script>
/* @flow */
export default {  
  methods: {
    flowIt (a: number): number {
      return a * 10
    }
  },

  mounted: function () {
    this.flowIt(20)
    this.flowIt('bah') // Should throw a type error.
  }
}
</script>

<style>...</style>

Je ne sais pas si cela a beaucoup à voir avec Vue comme avec mon expérience avec Flow (indice: pas expérimenté). Je pense avoir besoin de fichiers types qui permettent à Flow de "comprendre" la structure d'un composant Vue (idem pour les directives, je suppose).

Pour ceux qui en ont plus d'expérience, comment avez-vous réussi à faire fonctionner Flow avec Vue + webpack?

13
Dan Mindru

Vous pouvez toujours utiliser Flow pour la partie JS d'un composant .vue en commentant les parties <template>, <style> et <script>:

 /* @flow
 <style>
 ...style definitions here
 </style>
 <template>
 ...html...
 </template>
 */
 // <script>
 export default {  
   methods: {
      flowIt (a: number): number {
         return a * 10
      }
   },

   mounted: function () {
      this.flowIt(20)
      this.flowIt('bah') //Won't throw error, as flowIt is attached to
                         //this.
   }
}
// </script>

Le compilateur de vue reconnaîtra toujours les sections <template>, <style> and <script> même lorsqu'il sera commenté, mais le vérificateur de type de flux les ignorera et ne traitera que la section javascript appropriée.

Malheureusement, cela ne vous apportera pas une couverture de type à 100%, car Flow ne pourra pas vérifier les fonctions et les objets attachés à this (le composant Vue lui-même). Cependant, vous pouvez toujours bénéficier de la vérification de type des appels aux fonctions externes par Flow. (par exemple, actions et accesseurs Vuex, autres modules importés en javascript), et si vous avez une logique métier étendue au sein des méthodes du composant, vous pouvez obtenir une sécurité de type lorsque vous utilisez les paramètres de méthode.

3
Nik

Utiliser eslint + flow

C’est là une autre approche de l’intégration de flow & vue .. Entre-temps, flow est devenu eslint. Par conséquent, nous pouvons obtenir des erreurs de flux directement comme des erreurs de lint. C'est une approche plus propre, mais le flux devient alors associé à votre processus de génération (vous ne pouvez pas exécuter flow check de manière indépendante, mais vous devez exécuter l'ensemble de votre pipeline de génération via Webpack pour obtenir les erreurs). J'attends toujours ce problème à résoudre pour avoir une prise en charge complète des flux dans les fichiers .vue à compter du 10 mai 2017.

Dans la plupart des cas, c'est correct, mais certains voudront peut-être encore la souplesse (et la rapidité) de l'exécution de flow check. Cela peut également dépendre de la configuration de votre CI.

Voici comment vous pouvez configurer flow et eslint:

  1. Installer des deps

    yarn add \
      babel-plugin-syntax-flow \
      babel-plugin-transform-class-properties \
      babel-plugin-transform-flow-strip-types \
      eslint \
      babel-eslint \
      eslint-plugin-html \
      eslint-plugin-flowtype-errors \
      eslint-plugin-vue \
      eslint-config-vue \
      flow-bin \
    -D
    
  2. Configurer .babelrc

    {
      ...
      "plugins": [
        "babel-plugin-transform-class-properties",
        "babel-plugin-syntax-flow",
        "babel-plugin-transform-flow-strip-types"
      ]
    }
    
  3. Configurer .eslintrc

    {
      "parser": "babel-eslint",
    
      "plugins": [
        "html",
        "flowtype-errors"
      ],
    
      "extends": [
        "vue"
      ],
    
      "rules": {
        "flowtype-errors/show-errors": 2
      }
    }
    
  4. Créez un fichier .flowconfig. Il peut être vide si vous n'avez rien à configurer.

Aucune autre solution de contournement n’est requise dans ce cas, vous pouvez simplement utiliser /* @flow */ dans les balises de script de l’un de vos fichiers .vue . Voir le message original ici .

5
Dan Mindru

En plus de la réponse de Nik , il convient de mentionner que la combinaison de sa stratégie de "commentaire" avec un vérificateur d'exécution rend le "paquet" un peu plus complet. Une des façons de le faire est d’utiliser babel-plugin-tcomb . Cela fera du vérificateur d’exécution une partie du processus Webpack/build (lors de la sauvegarde) + flow check dans le cadre d’un script de CI. 

Pour le développement, tcomb effectuera une vérification de l’exécution et lèvera une exception (console). Il ne fait pas de vérifications statiques, donc ce qui suit

<script>
/* @flow */
const flowIt = (a: number): number => {
  return '' // Sees nothing wrong here, should be a number
}

// Vue component
export default {    
  ...
}
</script>

ne fonctionnera pas comme prévu. Cependant, ce qui suit:

<template>{{ foo('bar') }} <!-- Type error --></template>
<script>
/* @flow */
const flowIt = (a: number): number => {
  return '' // Type error
}

// Vue component
export default {    
  methods: {
    foo: (x) => { flowIt(x) // Type error }
  },

  mounted: () => {
    flowIt([]) // Type error
  }
}
</script>

Ce n'est pas idéal, mais cela vérifie après chaque sauvegarde et cela interceptera la plupart des erreurs de type .A noter: tcomb utilise les mêmes annotations (utilise Flow en interne), donc cela fonctionne immédiatement. 

Ofc, ce n'est pas assez bon et déjoue un peu le point de départ de Flow. La solution à cela consiste à exécuter flow check sur le CI, comme indiqué. Cela nécessite un certain nombre de changements:

  1. Mettez à jour .flowconfig pour charger les fichiers .vue:

    ...
    [options]
    module.file_ext=.vue
    module.file_ext=.js
    ...
    
  2. Incluez le bloc template & style dans le commentaire contenant le pragma @flow; commentez les balises de script (cette approche a été mentionnée ici ):

    /* @flow
    <template>...</template>
    
    <style>...</style>
    */
    
    // <script>
    ...
    // </script>
    

    C'est un peu gênant, mais je ne pouvais pas trouver un meilleur moyen. Idéalement, Flow serait en mesure de traiter les balises <script> dans un document HTML, mais cela ne figure que dans la liste de souhaits pour le moment ( voir issue ).

  3. Désactiver tcomb en production

    {
      ...
      "plugins": [
        ...
        "syntax-flow",
        "transform-flow-strip-types"
      ],
      "env": {
        "development": {
          "plugins": ["tcomb"]
        }
      }
    }
    
4
Dan Mindru

Je pense que cela a été résolu entre-temps et que vous pouvez maintenant utiliser Flow avec les composants Vue sans piratage. Voir cet article plutôt brillant pour plus de détails sur la configuration: https://alligator.io/vuejs/components-flow/

2
musicformellons

J'ai implémenté un modèle de projet pour vue avec flow. https://github.com/wemake-services/wemake-vue-template Il prend en charge les composants à fichier unique, le filtrage, les tests avec jest, la construction et le rendu côté serveur.

vue

Voici à quoi ressemblent vos composants:

<template>
...
</template>

<script>
// @flow

import Vue from 'vue'
import { Store } from 'vuex'
import Component from 'nuxt-class-component'
import { Getter, State } from 'vuex-class'
import AppLogo from '~/components/AppLogo'
import Comment from '~/components/Comment'
import type { CommentType, StateType } from '~/types'

@Component({
  components: {
    AppLogo,
    Comment
  }
})
export default class Index extends Vue {
  @State('comments') comments: Array<CommentType>
  @Getter('hasComments') hasComments: boolean

  fetch (
    { store, app }: { store: Store<StateType>, app: Vue }
  ): Promise<Array<CommentType>> {
    // Uncomment the next line to test flow types:
    // console.log(this.comments + 12)
    return store.dispatch('fetchComments', app)
  }
}
</script>

Cela nécessite plusieurs choses à configurer:

  1. Les dépendances. Tout avec flow dans son nom à partir d'ici: https://github.com/wemake-services/wemake-vue-template/blob/master/template/package.json
  2. Créer un .flowconfig valide. Cela peut être délicat: https://github.com/wemake-services/wemake-vue-template/blob/master/template/.flowconfig
  3. Configuration de .babelrc: https://github.com/wemake-services/wemake-vue-template/blob/master/template/.babelrc
  4. Configuration de eslint: https://github.com/wemake-services/wemake-vue-template/blob/master/template/.eslintrc
  5. Déclenchez flow-typed install après chaque installation normale: https://github.com/wemake-services/wemake-vue-template/blob/master/template/package.json#L12

vuex

Vous pouvez également annoter vuex store: state, des gestionnaires de validation, des getters et des actions. Vous pouvez utiliser @vue-flow-typed/vuex pour cette partie.

Voilà à quoi ça ressemble:

type StateType = {
  comments: string[]
}

function state (): StateType {
  return {
    comments: null
  }
}

const getters = {
  hasComments (state: StateType): boolean {
    return Boolean(state.comments && state.comments.length > 0)
  }
}

const mutations = {
  'SET_COMMENTS': (
    state: StateType, comments: string[]
  ) => {
    state.comments = comments
  }
}

const actions = {
  async fetchComments (
    { commit, state }: ActionContext<StateType>
  ) {
    const data = await Promise.resolve(['good', 'Nice'])
    commit('SET_COMMENTS', data)
    // Uncomment next line to see typing in action:
    // console.log(state.comments, state.fake)

    return data
  }
}

Mais attention, il est encore impossible d'annoter certaines parties. En savoir plus sur les problèmes connus ici: https://github.com/sobolevn/vue-flow-typed#known-problems

0
sobolevn