.mydoc_h1{
margin: 0 0 1em;
}
.mydoc_h1_a{
color: #2c3e50;
text-decoration: none;
font-size: 2em;
}
.mydoc_h1_h1{
margin: 45px 0 8px;
padding-bottom: 7px;
font-size: 28px;
}
.mydoc_h1_content{
}.mydoc_p{
line-height: 1.6em;
margin: 1.2em 0 -1.2em;
padding-bottom: 1.2em;
position: relative;
z-index: 1;
color: #333;
}/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.mydoc_code{
overflow-x: auto;
position: relative;
background-color: #f8f8f8;
padding: 0;
line-height: 1.1em;
border-radius: 2px;
margin: 1.2em 0;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8AgMAAABHkjHhAAAACVBMVEWAgIBaWlo+Pj7rTFvWAAAAA3RSTlMHCAw+VhR4AAAA+klEQVQoz4WSMW7EQAhFPxKWNh2FCx+HkaZI6RRb5DYbyVfIJXLKDCFoMbaTKSw/8ZnPAPjaH2xgZcUNUDADD7D9LtDBCLZ45fbkvo/30K8yeI64pPwl6znd/3n/Oe93P3ho9qeh72btTFzqkz0rsJle8Zr81OLEwZ1dv/713uWqvu2pl+k0fy7MWtj9r/tN5q/02z89qa/L4Dc2LvM93kezPfXlME/O86EbY/V9GB9ePX8G1/6W+/9h1dq/HGfTfzT3j/xNo7522Bfnqe5jO/fvhVthlfk434v3iO9zG/UOphyPeinPl1J8Gtaa7xPTa/Dk+RIs4deMvwGvcGsmsCvJ0AAAAABJRU5ErkJggg==');
}
.mydoc_code_pre{
padding: 1.2em 1.4em;
line-height: 1.5em;
margin: 0;
}:not(.mydoc_li) + .mydoc_li, .mydoc_li:first-child{
margin-top: 10px;
}
.mydoc_li + .mydoc_li{
margin-top: -10px;
}
.mydoc_li{
margin: 0;
color: #34495e;
margin-bottom: 10px;
position: relative;
}.mydoc_h2{
margin: 35px 0 0.8em;
}
.mydoc_h2_a{
font-size: 1.5em;
text-decoration: none;
color: #2c3e50;
}
.mydoc_h2_a::before{
content: '';
display: block;
margin-top: -40px;
height: 40px;
visibility: hidden;
}
.mydoc_h2_h2{
margin: 5px 0 8px;
border-bottom: 1px solid #ddd;
font-size: 22px;
padding-bottom: 1em;
}
.mydoc_h2_content{
}.mydoc_strong{
font-weight: 600;
color: #2c3e50;
}.mydoc_a{
color: #42b983;
font-weight: 400;
text-decoration: none;
cursor: pointer;
}.mydoc_blockquote{
padding: 12px 5px 12px 30px;
margin: 2em 0 0 8px;
border-width: 0;
border-left: 4px solid #f66;
background-color: #f8f8f8;
position: relative;
border-bottom-right-radius: 2px;
border-top-right-radius: 2px;
line-height: 1.6em;
}
.mydoc_blockquote::before{
position: absolute;
top: 14px;
left: -12px;
background-color: #f66;
color: #fff;
content: "!";
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
font-weight: bold;
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
font-size: 14px;
border-radius: 10px;
}
.mydoc{
font-size: 14px;
overflow: hidden;
}

这是一个Flow的简易教程,属于笔者学习Flow并不断踩坑的过程总结。内容大多翻译Flow官网已经笔者自己的实践。

JavaScript是一个弱类型的解释性语言,无法在编译环节进行静态类型校验,这给JavaScript代码重构带来了巨大的困难,有一句话说的好——动态类型一时爽,重构全家火葬场,充分说明动态类型在编码阶段的高效和重构阶段的低效,因此大家都希望能够让JavaScript也具备静态类型检查功能。Flow就是一个用于JavaScript的静态类型检查的工具,最早由Facebook在2014年的Scale大会上推出,它让JavaScript也可以进行静态类型校验的开发工作,同时兼容JavaScript的弱类型、动态类型的特性,让我们可以开发出利于重构JavaScript代码。

Flow看似与微软的TypeScript有些类似,不过笔者看来TypeScript更像是另一门新语言,而Flow则更像是仅给JavaScript增加了用于静态类型检查的注解(甚至可以在完全符合es语法的情况下通过增加注释来做静态类型检测)。与其说Flow是一门语言不如说他说一个工具。目前已经有很多JavaScript项目都是用了Flow开发的,例如:vue2、react生态下的很多项目等。

