Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Flow to properly work with Vue 2 (webpack)?

I'm trying to add Flow to the Vue 2 webpack-template. For the record, I'm on runtime-only (files follow the .vue format / standard).

My first attempt was to use flow through the cli, which I realized it's not going to work because it didn't know how to handle .vue files.

My second attempt was to add a webpack loader (namely flow-status-webpack-plugin) and run Flow check as part of the build (like eslint works for example). That didn't work out, so I looked into other options.

My third attempt was to use a babel plugin, which was fairly successful at first. I used babel-plugin-typecheck + babel-plugin-syntax-flow. There's no output in Webpack, however a type error would break the app. I'm fine with this approach; it'll work fine with a CI and break the build.

Here's how my .babelrc looked:

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

At this point, Flow works as expected for global methods, but doesn't work inside a Vue component:

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

On top of that, the goal is to not change the app code because of Flow. Ideally, I'd just use Vue as normally:

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

Not sure if this has that much to do with Vue as it has with my experience with Flow (hint: not that experienced). I'm thinking I need some type files that make Flow 'understand' how a Vue component is structured (same for directives I guess).

To those that have more experience with it, how did you get Flow to properly work with Vue + webpack?

like image 794
Dan Mindru Avatar asked Oct 18 '16 09:10

Dan Mindru


People also ask

How do I change the config in Vue Webpack?

The easiest way to tweak the webpack config is providing an object to the configureWebpack option in vue.config.js: The object will be merged into the final webpack config using webpack-merge . Some webpack options are set based on values in vue.config.js and should not be mutated directly.

How do I use flow in a Vue or JavaScript file?

You can now use Flow in your .js files or .vue single-file components just by adding the /* @flow */ annotation to the top of each file or script section.

How to send/receive signals from components using Vuex?

Just add a Vue component called ‘EventBus’ to your main.js, and use it as a way to send/receive signals from components. While this is a great way to work from small to medium sites, when we want to get serious, we need to use Vuex

What is the difference between publicpath and outputdir in Vue config?

For example, instead of modifying output.path, you should use the outputDir option in vue.config.js; instead of modifying output.publicPath, you should use the publicPath option in vue.config.js. This is because the values in vue.config.js will be used in multiple places inside the config to ensure everything works properly together.


3 Answers

Using eslint + flow

This is yet another approach to integrating flow & vue. Meanwhile, flow came to eslint. Therefore, we can get flow errors straight as lint errors. It's a cleaner approach, but then flow becomes coupled with your build process (you can't run flow check independently, but need to run your entire build pipeline via webpack to get the errors). Still waiting for this issue to be resolved to have full flow support in .vue files as of 10th of May 2017.

For most cases that's fine, but some might still want the flexibility (and speed) of running flow check. That might also depend on your CI setup.

Here's how you can setup flow and eslint:

  1. Install 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. Configure .babelrc

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

    {
      "parser": "babel-eslint",
    
      "plugins": [
        "html",
        "flowtype-errors"
      ],
    
      "extends": [
        "vue"
      ],
    
      "rules": {
        "flowtype-errors/show-errors": 2
      }
    }
    
  4. Create a .flowconfig file. It can be empty if you have nothing to configure.

No other workarounds required in this case, you can then just use /* @flow */ in the script tags in any of your .vue files. See the original post here.

like image 174
Dan Mindru Avatar answered Oct 18 '22 08:10

Dan Mindru


You can still use Flow for the JS portion of a .vue component, by commenting out the <template>, <style> and <script> portions:

 /* @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>

The vue compiler will still recognize the <template>, <style> and <script> sections even when commented, but the Flow type checker will ignore them and only process the proper javascript section.

Unfortunately, this won't get you 100% type coverage, as Flow will not be able to check functions and objects attached to this (the Vue component itself), however, you can still benefit from Flow's type checking of calls out to external functions (e.g. Vuex actions and getters, other javascript imported modules), and if you have extended business logic within the component's methods, you can get some type safety when working with the method parameters.

like image 42
Nik Avatar answered Oct 18 '22 09:10

Nik


I think this has been solved in the meantime and now you can use Flow with Vue-components without hacks. See this rather brilliant article for config details: https://alligator.io/vuejs/components-flow/

like image 34
musicformellons Avatar answered Oct 18 '22 08:10

musicformellons