索鸟网

  1. 首页
  2. webpack选择性编译(打包自动剔除测试数据)

webpack选择性编译(打包自动剔除测试数据)


背景

程序在开发的过程中,少不了打印调试用的日志,测试流程时伪造的数据。这些代码是不能出现在生产环境上的。
这意味着在程序打包前,需要把相关代码剔除掉。
这些事情用人手去做很麻烦,很容易疏漏。而且打包出来测试时遇到了bug,又得重新把测试代码添加回去。重复整个繁琐的过程。

既然人工做这么麻烦而且容易出错,那能不能用程序帮我们完成这些事情呢?
当然可以,用选择性编译技术就行,本文就介绍在webpack下解决这一问题的方法。
其实这个方法在webpack官网就有提到,本文只是提供相关示例及做一些延伸。

选择性编译是指根据打包是环境的不同,选择性地让特定的语句有效,让特定的语句无效。
最简单的例子,在开发环境中,我们打印日志,但在生产环境中,我们让所有打印日志的语句无效(让程序不运行打印的语句,甚至让打包出来的文件根本就不包含打印日志的语句)。

选择性编译是笔者自己瞎想出来的名词,不知道用的对不对。

实践过程

首先,先让我们看一个选择性打印日志的示例。

  • 新建一个vue项目
  • 打开build/webpack.dev.conf.js文件(项目处于开发环境时使用到的webpack打包配置,运行npm run dev,这个文件就会被执行)
  • 添加如下代码

    new webpack.DefinePlugin({
        "process.env": config.dev.env,
        IS_DEV: JSON.stringify(true),
    }),

  • 打开build/webpack.prod.conf.js文件(项目打包生产环境时使用到的webpack打包配置,运行npm run build,这个文件就会被执行)
  • 添加如下代码

    new webpack.DefinePlugin({
        "process.env": config.dev.env,
        IS_DEV: JSON.stringify(false),
    }),

  • 打开src/main.js文件(项目入口文件,运行项目时被执行)
  • 添加如下代码

    if (IS_DEV) {
        console.log("this is dev env");
    } else {
        console.log("this is prod env");
    }

  • 分别在开发环境和生产环境运行程序,查看控制台。我们发现,在开发环境下,打印了this is dev env。在生产环境下运行打印了this is prod env
  • 打开打包出来的文件/dist/static/js/app.xxx.js.map,搜索this is prod env。我们发现IS_DEV变成了false。
  • 同理,我们在开发环境下,查看chrome开发者工具,找到相应的app.xxx.js文件。我们发现IS_DEV变成了true。

由此我们可以知道

  • 选择性编译本质上是字符串的替换,先经过DefinePlugin对代码中的特定字符串进行替换。再对替换后的代码进行编译打包。
  • 需要替换的变量需要分别在webpack.dev.conf.jswebpack.prod.conf.js中指定其转换后的意义。
  • 为什么在mian.js中使用IS_DEV,程序不会报"IS_DEV is not defined"的错误?
    因为浏览器在运行代码时,拿到的文件里面IS_DEV已经被替换成了true或者false,已经不存在IS_DEV这个变量。所以不会报错。

DefinePlugin的使用说明

  • 除了替换成简单的布尔值,还可以替换成字符串,数值,数组,对象等。
    如TEST_DATA: JSON.stringify({name:"momo",age:18}),
  • 为什么需要进行JSON.stringify替换?
  • 另外还可以替换成某个段代码的值(代码内容直接使用""包裹即可)。
    如:TWO: "1+1",TOW将被替换成这段代码的结果,即2。

ESLint冲突处理

ESLint是一个用来识别 ECMAScript 并且按照规则给出报告的代码检测工具,使用它可以避免低级错误和统一代码的风格。

配置了eslint的项目在使用选择性编译功能时,可能会报出这样的错误。
http://exlint.org/docs/rules/no-undef "IS_DEV" is not defined
正如报错信息所说的,这是由于eslint检测代码时,发现IS_DEV没有定义(这侧面说明了eslint是先于条件编译执行的。ESLint检测时,IS_DEV还没有被替换掉)。解决这个问题有以下三种方法:

  • 简单粗暴的方法,修改eslint的配置,将error改为warn呗,先打包了再说。具体操作为修改eslintrc.js文件,如果配置文件里面已有第一条语句"eslint":"recommended"(这是引用默认配置)。则往rules里面添加一条规则"no_undef":"warn",以覆盖掉默认配置。
    如果已经存在"no-undef"的配置,则直接改为"warn"就行。
  • 上面的方法影响太大,直接修改了规则。能不能局部修改规则,只在特定语句中忽略掉该规则呢?可以的,使用备注包裹需要忽略的语句就行。
  • 但是上面的方法需要在每个用到的地方都多写两条语句,略麻。,有没有更简单的,一劳永逸的方法呢?有有有~~ 修改eslintrc.js,将IS_DEV配置成一个全局变量,之后eslint就不会认为IS_DEV是未定义的变量了。

选择性编辑技术的应用场景

  • API接口的环境替换
  • 账号信息的模拟,数据模拟
  • 日志打印等

彩蛋

更优的去除log的方法