我们可以在前端开发中使用它,当然你也可以使用在nodejs中,或者在任何你想使用它的地方。

Flow的安装方法很多,这里仅介绍npm安装,事实上Facebook提供了一个新一代node包管理工具——yarn,与Flow算是相同生态下的工具,不过两者使用起来差异不大,因此以下实例均仅基于npm。使用npm安装Flow:

npm install flow-bin -g

Flow的通用使用流程是:

  • 初始化Flow项目
  • 开启Flow的后台进程,这样Flow会自动在每一次文件内容变化的时候执行静态类型校验
  • 使用Flow注释书写JavaScript代码
  • Flow自动检测出关于类型的错误,并提示

初始化Flow

因此第一步是初始化一个项目,安装完flow-bin后就可以初始化一个项目了,如果如上所示将flow-bin安装在全局,则可以使用flow命令:

flow init

这个命令要在工程的根目录下执行,执行后就会出现一个名为.flowconfig的文件,Flow监听文件变化需要一个后台进程,而.flowconfig文件就是告诉这个后台进程应该做什么。

[ignore]
[include]
[libs]
[options]
[version]

如上所示,.flowconfig有5部分组成:

  • [include]告诉Flow那些文件是需要监听的,通常Flow仅会校验项目根目录下拥有Flow注解的文件,使用include可以将工程外的文件也指定进来。
  • [ignore]告诉Flow忽略哪些目录或文件,这些目录里面的文件即使有Flow注解也不会被监听。这很适合给node_modules这样的目录使用,以增加Flow执行效率。
  • [libs]告诉Flow使用哪些库定义(library definitions),至于什么是库定义,笔者准备到了高级篇在介绍。
  • [version]指定Flow的版本

开启Flow的后台进程

Flow的最大好处就是能快速地校验你代码的错误,一旦你初始化好你的工程后,就可以开始启动Flow进程去校验代码了:

flow status

这实际上是启动了一个后台进程,停止这个进程只需执行:

flow stop

使用Flow注释书写JavaScript代码

现在我们就可开始写Flow文件了,我们之前说了,Flow的后缀名也是js,那么Flow是怎么知道一个文件是Flow文件还是JavaScript文件呢?Flow虽然完全兼容JavaScript代码,但是如果JavaScript代码出现了type相关的错误,Flow也会在校验时候提示错误的,而对于JavaScript则是运行时候才去报错。两种虽然都是报错,但是有本质上的区别,因此我们必须让Flow区分出哪些是JavaScript文件,哪些是Flow的文件。

Flow区别JavaScript文件的方式非常简单,就是给文件加注解:

// @flow
// js的代码部分

注意注解前边的注释不能省,而且注解要放到文件的最上面。除了// @flow注解,还可以用/* @flow */

加上注解后,Flow的后台进程就会自动监听这些文件的变化,并对其做静态类型校验。

到此为止,理论上我们每修改一个文件就应该能够看到文件的校验结果,但实际上并没有出现更改后的校验结果。因为flow status是一个后台进程,所有我们看不到校验结果,如果想要获得当前校验结构需要再执行一下flow status,这一次执行速度明显会比第一次快很多。虽然速度快了,但是和我们想要的自动监听并提示还有差距,不过没关系,稍后笔者会告诉大家解决方法。

前面介绍的是基于后台进程做自动执行校验,除此之外还可以通过cli命令进行手动校验:

flow check

这种方法的执行速度要比后台进程方式慢。

通过以上方法我们就实现了静态类型校验的工作,但是想要Flow能够像JavaScript一样运行还需要“编译”一下才行。接下来介绍编译器的安装。

Flow需要“编译”为JavaScript才能运行,因此必须选择一个“编译器”。其实将FLow解析为JavaScript的过程称为编译其实并不准确,因为这个“编译”过程仅仅就是把Flow提供的注解语法去除。Flow目前支持两种去除注解的方法——babelflow-remove-types

flow-remove-types是一个轻量级的专门用于去除Flow注解的命令行工具,而babel大家应该个更加熟悉,它是现在最流行的es6编译工具,而且可以很容易的和webpack等前端自动化工具集成,因此笔者仅介绍基于babel的版本。

