为什么需要区分环境

在开发网页的时候,一般都会有多套运行环境,例如:

  1. 在开发过程中方便开发调试的环境。
  2. 发布到线上给用户使用的运行环境。

这两套不同的环境虽然都是由同一套源代码编译而来,但是代码内容却不一样,差异包括:

  • 线上代码被通过 4-8 压缩代码 中提到的方法压缩过。
  • 开发用的代码包含一些用于提示开发者的提示日志,这些日志普通用户不可能去看它。
  • 开发用的代码所连接的后端数据接口地址也可能和线上环境不同,因为要避免开发过程中造成对线上数据的影响。

为了尽可能的复用代码,在构建的过程中需要根据目标代码要运行的环境而输出不同的代码,我们需要一套机制在源码中去区分环境。 幸运的是 Webpack 已经为我们实现了这点。

如何区分环境

具体区分方法很简单,在源码中通过如下方式:

if (process.env.NODE_ENV === 'production') {
console.log('你正在线上环境');
} else {
console.log('你正在使用开发环境');
}

其大概原理是借助于环境变量的值去判断执行哪个分支。

当你的代码中出现了使用 process 模块的语句时,Webpack 就自动打包进 process 模块的代码以支持非 Node.js 的运行环境。 当你的代码中没有使用 process 时就不会打包进 process 模块的代码。这个注入的 process 模块作用是为了模拟 Node.js 中的 process,以支持上面使用的  process.env.NODE_ENV === 'production'  语句。

在构建线上环境代码时,需要给当前运行环境设置环境变量  NODE_ENV = 'production' ,Webpack 相关配置如下:

const DefinePlugin = require('webpack/lib/DefinePlugin');
module.exports = {
plugins: [
new DefinePlugin({
// 定义 NODE_ENV 环境变量为 production
'process.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 模块了。

DefinePlugin 定义的环境变量只对 Webpack 需要处理的代码有效,而不会影响 Node.js 运行时的环境变量的值。

通过 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),
})

结合 UglifyJS

其实以上输出的代码还可以进一步优化,因为  if(true)  语句永远只会执行前一个分支中的代码,也就是说最佳的输出其实应该直接是:

  console.log('你正在线上环境');

Webpack 没有实现去除死代码功能,但是 UglifyJS 可以做这个事情,如何使用请阅读 4-8 压缩代码 中的压缩 JavaScript。

第三方库中的环境区分

除了在自己写的源码中可以有环境区分的代码外,很多第三方库也做了环境区分的优化。 以 React 为例,它做了两套环境区分,分别是:

  1. 开发环境:包含类型检查、HTML 元素检查等等针对开发者的警告日志代码。
  2. 线上环境:去掉了所有针对开发者的代码,只保留让 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 ' 两个值是社区的约定,通常使用这条判断语句在区分开发环境和线上环境。本实例 提供项目完整代码

webpack学习笔记--区分环境的更多相关文章

  1. Android Studio 学习笔记(一)环境搭建、文件目录等相关说明

    Android Studio 学习笔记(一)环境搭建.文件目录等相关说明 引入 对APP开发而言,Android和iOS是两大主流开发平台,其中区别在于 Android用java语言,用Android ...

  2. Qt5学习笔记(1)-环境配置(win+64bit+VS2013)

    Qt5学习笔记(1)-环境配置 工欲善其事必先-不装-所以装软件 久不露面,赶紧打下酱油. 下载 地址:http://download.qt.io/ 这个小网页就可以下载到跟Qt有关的几乎所有大部分东 ...

  3. openresty 学习笔记一:环境安装

    openresty 学习笔记一:环境安装 openresty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库.第三方模块以及大多数的依赖项.用于方便地搭 ...

  4. 更博不能忘——webpack学习笔记

    webpack是前端构建系统就像grunt和gulp(之前有学习过grunt所以也就大概明白webpack是个什么东西),所以说前端技术大部分还真是相通的,现在觉得当时多看的东西并不白费,虽然长时间不 ...

  5. 【原】webpack学习笔记

    之前在react的项目中有用过webpack,不过没有认真的去研究,这段时间又重新好好的学习一下webpack,发觉 webpack是一个很强大的东西.而且很好用,方便,接下来主要是做一下学习的笔记 ...

  6. webpack学习笔记—webpack安装、基本配置

    文章结构: 什么是webpack? 安装webpack 'webpack基本配置 一.什么是webpack? 在学习react时发现大部分文章都是react和webpack结合使用的,所以在学reac ...

  7. Python3学习笔记 - 准备环境

    前言 最近乘着项目不忙想赶一波时髦学习一下Python3.由于正好学习了Docker,并深深迷上了Docker,所以必须趁热打铁的用它来创建我们的Python3的开发测试环境.Python3的中文教程 ...

  8. webpack学习笔记一:安装webpack、webpack-dev-server、内存加载js和html文件、loader处理非js文件

    一 .webpack学习环境准备: 1:window系统 2:安装node.js  官方网址 下载好后下一步下一步安装即可 安装步骤略过....... 3:nrm的安装 打开cmd命令控制台 输入:n ...

  9. oracle学习笔记——配置环境

    题记:最近再学oracle,于是按照这本经典的书<Oracle Database 9i/10g/11g编程艺术>来学习. 配置环境 如何正确建立SCOTT/TIGER演示模式 需要建立和运 ...

随机推荐

  1. Ex 2_4 假定您需要在以下三种算法中作出抉择..._第三次作业

  2. scrapy-redis(调度器Scheduler源码分析)

    settings里面的配置:'''当下面配置了这个(scrapy-redis)时候,下面的调度器已经配置在scrapy-redis里面了'''##########连接配置######## REDIS_ ...

  3. Math中的floor,round和ceil方法总结

    floor向下取整,返回不大于的最大整数  Math.floor(1.4)=1.0ceil向上取整,返回不小于的最小整数  Math.ceil(1.4)=2.0round 四舍五入,将原来的数字加入0 ...

  4. SQL语句的行列转换

    [一]行转列 1,查询原始的数据 /***这次练习的主题,行转列,列转行***/select * from Scores 2,得到姓名,通过group by select Student as '姓名 ...

  5. 对象Object

    功能分类                       1. 创建对象 把各对数自身拥有的可枚举属性复制到第一个对象并返回:obj = Object.assign(o1, o2, o3),o1=obj ...

  6. Oracle存储过程中跳出循环的写法

    注:本文来源于: <  Oracle存储过程中跳出循环的写法   > Oracle存储过程中跳出循环的写法 记录exit和return的用法 1:exit用来跳出循环 loop IF V_ ...

  7. Confluence 6 创建站点的导出文件

    希望为你的站点创建一个 XML 导出文件: 进入  > 基本配置(General Configuration) > 备份和恢复(Backup & Restore). 选择 归档到备 ...

  8. Confluence 6 使用 Decorator 宏

    Decorator 宏(Macros)是 Velocity  宏.这个宏可以被用来在页面编辑 Custom decorators 中创建复杂或者可变的部分,例如菜单,页面其他部分等.Decorator ...

  9. selenium之实现多窗口切换到自己想要的窗口

    #coding=utf-8 from selenium import webdriver import time from selenium.webdriver.support import expe ...

  10. Django Rest Framework(2)

    目录 一.认证 二.权限 三.限制访问频率 四.总结 一.认证(补充的一个点) 认证请求头 #!/usr/bin/env python # -*- coding:utf-8 -*- from rest ...