使用DefinePlugin改变打包流程

前言

基于webpack开发的时候,我们有些代码只需要在开发时期来运行,例如打印详细的错误或警告信息。

有些代码我们需要在线上运行的时候在执行。例如数据埋点,如果在开发的时候就运行,会导致线上埋点的结果不是很准确,失去了分析的意义。

实现

今日我通过查看部分库的源代码,里面用到了webpack的 DefinePlugin,这个插件可以定义一个webpack打包时的全局变量,在我们的代码中可以通过判断这个全局变量的值就来执行对应的代码。

1、修改webpack配置

由于DefinePlugin是webpack内置的,所以不需要单独的下载,具体修改的配置如下:

module.exports = {
    ...
    plugins:[
      ...,
      new webpack.DefinePlugin({
          DEBUG: !/(product|stage)/.test(process.env.NODE_ENV)
      })
    ]
};

这样我们就可以通过在编译的时候传入NODE_ENV参数来控制代码的执行了。如果我们传入的NODE_ENV包含stage或者是product就设置为false,否则就是true。

2、修改我们的业务代码

我们在业务代码中加入判断就可以选择代码的执行了。

if (DEBUG) {
    // 这里是开发环境执行的代码
    console.log('可查看详细的错误信息了');
} else {
    // 不是开发环境了,就直接执行线上的代码,我们可以在这里做用户行为分析的功能或者其他
    // 屏蔽console和alert
    const noop = () => {};
    window.alert = () => {};
}

还有一个好处就是线上打包的时候,uglifyjs通过代码分析,将 if (false) {} 这种的代码直接删除掉,减少了代码的体积。

3、运行测试

怎么才能看出我们上面的插件有没有用呢,我们可以执行下面的代码,来看看控制台的打印就好了。

首先在我们的业务代码中使用 console.log() 来打印一下这个值(先不要屏蔽console测试)。

console.log('是不否开发环境', DEBUG);

然后调用 webpack-dev-server 来查看。

webpack-dev-server  # 没有传递任何的环境变量,控制台会输出true

线上或者是测试环境运行。

NODE_ENV=stage webpack-dev-server  # 现在NODE_ENV是stage,控制台会输出false
NODE_ENV=product webpack-dev-server # 现在NODE_ENV是product,控制台也会输出false

既然输出都是正确的,那么我们通过判断的代码执行的逻辑也就是没有问题了。

使用场景

1、我们在做谷歌分析或者TalkingData的时候,我们只有线上环境才会执行分析,开发环境不会调用对应的事件,我们就可以定义一个环境变量来判断当前的环境。

2、我们在线上需要屏蔽不必要的alert,我们也可以这样做。

3、其他开发时和运行时代码级别的差异化都可以使用这种方法去实现。

扩展阅读

1、为什么我们要判断process.env.NODE_ENV呢?

因为我们的webpack是运行的node环境中的,process对象是node内置的一个运行时线程对象,process.env存储的使我们所有的环境变量,可以在执行node程序之前临时加上一个环境变量,linux和mac下使用比较简单,只需要在要执行的程序之前添加 变量名=变量值 就可以使用process.env读取到,举个例子:

NODE_ENV=stage webpack-dev-server 
# 执行webpack-dev-server的时候,取到的process.env.NODE_ENV就是stage, 其他的类似。

2、为什么windows,执行NODE_ENV=stage webpack-dev-server会出现错误,我们就需要用到一个包叫做cross-env,将脚本修改为

cross-env NODE_ENV=stage webpack-dev-server 

留下回复