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

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 条评论
登录 后参与评论

相关文章

来自专栏章鱼的慢慢技术路

MFC绘图基础——上机操作步骤

2183
来自专栏ShaoYL

XCode的debug断点调试

3227
来自专栏喵了个咪的博客空间

zephir-(3)你的第一个PHP拓展

#zephir-你的第一个PHP拓展# ? ##前言## 先在这里感谢各位zephir开源技术提供者 在之前的介绍中大家不仅了解了zephir具体是一个什么样的...

3647
来自专栏木头编程 - moTzxx

PHP 生成随机码探索

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

702
来自专栏python3

python3--基础综合练习题

允许用户最多尝试3次,3次都没猜对的话,就直接退出,如果猜对了,打印恭喜信息并退出

723
来自专栏xingoo, 一个梦想做发明家的程序员

Elasticsearch——使用_cat查看Elasticsearch状态

Elasticsearch通过使用JSON来作为沟通的数据格式,这对于开发者来说很友好,因为很多程序都支持JSON格式。比如js就不说了,Java也有fast...

1819
来自专栏程序员互动联盟

【答疑解惑】什么是API?

有朋友在群里问什么是API?这个问题是很多初学者常常听到但又感觉讳莫如深。 ? API的英文是ApplicationProgramming Interface,...

36811
来自专栏王小雷

程序员必知的LinuxShell命令

程序员必知的LinuxShell命令 grep (Globle Regular Expression Print全局正则表达式) 命令是一种强大的文本搜索工具,...

1847
来自专栏汇智网教程

web3.eth.accounts

29611
来自专栏Vamei实验室

Linux文件管理相关命令

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢! 在了解了Linux文件管理背景知识之后, ...

1855

扫码关注云+社区