Как заставить Flow правильно работать с Vue 2 (webpack)?

Я пытаюсь добавить поток к Vue 2 webpack-шаблон. Для записи я нахожусь только во время выполнения (файлы следуют за .vue формат / стандарт).

моей первой попыткой было использовать поток через cli, который я понял, что он не будет работать, потому что он не знал, как обращаться .vue файлы.

моей второй попыткой было добавить загрузчик webpack (а именно поток-статус-webpack-плагин) и запустить проверку потока как часть сборки (например,eslint работает, например). Это не сработало, так что я изучил другие варианты.

моей третьей попыткой было использовать плагин babel, который сначала был довольно успешным. Я использовал babel-плагин-typecheck + babel-plugin-syntax-flow. В Webpack нет вывода, однако ошибка типа нарушит приложение. Я в порядке с этим подходом; он будет отлично работать с CI и сломать сборку.

вот как мой .babelrc посмотрел:

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

в этом point, Flow работает как ожидалось для глобальных методов, но не работает внутри компонента 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>

кроме того, цель состоит в том, чтобы не менять код приложения из-за потока. В идеале я бы просто использовал Vue как обычно:

<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>

Не уверен, что это имеет такое же отношение к Vue, как и к моему опыту с потоком (подсказка: не то, что опыт). Я думаю, мне нужны файлы типа, которые заставляют Flow "понимать", как структурирован компонент Vue (то же самое для директив I гадать.)

для тех, кто имеет больше опыта работы с ним, как вы получили поток для правильной работы с Vue + webpack?

5 ответов


вы все еще можете использовать поток для части JS a .компонент vue, комментируя <template>, <style> и <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>

компилятор vue по-прежнему распознает <template>, <style> and <script> разделы даже при комментариях, но проверка типа потока будет игнорировать их и обрабатывать только соответствующий раздел javascript.

к сожалению, это не даст вам 100% покрытия типа, так как Flow не сможет проверять функции и объекты, прикрепленные к this (Vue сам компонент), однако, вы все равно можете извлечь выгоду из проверки типа потока вызовов внешних функций (например, действий и геттеров Vuex, других импортированных модулей javascript), и если у вас есть расширенная бизнес-логика в методах компонента, вы можете получить некоторую безопасность типа при работе с параметрами метода.


использование eslint + flow

это еще один подход к интеграции flow & vue. А пока ... -Пришел -3--> до eslint. Таким образом, мы можем получить ошибки потока прямо как ошибки корпии. Это более чистый подход, но затем поток становится связанным с вашим процессом сборки (вы не можете запустить flow check независимо, но нужно запустить весь конвейер сборки через webpack, чтобы получить ошибки). Все еще жду этот вопрос будет разрешено иметь полную поддержку потока в .vue файлы по состоянию на 10 мая 2017.

в большинстве случаев это нормально, но некоторые все еще могут хотеть гибкости (и скорости) работы flow check. Это также может зависеть от вашей настройки CI.

вот как вы можете настроить поток и eslint:

  1. установить 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. настроить .babelrc

    {
      ...
      "plugins": [
        "babel-plugin-transform-class-properties",
        "babel-plugin-syntax-flow",
        "babel-plugin-transform-flow-strip-types"
      ]
    }
    
  3. настроить .eslintrc

    {
      "parser": "babel-eslint",
    
      "plugins": [
        "html",
        "flowtype-errors"
      ],
    
      "extends": [
        "vue"
      ],
    
      "rules": {
        "flowtype-errors/show-errors": 2
      }
    }
    
  4. создать . Он может быть пустым, если вам нечего настроить.

никаких других обходных путей, необходимых в этом случае, вы можете просто использовать /* @flow */ в тегах скрипта в любом из ваших .vue файлы. Смотрите Оригинальный пост здесь.


кроме Ника!--10-->, стоит отметить, что объединение его стратегии "комментарий" с проверкой времени выполнения делает "пакет" немного более полным. Один из способов сделать это-использовать babel-plugin-tcomb. Это сделает проверку выполнения частью процесса webpack / build (при сохранении) + flow check как часть сценария CI.

для разработки tcomb выполнит проверку времени выполнения и выдаст исключение (консоль). Он не делает статических проверок, поэтому следующее

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

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

не будет работать, как ожидалось. Однако, следующее:

<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>

это не идеально, но он проверяет после каждого сохранения, и это будет ловить большинство ошибок типа. Стоит упомянуть: tcomb использует те же аннотации (использует поток внутри), поэтому он работает из коробки.

Ofc, это недостаточно хорошо и своего рода побеждает точку потока. Решение, что это все-таки запустить flow check на CI, как упоминалось. Это требует нескольких изменения:

  1. обновление .flowconfig для загрузки .файлы vue:

    ...
    [options]
    module.file_ext=.vue
    module.file_ext=.js
    ...
    
  2. включите блок template & style в комментарий ,содержащий @ flow pragma; прокомментируйте теги скрипта (этот подход был упомянут здесь):

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

    это немного неловко, но я не мог найти лучшего способа. В идеале Flow сможет обрабатывать <script> теги в HTML-документе, но пока это только в списке пожеланий (см. вопрос).

  3. отключить tcomb в производстве

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

Я думаю, что это было решено тем временем, и теперь вы можете использовать поток с Vue-компонентами без хаков. См. эту довольно блестящую статью для деталей конфигурации: https://alligator.io/vuejs/components-flow/


я реализовал шаблон проекта для vue С flow. https://github.com/wemake-services/wemake-vue-template он поддерживает один файл компонентов, проверку, тесты с jest, здания, и сервер обработки.

vue

вот как будут выглядеть ваши компоненты:

<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>

для настройки требуется несколько вещей:

  1. зависимостей. Все с flow на свое имя от здесь: https://github.com/wemake-services/wemake-vue-template/blob/master/template/package.json
  2. создание valid .flowconfig. Это может быть сложно: https://github.com/wemake-services/wemake-vue-template/blob/master/template/.flowconfig
  3. настройка .babelrc: https://github.com/wemake-services/wemake-vue-template/blob/master/template/.babelrc
  4. настройка eslint: https://github.com/wemake-services/wemake-vue-template/blob/master/template/.eslintrc
  5. запуск flow-typed install после каждой нормальной установки: https://github.com/wemake-services/wemake-vue-template/blob/master/template/package.json#L12

vuex

вы также можете аннотировать vuex store: состояние, обработчики фиксации, геттеры и действия. Вы можете использовать @vue-flow-typed/vuex для этого часть.

вот как это выглядит:

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
  }
}

но будьте осторожны, что по-прежнему невозможно аннотировать некоторые части. Подробнее об известных вопросов здесь: https://github.com/sobolevn/vue-flow-typed#known-problems