用if逻辑判断来输出log可能略显繁琐。其实对于控制台输出的日志,我们可以通过UglifyJs在打包时来剔除。
具体操作:

  • 打开build/webpack.prod.conf.js文件,添加如下语句

    compress: {
        warnings: false, // 去除warning警告
        drop_debugger: true, // 发布时去除debugger语句
        drop_console: true // 发布时去除console语句
    },
  • 如果想只去除console.log,同时保留console.error等错误提示。可以指定去除特定的函数

    compress: {
        warnings: false, // 去除warning警告
        pure_funcs: ["console.log"], // 配置发布时,不被打包的函数
        // drop_debugger: true, // 发布时去除debugger
        // drop_console: true // 发布时去除console
    }
    *注意,添加了这个配置以后,console.log在打包出来的文件就不存在了。所以前面测试用的this is dev env也会消失不见*

去除条件编译中不可达代码

  • 什么叫不可达代码?就是无论什么情况下都不会被运行的代码。
    例如我们在条件编译打包出来的代码中

    if (false) {
        console.log("this is dev env");
    } else {
        console.log("this is prod env");
    }

    console.log("this is dev env");就是不可达代码。
    我们同样可以使用UglifyJs的功能把这部分无用代码去除掉。让条件编译不留痕迹。
    具体配置如下:

    compress: {
        warnings: false, // 去除warning警告
        dead_code: true, // 去除不可达代码
    }, sourceMap: true

UglifyJs的更多功能

UglifyJs还用很多强大的功能,如代码混淆,压缩,重拍版等。这里附上UglifyJs官方网址
英文不好的同学还可以查看对应的中文文档(其实这才是重点#机智脸)

完结,撒花花

node.js javascript vue.js webpack

来源地址:https://segmentfault.com/a/1190000011530718 版权归作者所有!

相关教程

  • webpack选择性编译(打包自动剔除测试数据)

    背景 程序在开发的过程中,少不了打印调试用的日志,测试流程时伪造的数据。这些代码是不能出现在生产环境上的。这意味着在程序打包前,需要把相关代码剔除掉。这些事情用人手去做很麻烦,很容易疏漏。而且打包出来测试时遇到了bug,又得重新把测试代码添加回去。重复整个繁琐的过程。 既然人工做这么麻烦而且容易出错,那能不能用程序帮我们完成这些事情呢?当然可以,用选择性
  • webpack项目中使用grunt监听文件变动自动打包编译

    【小技巧】webpack项目中使用grunt监听文件变动自动打包编译 分享背景:编写npm插件的时候,在项目里的测试html文件内引用需要从入口文件转译打包成ES5。因此测试时每次改动都需要手动需要npm run build一下,很麻烦。获知grunt有个watch功能,折腾了一下,可以做到每次js文件改动时自动build一波,很灵性。 安装依赖包 //
  • Webpack打包优化

    简单粗暴的Webpack打包优化 使用webpack+vue+......,在打包代码的时候经常由于引入的模块太多,导致打包速度很慢,并且打包后的js文件很大。 方案一:externals选项 配置externals选项: // webpack.prod.config.js // 多余代码省略 module.exports = { externa
  • webpack打包发布

    webpack打包发布 粗略的说明了一下打包的文件和大概的流程. 执行npm run build开始打包 调用build.js 然后主要调用webpack.prod.conf(有其他依赖,例如webpack.base.conf) 关于发布,就大概说了一下如何对已经进行发布的js,css,html进行一个小型服务器的发布 执行node prod.ser
  • 【编译打包】fastdfs-5.0.5-7.el7.centos.src.rpm

    安装问题是典型的无意义的重复劳动,理应简单,一个软件应该让使用者更专注于软件的用法和配置文件,而不是安装过程。fastdfs官方的spec文件功能不够完整,仅仅能够完成rpm打包,但是rpm包安装时会有各种问题。极少看到有人反馈spec文件问题,估计使用rpm包进行安装的,只有我一人。而使用rpm安装,可以省略重复无意义且容易出错的编译过程,提升软件安装体验。(文末有百度网盘的链
  • Webpack 服务器端代码打包

    环境变量 之前,我们在项目里会经常使用 process.env.NODE_ENV, 但这个变量对于 webpack打包是有影响的, 在 production 的时候是有优化的. 所以, 我们将改用其他的环境变量来区别: new webpack.DefinePlugin({ "process.env.NODE_ENV": ""production"",
  • webpack打包容量优化

    缘由 造成打包容量过大的原因有以下几种: 未使用懒加载 未使用压缩文件 未开启服务端压缩 拆分 app.js 请将app.js视为入口文件,可以将必需的前置插件打包到此文件。 vendor.js 可以将基本上所有页面公用的插件或库打包到此文件。 静态引用 非公用插件或库,引用静态文件或异步获取文件。 使用.min文件 使用.min文件进行打包。 压缩
  • webpack打包优化解决方案

    单页应用首次进入项目会获取一部分数据,之后将JS包分片,走到那块再去加载那块的JS。这样跨页面重复的JS,CSS不必再去获取,跨页面就不会出现进度条。这样减少了等待时间,提升了用户体验,省去了不必要的流量。但是单页应用也有一个显著的问题:首次进入的时候,加载的资源太多,白屏时间太长。 这里介绍一些常用的webpack打包优化解决方案 使用插件查看项目所