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

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

相关文章

来自专栏喔家ArchiSelf

消息队列在RTOS的应用

传说互联网应用有两大利器,一个是缓存,另一个就是消息队列。 一直相对消息队列做一下梳理,希望早日另有成文。 一叶知秋,实际上消息队列在嵌入式系统中同样有着广泛的...

1103
来自专栏腾讯NEXT学位

JavaScript Worker 另类玩法

1243
来自专栏Java后端技术栈

【动画】当我们在读写Socket时,我们究竟在读写什么?

套接字socket是大多数程序员都非常熟悉的概念,它是计算机网络编程的基础,TCP/UDP收发消息都靠它。我们熟悉的web服务器底层依赖它,我们用到的MySQL...

1232
来自专栏数据之美

玩转 Nginx 之:使用 Lua 扩展 Nginx 功能

1、Nginx 简介 Nginx 作为一款面向性能设计的HTTP服务器,相较于Apache、lighttpd具有占有内存少,稳定性高等优势。其流行度越来越高,应...

1.2K7
来自专栏文武兼修ing——机器学习与IC设计

流水线式p2p接口的分析与实现

P2P接口是一种双向握手接口,传输的前级和后级各提供一个数据有效信号valid和忙信号busy信号,只有当两个信号达成某种指定情况时,握手完成,数据传输完成,否...

1082
来自专栏linux、Python学习

黑客们会用到哪些Python技术?

Python已经成为漏洞开发领域的行业标准,读者会发现大多数概念验证工具都是用Python语言编写的(除了用Ruby写的安全漏洞检测工具)。Python允许开发...

2144
来自专栏Java技术栈

分布式 | Dubbo 架构设计详解

Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度...

1692
来自专栏木子昭的博客

精析Python3实现动态web服务(附服务端源码)如果我们提供一个动态网站服务,至少应考虑以下四点:一个优秀的动态web框架应该是这样的:关于WSGI标准WIGS模型的要点:实现源码小结:

实现一个简单的静态web网站,只需将写好的html页面上传到特定的web服务器软件即可,但静态网页其实和图片没什么区别,每次更新网站内容,都需要重新制作htm...

38412
来自专栏Java后端技术

解决eclipse中egit中的cannot open git-upload-pack问题

  今天在使用eclipse的egit插件进行检出远程代码到本地时,出现了cannot open git-upload-pack错误,后经过努力解决该问题,记录...

951
来自专栏张善友的专栏

替换EnterPrise Library 4.0 缓存应用程序块的CacheManager

缓存是用来提高应用程序性能的常见技术,其实现方式是将常用数据从慢数据源复制到更快的数据源。对于数据驱动的应用程序来说,该技术通常需要将从数据库或 Web 服务检...

2007

扫码关注云+社区

领取腾讯云代金券