在开发网页的时候,通常都会有多套运行环境,例如:node
这两套不一样的环境虽然都是由同一套代码编译而来,可是代码内容却不同,差别包括:react
线上代码通过压缩处理
开发用的代码包含一些用于提示开发者的提示日志,这些日志普通用户不可能去看它
开发用的代码所链接的后端数据接口地址也可能和线上环境不一样,由于避免开发过程当中形成对线上数据的影响。
为了尽量的复用代码,在构建的过程当中须要根据目标代码要运行的环境而输出不一样的代码。咱们须要一套机制在源码中去区分环境。幸运的是webpack已经为咱们实现了。webpack
具体区分方法比较简单,在源码中经过以下方式:web
if(process.env.NODE_ENV === "production") { console.log("你正在线上环境") }else { console.log("你正在使用开发环境") }
其大概原理是借助于环境变量的值去判断执行哪一个分支。shell
当你的代码中出现了使用process模块的语句时, webpack就自动打包进process模块的代码以支持非nodejs的运行环境。当你的代码中没有使用proces时就不会打包进process模块的代码。这个注入process模块做用就是为了模拟nodejs中的process,以支持上面使用的后端
process.env.NODE_ENV === 'production'
在构建线上环境代码时,须要给当前运行环境设置环境设置环境变量NODE_ENV == 'prodeuction',webpack的配置以下:性能
const DefinePlugin = require("webpack/lib/DefinePlugin") module.exports = { plugins: [ new DefinePlugin({ //定义NODE_ENV环境变量为production "production.env": { NODE_ENV: JSON.stringify("production") } }) ] }
注意在定义环境变量的时候使用的是 JSON.stringify包裹字符串的缘由是环境变量的值须要时一个由双引号包裹的字符串,而 JSON.stringify('production')的值正好等于'"production"'.
执行构建后, 你会在输出的文件中发现以下代码:优化
if(true) { console.log('你正在使用线上环境') }else { console.log('你正在使用开发环境') }
定义的环境变量的值被代入到源码中, process.env.NODE_ENV === 'production'被直接替换成true。而且因为此时访问process的语句被替换了而没有了,webpack也不会打包进process模块了。ui
DefinePlugin定义的环境变量只对webpack须要处理的代码有效, 而不会影响nodejs运行时的环境变量的值。调试
经过shell脚本的方式去定义的环境变量,例如NODE_ENV=production webpack
,webpack是不认识的,对webpack须要处理的代码中的环境区分语句时没有做用的。
也就是说只须要经过DefinePlugin定义环境变量就能使上面介绍的环境区分语句正常工做,不必又经过shell脚本的方式去定义一遍。
若是你想让webpack经过shell脚本的方式去定义的环境变量,你可使用EnvironmentPlugin,代码以下:
new webpack.EnvironmentPlugin(['NODE_ENV'])
这句代码实际上等于:
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) })
其实以上输出的代码还能够进一步优化,由于if(true)语句永远只会执行前一个分支的代码,也就说最佳的输出应该直接是:
console.log("你正在线上环境")
webpack没有实现去除死代码的功能,可是UglifyJ能够作这个事情。
除了在本身写的源码中能够有环境区分的代码外, 不少第三方库也作了环境区分的优化。以react为例,它作了两套环境区分:
例如react中有大量相似下面这样的代码:
if(process.env.NODE_ENV !== 'production') { warning(false, '%s(...): Can only update a mounted or mounting component.... ') }
若是你不定义NODE_ENV=production那么这些警告日志就会被包含到输出的代码中,输出的文件将会很是大。
process.env.NODE_ENV !== 'production'中的NODE_ENV和'production'两个值是社区的约定, 一般使用这条判断语句在区分开发环境和线上环境。