一步一步带你搭建一个“摩登”的前端开发环境

js 类型系统

最近纠结一个问题,前端的 js 由于其动态的特性,写几行代码,在浏览器刷新一下就能看到结果了,非常适合快速开发和迭代。但随着代码的规模越来越大,到了后期就会变得难以维护,任何的改动都有可能引入新的 bug,js 工程师需要花费越来越多的时间来调试修复各种 bug。

造成这样结果的原因有多样,而其中之一的原因,是由于 js 缺乏类型系统,导致我们无法通过工具来在开发的过程中检测到那些可能会发生的错误,也无法通过具体的类型定义来约束别人如何调用自己写的代码库。

这样的想法其实在 js 社区里已经得到越来越多人的认同,最近几年也陆续推出了多种不同的 js 类型系统用于增强 js 的健壮性,其中像typescript就是其中的佼佼者。当然我今天要讲的并不是 typescript,而是由 facebook 推出的flow

flow 和 typescript 不同,typescript 是 js 的超集,是另外一门语言(向下兼容 js),而 flow,则是一个静态类型检测工具,并没有修改 js 的语言特性。flow 通过自动推断 js 代码中各个变量的类型,来约束代码的行为,举个例子,在 js 中对两个变量进行相加,在不同情况下会得到不一样的结果:

let strA = "hello ";
let strB = "world";
let numC = 1;
let numD = 2;
let objE = { "key": "value" };
let arrF = [ 1, 2, 3 ];

// 情况 1
strA   srtB // "hello world"
// 情况 2
numC   numD // 3;
// 情况 3
strA   numC // "hello 1"
// 情况 4
strA   objE // "hello [object Object]"
// 情况 5
strA   arrF // hello 1,2,3"

上面的 5 种情况,在 js 中都是被允许的,然而情况 4 和 5,在一般情况下并不是我们所期望的。而在 flow 中,则只允许情况 1~3 通过检测,而对于情况 4 和 5 则直接报错了。

strA   objE;
       ^^^^ object literal. This type cannot be added to
strA   objE;
^^^^ string

strA   arrF;
       ^^^^ array literal. This type cannot be added to
strA   arrF;
^^^^ string

flow 除了可以自动的进行类型推断外,还可以通过类型声明的来进一步限制代码的行为,例如我们声明一个函数,接受一个参数,并返回一个字符串,如果我们不进行额外的类型声明,flow 默认是会接受 string 和 number 两种类型的参数

function hello(val) {
  return "hello "   val;
}

hello("world");
hello(1);

但如果我们希望我们的函数只接受 string 作为参数,并且明确返回 string,则可以

function hello(val: string): string {
  return "hello "   val;
}

这是如果再传入 number 则会报错,对于完整的 flow 使用,大家可以参考 这里

hello(1);
      ^ number. This type is incompatible with the expected param type of