不过需要注意的是,无论是babel还是flow-remove-types,他们仅是去除Flow的注解,但是并没有进行Flow的静态类型检测。事实上babel已经提供了一个Flow预设插件组(babel-preset-flow),它的会自动集成一个叫transform-flow-strip-types的babel插件来去除Flow注解,但是这个插件并不进行flow check。如何想让babel进行Flow的静态类型校验,这就需要手动集成另外一个插件——babel-plugin-typecheck

接下来进行具体的babel集成步骤,首先安装babel、babel-preset-flow、babel-plugin-typecheck,而babel这种工具我们可以安装在全局:

npm install -g babel-cli
npm install --save-dev babel-preset-flow babel-plugin-typecheck

然后创建babel的配置文件,在根目录下创建.babelrc,然后选择Flow的预设插件组(flow),并手动加上babel-plugin-typecheck插件:

{
  "presets": ["flow"],
  "plugins": ["typecheck"]
}

接着我们就可以使用babel编译我们的Flow代码了,例如我们用Flow开发的源代码在src目录,最终输出在dist目录,只需:

babel src/ -d dist/ --watch

这样我就仅需要babel就完成了校验和编译两项工作,从而不需要Flow的初始化和后台进程,而且使用babel的“--watch”功能解决了之前Flow命令行不能同时监听、提示的缺憾。

貌似大功告成,但是其实还有个问题,分别使用flow-binbabel编译如下代码:

function foo(x){
    return x * 12;     //Flow根据代码,推断foo的x1参数是string类型,string类型不能执行“*”操作,所有这里Flow会报错
}
foo("Hello, world!")

flow-bin会报错,错误类型如注释。而babel则顺利编译。笔者推测为babel-plugin-typecheck仅会对添加了类型注解的变量做类型检验,而不会对未加注解的变量先做推断类型再检验。

除了集成到babel外,我们还希望能够将我们的源代码的编译过程集成到webpack中,实现校验、打包、编译、丑化等工作,以便能够达到一个完整的构建工作流。集成到webpack的过程非常简单,其实就是babel集成到webpack的过程。

先安装webpack,建议将webpack安装到全局,然后安装babel和Flow的loader。

npm install -g webpack

并配置好webpack的配置文件webpack.config.js。因为webpack有模块化打包的功能,所有只要给出指定的入口文件,就能将所有依赖的文件打包成一个文件。例如src下的index.js是我们的入口文件,则:

var path = require('path');
module.exports = {
    entry: './src/index.js',
    output: {
        path: path.join(__dirname ,'/dist/'),
        filename: '[name].js',
    },
    module: {
        loaders: [{
            test: /.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader'
        }]
    }
}

最后只要运行webpack即可。

以上集成仅是个简单例子,我们还需使用webpack做热替换(HMR)交换,并且能够自动刷新页面页面刷新,甚至是和react和vue集成,这些对于熟悉react和vue的朋友都说小case,这里不再具体深入。

如果你不想手动修改babel的配置,可以使用flow-babel-webpack-plugin这个插件,简化babel对flow的配置。

之前的命令行搭配已经很合理了,但是开发时候我们还是更喜欢IDE帮我们提示语法上的错误,事实上Flow可以和几乎所有主流IDE集成,这里仅以webstorm和vscode为例。

和webstorm集成

Flow提供了自己的注解,这算是扩充了es的语法,直接用es的语法检查肯定会报错,首先让我们的webstorm不要对Flow的注解保错,打开file->settings->Language & Framework->JavaScript界面。将JavaScript Version选为Flow,这样webstorm就不会再对Flow注解报错了。但是仅仅这样还能是不提示Flow的校验结果,还需要选择Flow executable,将Flow的cli的路径配置到这里。windows一般是C:\Users\用户名\AppData\Roaming\npm\flow.cmd,mac一般是usr/local/bin/flow。这样Webstorm就能报出Flow的校验错误了。

和vscode集成

直接安装vscode-flow-ide或者Flow-Language-Support插件即可。

以上就是这一期的全部内容,下一期会着重介绍Flow的注解使用。

