工程化
webpack.DefinePlugin介绍
基本用法
这个插件用来定义全局变量,在webpack打包的时候会对这些变量做替换。
先看个例子
|
|
编译完的结果如下:
|
|
可以看到代码中 SOMETHINE 被直接替换为 This is something we needed. 但是我们的本意中 SOMETHINE 是一个字符串,而直接替换后却不是一个字符串。怎么办呢?
方法一:可以将 SOMETHINE 的值写成
|
|
方法二: 借助 JSON.tringify ,转为字符串
|
|
推荐使用方法二,它不仅可以处理字符串,还可以处理Object中的字符串和Array。如下:
|
|
编译结果
|
|
还剩下 Number 和 Boolean 两种变量类型,对于这两种类型,就不像上面介绍的这么麻烦了,直接写就行
|
|
编译结果
|
|
实际运用
介绍了这么多,在实际使用中, DefinePlugin 最为常用的用途就是用来处理我们开发环境和生产环境的不同。比如一些 debug 的功能在生产环境中需要关闭、开发环境中和生产环境中 api 地址的不同。以 vue-cli 生成的打包文件为例子,来看看在实际中的使用。
vue-cli 生成的目录中编译、打包相关的有两个文件夹 build 和 config 。
build 文件夹中找到 wbepack.dev.conf.js 和 webpack.prod.conf.js ,这两个文件中都通过 DefinePlugin 插件定义了 process.env 这个变量
|
|
config 中对 env 的定义分别放在 config/dev.env.js 和 config/prod.env.js 中
|
|
到此可以看到,在 wbepack.dev.conf.js 中最终为
|
|
在 webpack.prod.conf.js 中最终为
|
|
在我们的代码中,如果部分只是在开发环境下才执行的逻辑,那么可以通过下面的方式
|
|
flow的使用
facebook 推出的 js 静态类型检查工具。
flow可以在代码运行前对类型错误进行检查,包括:
- 类型错误
- 对null的引用
- 以及可怕的 “undefined is not a function”
flow 允许我们给变量添加类型
flow 的安装和使用
安装:
由于 flow 是用 OCaml 语言写的,npm 上只有对应的二进制包。
|
|
1.基本使用
安装完成后我们在要执行静态检查的文件跟目录下执行一下 flow init ,之后会发现多处一个.flowconfig文件,这个文件告诉 Flow 在这个目录下开始检测。此外 .flowconfig 文件可以进行一下更为高级的配置,比如仅包含一些目录、忽略一下目录等等(更深入的了解,请戳官网)。
对于需要使用 flow 进行类型检查的 js 文件,在开头加入 @flow 的注释
|
|
例如:
|
|
接下来执行 flow check 看一下结果
|
|
multiple10 函数中的类型转换被 flow 标记出。
2.类型注解
注意上面例子中 flow 的报错,只有 multiple10 中静态类型错误被检测中。对于 getLength 函数中参数 str 的类型是什么呢? 从函数本身来分析,只要包含 length 属性就都是合法的。 对于这种情况则可以为其添加“类型注解”,来明确的告诉 flow 这个值的类型。
|
|
再来运行一下 flow check , 这时结果会提示我们[1,2,3]这个参数类型不对。
|
|
3.自定义类型
很多时候,除了 number 、 string 这些基础类型外,我们还会有一些自定义的类型,比如:
|
|
这时候可以在一个单独的文件中将 someData 申明了一个自定义类型。方式如下:
|
|
然后在 .flowconfig 文件中引入该申明文件
|
|
flow server
在大型项目中,如果每修改完代码,就执行以下 flow check ,然后等待看结果,显然会被逼疯的。flow 为我们提供了一个 flow server ,支持在后台运行,并且只监测有修改的文件。方法很简单,只有一个命令
|
|
babel+flow
由于 flow 中类型注解的语法不属于 javascript 规范中的内容。所以在最终的代码中,我们需要移除flow的内容。flow 提供了 flow-remove-types 和 babel 插件两种方式,推荐使用 babel 插件来完成这项工作。
flow-remove-types
这种方法比较简单粗暴: 安装 flow-remove-types,然后执行命令。12$> npm install -g flow-remove-types$> flow-remove-types src/ --out-dir build/
babel插件
安装 babel 插件1$> npm install babel-plugin-transform-flow-strip-types
babel 的 plugin 中加入该插件
|
|
注意:在 babel6 的 babel-preset-react 的插件中已经内置了 transform-flow-strip-types(https://flowtype.org/docs/syntax.html),如果使用了 babel-preset-react 那么无需再引入transform-flow-strip-types
eslint
eslint-plugin-flowtype 插件,可以让我们在 eslint 代码检查中加入 flow 的书写规范化检查。使用方式也很简单:
安装
1$> npm install eslint-plugin-flowtype在 .eslintrc.js 中设置 parser 为 babel-eslint
- plugin 中加入 flowtype
- eslint-plugin-flowtype 插件中默认提供了一份基于优秀实践总结出的 flow type 书写规范配置,在 .eslintrc 文件的 extend 中加入 “plugin:flowtype/recommended” 即可直接使用。
|
|
完成后我们来看看效果。下面的代码
|
|
eslint 检查结果会抛出一个错误:类型注解的冒号后面丢失了空格。
|
|
因为推荐的规范中:类型注解冒号后需要一个空格
|
|
flow type 规范配置如:函数返回类型是否必须、类型注解冒号前后的空格、自定义的type 的名称的命名方式等等,官方给出了很详细说明和例子。注:针对flow的的规范规则配置前添加“flowtype/”
配置名称 | 作用 | |
---|---|---|
boolean-style | 类型注解中布尔值使用boolean还是bool | |
define-flow-type | 将类型注解标记为已定义,no-undef的检查中不会出现报错 | |
delimiter-dangle | Object和Tuple类型定义中分隔符使用规范 | |
generic-spacing | 泛型对象的尖括号中类型前后的空格规范 | |
space-before-generic-bracket | 泛型对象的尖括号前的空格规范 | |
no-dupe-keys | object类型的定义中是否有重复的属性值 | |
no-primitive-constructor-types | 禁止使用原生的类型 | |
no-weak-types | 是否可以使用弱类型any、Object、Function | |
object-type-delimiter | Object类型定义中,属性之前分割符为分号/逗号(注:该属性已被废弃,需要使用分号来分割) | |
require-parameter-type | 函数的参数是否需要类型注解 | |
require-return-type | 函数返回值是否需要类型注解 | |
require-valid-file-annotation | 文件开头@flow的写法 | |
require-variable-type | 什么样的变量是需要类型注解 | |
semi | 使用type自定义类型语句结尾是否需要分号结尾 | |
sort-keys | Object类型定义中属性排列顺序 | |
space-after-type-colon | 类型注解分号后的空格规范 | |
space-before-type-colon | 类型注解分号前的空格规范 | |
type-id-match | 使用type自定义类型的名称规范 | |
union-intersection-spacing | union类型、intersection类型连接符号\ | 、&之间的空格规范 |
use-flow-type | 将通过declare定义的自定义类型标记为已经被使用过,no-unused-vars的检查中不会出现报错 |
#####名词说明
文中一些中文词直接从英文文档中翻译过来,可能有不准确的地方,这里给出原文,避免歧义。
- 类型注解:原文为 type annotations ,标记变量的类型
自定义类型:原文为 type aliases, 类似C语言中的typedef,可以为已有类型定义一个新的名称,或将一个复杂类型进行封装,如
12345type a = Array<String>type Person = {name: string,age: number};
#####相关链接
flow 官网(关于 flow 的各种用法官网给出了详细的例子):https://flowtype.org/
Webpack.merge插件
webpack-merge插件可以用来merge两个webpack的配置。它的底层引用了lodash中的merge,但针对webpack的特点,专门对loaders,preLoaders,postLoaders专门做了处理。
一般情况下,对于以下两个module
|
|
进行merge(module, moduleExtend)后会得到如下结果:
|
|
因为loaders是数组,所以结果中的css的loader信息丢失了。所以为了保证merge之后,loaders,preLoaders,postLoaders中的内容不会丢失,webpack-merge中对于loaders,preLoaders,postLoaders进行了特殊处理,采用concat对数组内容进行合并
|
|
如此,merge的结果为
|
|
但是如果遇到两个test值相同的loader时,仅仅用concat的话,会产生两条结果
|
|
这时对于js文件会先用babel-loader处理,然后再用coffee-loader处理。但是更多的,我们希望merge的结果是,后一个可以覆盖掉前一个。此外,在loaders中,除了可以写loader:’coffee’,还会有loaders:[‘xx’]的形式,如果一律采用concat的形式,显然过于粗暴了。所以,webpack-merge提供了更为聪明的的merge.smart函数,可以将test值相同的loader(preLoaders,postLoaders)进行合并。
- 对于loader,后面的会覆盖前面的属性
|
|
- loaders将会合并为一个去重后的数组
|
|
注意:对于loaders中带参数的形式,如babel?plugins[]=object-assign,在smart merge时会认为和babel、babel?…为同一类,后一个会对前一个产生覆盖
|
|
- 如果后一个loaders,前一个为loader,则merge时会将loader转化为loaders,然后进行merge
|
|
- 如果后一个为loader,前一个为loaders,则merge的结果为loader
|
|
注意:include和exclude的配置同时也会影响loader是否会被合并。如果两个loaders有不同的include或者exclude值(后一个loaders不包含include或exclude除外),那么loaders最终不会进行合并,而是像merge中进行了concat。
|
|