如何让 Flow 与 Vue 2 (webpack) 一起正常工作?
Posted
技术标签:
【中文标题】如何让 Flow 与 Vue 2 (webpack) 一起正常工作?【英文标题】:How to get Flow to properly work with Vue 2 (webpack)? 【发布时间】:2017-02-27 12:56:18 【问题描述】:我正在尝试将 Flow 添加到 Vue 2 webpack 模板中。作为记录,我只在运行时(文件遵循.vue
格式/标准)。
我的第一次尝试是通过 cli 使用 flow,但我意识到它不会起作用,因为它不知道如何处理 .vue
文件。
我的第二次尝试是添加一个 webpack 加载器(即 flow-status-webpack-plugin)并在构建过程中运行 Flow check(例如 eslint
工作)。没有成功,所以我研究了其他选项。
我的第三次尝试是使用 babel 插件,一开始还算成功。我用babel-plugin-typecheck + babel-plugin-syntax-flow。 Webpack 中没有输出,但是类型错误会破坏应用程序。我对这种方法很好;它可以与 CI 一起正常工作并破坏构建。
这是我的.babelrc
的样子:
...
"plugins": [
...
["typecheck",
"disable":
"production": true
],
"syntax-flow",
"transform-flow-strip-types"
],
...
此时,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>
最重要的是,目标是不要因为 Flow 而更改应用程序代码。理想情况下,我会像往常一样使用 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 方面的经验一样(提示:没有那么有经验)。我想我需要一些类型文件来让 Flow“理解”Vue 组件的结构(我猜对指令也是如此)。
对于那些有更多经验的人,您是如何让 Flow 与 Vue + webpack 正常工作的?
【问题讨论】:
【参考方案1】:我已经用flow
为vue
实现了一个项目模板。 https://github.com/wemake-services/wemake-vue-template 它支持单文件组件、linting、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>
它需要配置几件事:
-
依赖关系。名称中带有
flow
的所有内容都来自这里:https://github.com/wemake-services/wemake-vue-template/blob/master/template/package.json
创建有效的.flowconfig
。这可能很棘手:https://github.com/wemake-services/wemake-vue-template/blob/master/template/.flowconfig
配置.babelrc
:https://github.com/wemake-services/wemake-vue-template/blob/master/template/.babelrc
配置eslint
:https://github.com/wemake-services/wemake-vue-template/blob/master/template/.eslintrc
每次正常安装后触发flow-typed install
:https://github.com/wemake-services/wemake-vue-template/blob/master/template/package.json#L12
vuex
您还可以注释vuex
store:状态、提交处理程序、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
【讨论】:
【参考方案2】:使用 eslint + 流
这是集成 flow 和 vue 的另一种方法。
与此同时,flow
来到了eslint
。因此,我们可以直接将流错误视为 lint 错误。这是一种更简洁的方法,但随后流程与您的构建过程相结合(您不能独立运行flow check
,但需要通过 webpack 运行整个构建管道以获取错误)。截至2017 年 5 月 10 日,仍在等待 this issue 得到解决,以便在 .vue
文件中获得完整的流支持。
在大多数情况下这很好,但有些人可能仍然希望运行 flow check
的灵活性(和速度)。这也可能取决于您的 CI 设置。
以下是设置 flow 和 eslint 的方法:
安装依赖
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
配置.babelrc
...
"plugins": [
"babel-plugin-transform-class-properties",
"babel-plugin-syntax-flow",
"babel-plugin-transform-flow-strip-types"
]
配置.eslintrc
"parser": "babel-eslint",
"plugins": [
"html",
"flowtype-errors"
],
"extends": [
"vue"
],
"rules":
"flowtype-errors/show-errors": 2
创建一个.flowconfig
文件。如果您没有要配置的内容,它可以为空。
在这种情况下不需要其他解决方法,然后您可以在任何.vue
文件的脚本标签中使用/* @flow */
。
见原帖here。
【讨论】:
我无法让它工作。我全力以赴并重新安装了 Atom 以确保一切设置正确,但我仍然无法在我的 Vue 组件中显示任何错误。如果我强制 Atom 将其解析为 javascript 文件,它仍然可以工作。嗯..你用的是什么编辑器?使用 linter-eslint 包来支持 ESLint。有什么想法吗 ?把它弄起来真是太好了。 搞定了!我必须将 linter-eslint 包激活为“Lint HTML 文件”,因为这将激活 .vue 文件的 linting。 太棒了。让它在 Atom 中的 Sublime 中工作(供参考)。编码愉快!【参考方案3】:我认为这个问题已经解决了,现在你可以在没有 hack 的情况下使用 Flow 和 Vue 组件。有关配置详细信息,请参阅这篇相当精彩的文章: https://alligator.io/vuejs/components-flow/
【讨论】:
嘿@musicformellons。这是另一种方法,但请注意,如果您选择 eslint 方法,flow check
将不起作用。见detailed explanation。不过,一种有效的方法:-)【参考方案4】:
除了Nik's answer,值得一提的是,将他的“评论”策略与运行时检查器相结合,使“包”更加完整。
一种方法是使用babel-plugin-tcomb。这将使运行时检查器成为 webpack / 构建过程的一部分(保存时)+ 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 使用相同的注解(内部使用 Flow),因此它可以开箱即用。
Ofc,这还不够好,有点违背了 Flow 的观点。如前所述,解决方案仍然是在 CI 上运行 flow check
。这需要进行一些更改:
更新 .flowconfig 以加载 .vue 文件:
...
[options]
module.file_ext=.vue
module.file_ext=.js
...
在包含@flow pragma 的注释中包含模板和样式块;注释掉脚本标签(here提到了这种方法):
/* @flow
<template>...</template>
<style>...</style>
*/
// <script>
...
// </script>
这有点尴尬,但我找不到更好的方法。理想情况下,Flow 将能够处理 HTML 文档中的 <script>
标签,但这只是目前的愿望清单 (see issue)。
在生产环境中禁用 tcomb
...
"plugins": [
...
"syntax-flow",
"transform-flow-strip-types"
],
"env":
"development":
"plugins": ["tcomb"]
【讨论】:
问题:如果我像 vue 2.0 boilerplate example 那样在开头构建我的组件,其中 .vue 仅加载外部 .js 和 .html 并让流 cli 忽略 .vue 并仅检查 .js 它可以也可以在没有丑陋的修改的情况下工作(因为它在开始时是分开的)。你怎么看? 是的,应该没问题。除非您在流程配置文件中明确声明,否则默认情况下不会检查 Vue 文件。【参考方案5】:您仍然可以将 Flow 用于 .vue 组件的 JS 部分,方法是注释掉 <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>
部分,但 Flow 类型检查器将忽略它们并仅处理正确的 javascript 部分。
不幸的是,这不会让您获得 100% 的类型覆盖率,因为 Flow 将无法检查附加到 this
(Vue 组件本身)的函数和对象,但是,您仍然可以从 Flow 的类型检查中受益调用外部函数(例如 Vuex 操作和 getter,其他 javascript 导入模块),如果您在组件的方法中扩展了业务逻辑,则在使用方法参数时可以获得一些类型安全。
【讨论】:
这太糟糕了。我希望有一种方法可以获得 100% 的覆盖率,也许是一些 Flow 注释魔术,但我开始相信没有。关于注释掉这些部分,使用 babel-plugin-typecheck 不需要注释掉模板和样式,因为它只检查脚本中的内容。它的工作方式与流式 webpack 插件或通过 CLI 运行流式有很大不同,但到目前为止我没有任何问题。 我再给它几天,如果没有其他关于如何实现这一点的建议,我会接受你的回答:-) 好的@Nik。在开发期间通过babel-plugin-tcomb 进行运行时检查+flow check
作为CI 的一部分,设法让它按照我最初想要的方式运行。在新答案中编写了我的配置;也许它会帮助别人。我会保持你的接受。感谢您的帮助。以上是关于如何让 Flow 与 Vue 2 (webpack) 一起正常工作?的主要内容,如果未能解决你的问题,请参考以下文章
如何让 react-hot-loader 与 webpack 2 和 webpackDevMiddleware 一起工作?
旧版vue-cli脚手架Webpack3项目如何升级Webpack4
Honeybadger projectRoot 与 webpack