webpack選擇性編譯DefinePlugin(打包自動剔除測試數據)

背景

程序在開發的過程當中,少不了打印調試用的日誌,測試流程時僞造的數據。這些代碼是不能出如今生產環境上的。
這意味着在程序打包前,須要把相關代碼剔除掉。
這些事情用人手去作很麻煩,很容易疏漏。並且打包出來測試時遇到了bug,又得從新把測試代碼添加回去。重複整個繁瑣的過程。
004vue

既然人工作這麼麻煩並且容易出錯,那能不能用程序幫咱們完成這些事情呢?
固然能夠,用選擇性編譯技術就行,本文就介紹在webpack下解決這一問題的方法。
其實這個方法在webpack官網就有提到,本文只是提供相關示例及作一些延伸。webpack

選擇性編譯是指根據打包是環境的不一樣,選擇性地讓特定的語句有效,讓特定的語句無效。
最簡單的例子,在開發環境中,咱們打印日誌,但在生產環境中,咱們讓全部打印日誌的語句無效(讓程序不運行打印的語句,甚至讓打包出來的文件根本就不包含打印日誌的語句)。
選擇性編譯是筆者本身瞎想出來的名詞,不知道用的對不對。
001

實踐過程

首先,先讓咱們看一個選擇性打印日誌的示例。

  • 新建一個vue項目
  • 打開build/webpack.dev.conf.js文件(項目處於開發環境時使用到的webpack打包配置,運行npm run dev,這個文件就會被執行)
  • 添加以下代碼git

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

    dev.conf

  • 打開build/webpack.prod.conf.js文件(項目打包生產環境時使用到的webpack打包配置,運行npm run build,這個文件就會被執行)
  • 添加以下代碼github

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

    prod.conf

  • 打開src/main.js文件(項目入口文件,運行項目時被執行)
  • 添加以下代碼web

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

    main

  • 分別在開發環境和生產環境運行程序,查看控制檯。咱們發現,在開發環境下,打印了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。

app.js.map

由此咱們能夠知道

  • 選擇性編譯本質上是字符串的替換,先通過DefinePlugin對代碼中的特定字符串進行替換。再對替換後的代碼進行編譯打包。
  • 須要替換的變量須要分別在webpack.dev.conf.jswebpack.prod.conf.js中指定其轉換後的意義。
  • 爲何在mian.js中使用IS_DEV,程序不會報"IS_DEV is not defined"的錯誤?

由於瀏覽器在運行代碼時,拿到的文件裏面IS_DEV已經被替換成了true或者false,已經不存在IS_DEV這個變量。因此不會報錯。app.js.mapchrome

DefinePlugin的使用說明

  • 除了替換成簡單的布爾值,還能夠替換成字符串,數值,數組,對象等。

如TEST_DATA: JSON.stringify({name:'momo',age:18}),npm

  • 爲何須要進行JSON.stringify替換?

008008

  • 另外還能夠替換成某個段代碼的值(代碼內容直接使用""包裹便可)。

如: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'就行。eslint-1瀏覽器

  • 上面的方法影響太大,直接修改了規則。能不能局部修改規則,只在特定語句中忽略掉該規則呢?能夠的,使用備註包裹須要忽略的語句就行。eslint-2
  • 可是上面的方法須要在每一個用到的地方都多寫兩條語句,略麻。,有沒有更簡單的,一勞永逸的方法呢?有有有~~ 修改eslintrc.js,將IS_DEV配置成一個全局變量,以後eslint就不會認爲IS_DEV是未定義的變量了。eslint-3

選擇性編輯技術的應用場景

  • API接口的環境替換
  • 帳號信息的模擬,數據模擬
  • 日誌打印等

002

彩蛋

更優的去除log的方法

用if邏輯判斷來輸出log可能略顯繁瑣。其實對於控制檯輸出的日誌,咱們能夠經過UglifyJs在打包時來剔除。
具體操做:app

  • 打開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也會消失不見
    console.log

去除條件編譯中不可達代碼

  • 什麼叫不可達代碼?就是不管什麼狀況下都不會被運行的代碼。

例如咱們在條件編譯打包出來的代碼中

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
```
![dead_code](http://upyun.luckly-mjw.cn/Assets/selective-compilation/dead_code.png)

UglifyJs的更多功能

UglifyJs還用不少強大的功能,如代碼混淆,壓縮,重拍版等。這裏附上UglifyJs官方網址
英文很差的同窗還能夠查看對應的中文文檔(其實這纔是重點#機智臉)
uglifyJS

完結,撒花花

003

相關文章
相關標籤/搜索