function hello(val: string): string {
                    ^^^^^^ string

flow 环境的搭建

要在项目中使用 flow,需要完成三件事情

第一安装 flow 命令行工具

$mkdir flow-proj && cd flow-proj
$npm init
$npm install flow-bin --save-dev

第二,编写 js 代码(hello.js),并在代码的第一行,加入注释 // [@flow][2]

// @flow
exports.hello = function (val: string): string {
  return "hello "   val;
}

这时候,flow 已经知道该文件是需要做类型检测的,这时候运行 flow init 命令初始化 flow

$./node_module/.bin/flow init

flow 会自动在该目录下创建.flowconfig 文件,接着我们运行 flow 命令,就可以在后台启动 flow 进程进行类型检测了

Spawned flow server (pid=28687)
Logs will go to /private/tmp/flow/zSUserszSlizZzZzZledzSDevzSflow-proj.log
No errors!

如果需要停止 flow 进程,只需要运行 flow stop 命令即可

$./node_module/.bin/flow stop

到现在为止,虽然 flow 已经可以正常运行了,然而因为我们在 js 代码里添加了额外类型声明,导致 js 代码不能直接在浏览器里执行,这时候我们需要做第三步,通过代码构建的方式,把 js 转换成浏览器能执行的形式。

这里我采用的 webpack babel 作为我们构建环境,所以首先我们需要安装 webpack 和 babel

$npm install webpack babel-core babel-loader --save-dev

然后我们需要安装 babel 的 flow 套装,使得 babel 支持 flow

$npm install babel-preset-flow --save-dev

然后我们编写 webpack 的配置文件 webpack.config.js

module.exports = {
  entry: "./hello.js",
  output: {
    path: __dirname,
    filename: "hello.bundle.js"
  },
  module: {
    loaders: [
      {
        test: /.js$/,
        exclude: /node_module/,
        loaders: ["babel-loader"]
      }
    ]
  }
};

还有我们的 babel 配置文件.babelrc

{
  presets: [
    "flow"
  ]
}

到这里为止,我们已经完成了构建环境的配置,接下来执行 webpack 命令,就会产生我们的目标文件(hello.bundle.js)

$./node_modules/.bin/webpack

打开目标文件,我们就会发现,flow 的类型声明已经被正确去掉了。

到现在为止,整个 flow 的环境已经算搭建完成了,然而在写了没几行代码之后,我们就会发现,每次要对代码进行检测,都需要打开 terminal,敲上一堆命令才能看到结果,实在是不爽。有没有办法可以节省这些多余的工作,把 flow 集成到编辑器中呢?答案当然是肯定的。

这里我使用的编辑器是 sublime text3,如果有的同学是使用其他编辑器,可以在 这里,找一下

对与像我一样使用 st3 的同学,首先我们要在 st3 里安装 SublimeLinter 插件,Ctrl Shift P 打开 Package Control,选中 Package Control:Install Package。输入 SublimeLinter,安装即可。

SublimeLinter 是一个语法校验的框架,但其本身并不会去做实际的校验工作,我们需要另外安装 SublimeLinter 的 flow 插件,同样是打开 Package Control,输入 SublimeLinter-flow,安装即可。

这时 SublimeLinter-flow 就会在当前文件夹向上查找.flowconfig 文件,并对带有 // [@flow] 的文件进行自动检测,如果出现错误,就会直接在编辑器上提示,十分的方便。

加入 eslint 语法校验

除了类型检测,有时候我们还需要对 js 进行语法校验,当然很多成熟都工具都可以帮我们完成这样的功能,这里我使用的 eslint,对于其他的例如 jshint,jslint,小伙伴都可以自行 google。

首先我们要安装 eslint 以及 eslint-loader,使得 eslint 可以集成到 webpack 里

$npm install eslint eslint-loader --save-dev

安装好 eslint 后,就可以执行 eslint --init 命令来初始化 eslint 了

$npm ./node_modules/.bin/eslint --init

这时 eslint 就会问你一些问题,一步步帮你完成初始化的工作,并生成对应.eslintrc 文件,这时候,我们需要更新一下 webpack.config.js 文件,加入对 eslint 的支持,记得 eslint-loader 一定要写在 babel-loader 之后,这样 eslint 才能正确执行

module.exports = {
  entry: "./hello.js",
  output: {
    path: __dirname,
    filename: "hello.bundle.js"
  },
  module: {
    loaders: [
      {
        test: /.js$/,
        exclude: /node_module/,
        loaders: ["babel-loader", "eslint-loader"]
      }
    ]
  }
};

不过如果这时候,你试着执行 webpack 命令进行构建,你会发现,报错了,原因是 eslint 不认识 flow 的类型声明语法。为了让 eslint 能通过 flow 的类型声明,我们需要安装两个工具,一个是 flow 的 eslint 插件 eslint-plugin-flowtype,另一个是 eslint 的 babel 版 js 解析器 babel-eslint,这是由于 eslint 默认的 espree 解析器认不得 flow 的类型声明

$npm install eslint-plugin-flowtype babel-eslint --save-dev

接着我们修改一下 eslint 的配置文件.eslintrc,把 parser 字段设置为 babel-eslint,然后分别在 extendsplugins 加入 flow 相应的设置

{
  "env": {
    "node": true,
    "browser": true,
    "commonjs": true,
    "es6": true
  },
  "extends": [
    "eslint:recommended", 
    "plugin:flowtype/recommended",
  ],
  "parser": "babel-eslint",
  "parserOptions": {
    "sourceType": "module"
  },
  "plugins": [
    "flowtype"
  ],
  "rules": {
    "indent": ["error", 4, { "SwitchCase": 1 }],
    "linebreak-style": ["error", "unix"],
    "quotes": ["error", "double"],
    "semi": ["error", "always"]
  }
}

done,现在我们再次执行 webpack 命令就能正常进行构建了。

最后最后,我们再通过在 sublime 中安装在 SublimeLinter 的插件 SublimeLinter-contrib-eslint 就可以让我们的编辑器也支持 eslint 的语法校验了。

这就是我这次给大家分享的,如何大家一个"摩登"的前端开发环境

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据结构与算法

2833 奇怪的梦境 未AC

2833 奇怪的梦境 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description Aide...

2645
来自专栏企鹅号快讯

盘点开发者最爱的 IntelliJ 插件 Top 10

关键时刻,第一时间送达! IntelliJ的十大插件?相信每个人都有自己的选择。我们也同样如此。在这里,我们为您带来我们认为的十大IntelliJ插件。 如果你...

1727
来自专栏后台全栈之路

Linux 内核中 Kconfig 文件的作用和添加 menuconfig 项的方法

嵌入式开发中,需要定制或添加一些内核的功能。这里就需要配置 Kconfig 文件了。本文简单说明一下如何修改。便于需要时查找

1535
来自专栏疯狂的小程序

微信小程序开发探索之路

项目起始时间:2017-11-25 前端人数: 3 页面数: 6 一期上线时间:2018-01-16 在我们开发的过程中,小程序的生态也不断变化。例如 最开始不...

2287
来自专栏木头编程 - moTzxx

获取小程序模板库标题列表 报错: {"errcode":-1,"errmsg":"system error hint: [zttteq44664"}

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/de...

1534
来自专栏FreeBuf

Vdex Extractor:从Vdex文件反编译和提取Android Dex字节码

一款命令行工具,用于从Vdex文件反编译和提取Android Dex字节码的工具。

994
来自专栏开源优测

代码阅读,就怕你知道却不会用

在函数定义、引用、实现的地方右击选择"Go To"根据需要选择跳转至定义、实现、父函数、测试函数等等

771
来自专栏lgp20151222

Maven的pom.xml文件结构之基本配置packaging和多模块聚合结构(微服务)

packaging给出了项目的打包类型,即作为项目的发布形式,其可能的类型。在Maven 3中,其可用的打包类型如下:

973
来自专栏世界第一语言是java

ELK+logback+kafka+nginx 搭建分布式日志分析平台

ELK(Elasticsearch , Logstash, Kibana)是一套开源的日志收集、存储和分析软件组合。而且不只是java能用,其他的开发语言也可以...

1402
来自专栏菜鸟前端工程师

JavaScript学习笔记027-BOM0window0location

753

扫码关注云+社区