web-dev-qa-db-ja.com

FlowをVue 2(webpack)で正しく動作させる方法は?

Flow をVue 2 webpack-templateに追加しようとしています。記録のために、私はランタイムのみを使用しています(ファイルは.vue形式/標準に従います) )。

私の最初の試みは、CLIを介したフローを使用することでしたが、.vueファイルの処理方法がわからなかったため、動作しないことに気付きました。

私の2番目の試みは、webpackローダー(つまり flow-status-webpack-plugin )を追加し、ビルドの一部としてフローチェックを実行することでした(たとえば、eslintは機能します)。それはうまくいかなかったので、私は他のオプションを調べました。

私の3番目の試みは、最初はかなり成功したbabelプラグインを使用することでした。 babel-plugin-typecheck + babel-plugin-syntax-flow を使用しました。 Webpackには出力はありませんが、タイプエラーが発生するとアプリが破損します。私はこのアプローチで大丈夫です。 CIで正常に動作し、ビルドを中断します。

.babelrcの外観は次のとおりです。

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

この時点で、フローはグローバルメソッドで期待どおりに機能しますが、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>

これが私のFlowの経験と同じようにVueと関係があるかどうかはわかりません(ヒント:それほど経験はありません)。Flow 'を理解させるタイプのファイルが必要だと思います。 'Vueコンポーネントの構造(私が推測するディレクティブについても同じ)。

それをより経験している人にとって、FlowをVue + webpackで適切に動作させるにはどうすればよいですか?

14
Dan Mindru

<template><style>、および<script>の部分をコメントアウトすることで、.vueコンポーネントのJS部分にフローを引き続き使用できます。

 /* @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セクションのみを処理します。

残念ながら、Flowはthis(Vueコンポーネント自体)にアタッチされた関数とオブジェクトをチェックできないため、これでは100%の型カバレッジは得られません。 Flowの外部関数(Vuexアクションとゲッター、その他のjavascriptインポートモジュールなど)への呼び出しの型チェックを引き続き利用できます。また、コンポーネントのメソッド内にビジネスロジックを拡張している場合は、メソッドを操作するときに型の安全性を確保できます。パラメーター。

5
Nik

Eslint +フローの使用

これは、フローとビューを統合するためのさらに別のアプローチです。その間、floweslintに来ました。したがって、フローエラーをリントエラーとして直接取得できます。これはよりクリーンなアプローチですが、フローはビルドプロセスと結合されます(flow checkを個別に実行することはできませんが、エラーを取得するには、ビルドパイプライン全体をwebpack経由で実行する必要があります)。 2017年5月10日現在、.vueファイルでフルフローをサポートするために この問題 が解決されるのをまだ待っています

ほとんどの場合、これで問題ありませんが、flow checkを実行する際の柔軟性(および速度)が必要な場合もあります。これは、CIの設定にも依存する可能性があります。

フローとエスリントを設定する方法は次のとおりです。

  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. .flowconfigファイルを作成します。構成するものがない場合は、空にすることができます。

この場合、他の回避策は必要ありません。その後、任意の/* @flow */ファイルのスクリプトタグで.vueを使用できます。元の投稿を参照してください ここ

5
Dan Mindru

Nikの答え に加えて、彼の「コメント」戦略をランタイムチェッカーと組み合わせると、「パッケージ」が少し完全になることに言及する価値があります。これを行う1つの方法は、 babel-plugin-tcomb を使用することです。これにより、ランタイムチェッカーがwebpack /ビルドプロセス(保存時)の一部になり、CIスクリプトの一部としてflow checkになります。

開発の場合、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は同じアノテーションを使用する(内部でFlowを使用する)ので、箱から出してすぐに機能します。

多くの場合、それは十分ではなく、フローのポイントをやや打ち負かします。これに対する解決策は、前述のように、CIでflow checkを実行することです。これには多くの変更が必要です。

  1. .flowconfigを更新して.vueファイルをロードします。

    ...
    [options]
    module.file_ext=.vue
    module.file_ext=.js
    ...
    
  2. @flowプラグマを含むコメントにテンプレートとスタイルブロックを含めます。スクリプトタグをコメントアウトします(このアプローチについては ここ ):

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

    それは少し厄介ですが、私はより良い方法を見つけることができませんでした。理想的には、FlowはHTMLドキュメント内の<script>タグを処理できますが、それは今のところウィッシュリストにあります( 問題を参照 )。

  3. 本番環境でtcombを無効にする

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

これは当面は解決されたと思います。今では、ハッキングなしでVueコンポーネントでFlowを使用できます。構成の詳細については、このかなり素晴らしい記事を参照してください: https://alligator.io/vuejs/components-flow/

2
musicformellons

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. 有効な.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:state、commitハンドラー、getter、およびアクションに注釈を付けることもできます。この部分には @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

1
sobolevn