Flow简易教程——安装篇的更多相关文章

  1. Git简易教程-安装及简单使用

    Git是一种版本控制器,在项目开发中可以用来托管代码 一.下载安装Git 1. Git下载 地址:https://git-scm.com/download/win 2. 安装 检验是否安装成功 电脑桌 ...

  2. Percona XtraDB Cluster简易入门 - 安装篇

    说明 Percona XtraDB Cluster(简称PXC),是由percona公司推出的mysql集群解决方案.特点是每个节点都能进行读写,且都保存全量的数据.也就是说在任何一个节点进行写入操作 ...

  3. BIND简易教程(0):在Ubuntu下源码安装BIND(其实跟前面的教程没太大关系)

    之前介绍过BIND的基本使用啦.关于BIND的入门级使用方法见:http://www.cnblogs.com/anpengapple/p/5877661.html简易教程系列,本篇只讲BIND安装. ...

  4. BIND简易教程(1):安装及基本配置

    首先,为什么说是简易教程呢?因为BIND的功能实在太多,全写出来的话要连载好久,我觉得我没有那么多精力去写:而我了解的仅仅是有限的一点点,不敢造次.百度上的文章也是一抓一大把呐!所以,教点基本使用方法 ...

  5. NSIS安装制作基础教程[初级篇], 献给对NSIS有兴趣的初学者

    NSIS安装制作基础教程[初级篇], 献给对NSIS有兴趣的初学者 作者: raindy 来源:http://bbs.hanzify.org/index.php?showtopic=30029 时间: ...

  6. PowerDNS简单教程(1):安装篇

    这一篇开始直接是PowerDNS教程,连续四篇.DNS的相关背景知识我就不介绍了,有需要的话看看 http://baike.baidu.com/link?url=QcthFpAb2QydMqcMJr9 ...

  7. iRedMail邮件系统配置简易视频安装教程

    iRedMail邮件系统配置简易视频安装教程        iRedMail邮件系统配置简易视频安装教程 iRedMail中文名为“艾瑞得邮件系统”, 属于开源的企业邮件解决方案,但其性能不逊于任何商 ...

  8. JavaScript简易教程(转)

    原文:http://www.cnblogs.com/yanhaijing/p/3685304.html 这是我所知道的最完整最简洁的JavaScript基础教程. 这篇文章带你尽快走进JavaScri ...

  9. Zabbix实战-简易教程系列

    一.基础篇(安装和接入) Zabbix实战-简易教程--总流程  Zabbix实战-简易教程--整体架构图 Zabbix实战-简易教程--DB安装和表分区 Zabbix实战-简易教程--Server端 ...

随机推荐

  1. c++中回调函数和函数指针的使用

    #include "stdafx.h" #include <iostream> //#include <string> using namespace st ...

  2. 如何配置VS使得可以通过域名或IP访问

    一.前言: 在平时使用Visio Studio进行网站开发,经常会遇到一个问题.既要可以使用VS的Debug一步步跟进项目的走向,又必须是外界可以访问的.这个问题会在微信开发中非常常见,就拿微信开发中 ...

  3. 通过IF({1,0}和VLOOKUP函数实现Excel的双条件多条件查找的方法

    在Excel中,通过VLOOKUP函数可以查找到数据并返回数据.不仅能跨表查找,同时,更能跨工作薄查找. 但是,VLOOKUP函数一般情况下,只能实现单条件查找. 如果想通过VLOOKUP函数来实现双 ...

  4. 纯css3打造瀑布流布局

    纯css3打造瀑布流布局 原理: 1.column-count 把div中的文本分为多少列 2.column-width 规定列宽 3.column-gap 规定列间隙 4.break-inside: ...

  5. setup命令的安装

    2018-03-01  10:25:18 最小化安装的Linux系统,setup命令使用不了 安装方法:yum install setuptool    #安装完以后,只要直接输入 setup,就会出 ...

  6. Effective Java 第三版——37. 使用EnumMap替代序数索引

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  7. git使用.gitignore设置不生效或不起作用的问题

    偶然遇到的问题,记录如下: 通常我们在push项目时,会有些配置文件或本地文件不想上传到服务器上 这时候我们会通过设置.gitignore  文件 一般设置成这样: # 20170418 by 51a ...

  8. C++实现Date日期类

    定义一个Date类,包含三个属性年.月.日 实现了如下功能: 年月日的增加.减少:2017年10月1日加上100个月30天是2025年5月31日 输出某天是星期几:2017年10月1日是星期日 判断某 ...

  9. Axis1.4之即时发布服务

    下载axis1.4开发包,解压开发包,将webapps目录下的axis文件夹拷贝到tomcat的webapps目录下.启动tomcat,在浏览器输入http://localhost:8080/axis ...

  10. AsyncTask源码笔记

    AsyncTask源码笔记 AsyncTask在注释中建议只用来做短时间的异步操作,也就是只有几秒的操作:如果是长时间的操作,建议还是使用java.util.concurrent包中的工具类,例如Ex ...