webpack學習筆記--壓縮代碼


瀏覽器從服務器訪問網頁時獲取的 JavaScript、CSS 資源都是文本形式的,文件越大網頁加載時間越長。 為了提升網頁加速速度和減少網絡傳輸流量,可以對這些資源進行壓縮。 壓縮的方法除了可以通過 GZIP 算法對文件壓縮外,還可以對文本本身進行壓縮。

對文本本身進行壓縮的作用除了有提升網頁加載速度的優勢外,還具有混淆源碼的作用。 由於壓縮后的代碼可讀性非常差,就算別人下載到了網頁的代碼,也大大增加了代碼分析和改造的難度。

下面來一一介紹如何在 Webpack 中壓縮代碼。

壓縮 JavaScript

目前最成熟的 JavaScript 代碼壓縮工具是 UglifyJS , 它會分析 JavaScript 代碼語法樹,理解代碼含義,從而能做到諸如去掉無效代碼、去掉日志輸出代碼、縮短變量名等優化。

要在 Webpack 中接入 UglifyJS 需要通過插件的形式,目前有兩個成熟的插件,分別是:

  •  UglifyJsPlugin :通過封裝 UglifyJS 實現壓縮。
  •  ParallelUglifyPlugin :多進程並行處理壓縮,4-4使用ParallelUglifyPlugin 中有詳細介紹。

由於 ParallelUglifyPlugin 在 4-4使用ParallelUglifyPlugin 中介紹過就不再復述, 這里重點介紹如何配置 UglifyJS 以達到最優的壓縮效果。

UglifyJS 提供了非常多的選擇用於配置在壓縮過程中采用哪些規則,所有的選項說明可以在 其官方文檔 上看到。 由於選項非常多,就挑出一些常用的拿出來詳細講解其應用方式:

  •  sourceMap :是否為壓縮后的代碼生成對應的 Source Map,默認為不生成,開啟后耗時會大大增加。一般不會把壓縮后的代碼的 Source Map 發送給網站用戶的瀏覽器,而是用於內部開發人員調試線上代碼時使用。
  •  beautify : 是否輸出可讀性較強的代碼,即會保留空格和制表符,默認為是,為了達到更好的壓縮效果,可以設置為 false
  •  comments :是否保留代碼中的注釋,默認為保留,為了達到更好的壓縮效果,可以設置為 false
  •  compress.warnings :是否在 UglifyJs 刪除沒有用到的代碼時輸出警告信息,默認為輸出,可以設置為 false 以關閉這些作用不大的警告。
  •  drop_console :是否剔除代碼中所有的  console  語句,默認為不剔除。開啟后不僅可以提升代碼壓縮效果,也可以兼容不支持 console 語句 IE 瀏覽器。
  •  collapse_vars :是否內嵌定義了但是只用到一次的變量,例如把 var x = 5; y = x 轉換成 y = 5,默認為不轉換。為了達到更好的壓縮效果,可以設置為 false
  •  reduce_vars : 是否提取出出現多次但是沒有定義成變量去引用的靜態值,例如把  x = 'Hello'; y = 'Hello'  轉換成  var a = 'Hello'; x = a; y = b, 默認為不轉換。為了達到更好的壓縮效果,可以設置為  false 。

也就是說,在不影響代碼正確執行的前提下,最優化的代碼壓縮配置為如下:

const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
module.exports = {
  plugins: [
    // 壓縮輸出的 JS 代碼
    new UglifyJSPlugin({
      compress: {
        // 在UglifyJs刪除沒有用到的代碼時不輸出警告
        warnings: false,
        // 刪除所有的 `console` 語句,可以兼容ie瀏覽器
        drop_console: true,
        // 內嵌定義了但是只用到一次的變量
        collapse_vars: true,
        // 提取出出現多次但是沒有定義成變量去引用的靜態值
        reduce_vars: true,
      },
      output: {
        // 最緊湊的輸出
        beautify: false,
        // 刪除所有的注釋
        comments: false,
      }
    }),
  ],
};

從以上配置中可以看出 Webpack 內置了 UglifyJsPlugin,需要指出的是 UglifyJsPlugin 當前采用的是 UglifyJS2 而不是老的 UglifyJS1, 這兩個版本的 UglifyJS 在配置上有所區別,看文檔時注意版本。

除此之外 Webpack 還提供了一個更簡便的方法來接入 UglifyJSPlugin,直接在啟動 Webpack 時帶上  --optimize-minimize  參數,即  webpack --optimize-minimize , 這樣 Webpack 會自動為你注入一個帶有默認配置的 UglifyJSPlugin。本實例提供項目完整代碼

壓縮 ES6

雖然當前大多數 JavaScript 引擎還不完全支持 ES6 中的新特性,但在一些特定的運行環境下已經可以直接執行 ES6 代碼了,例如最新版的 Chrome、ReactNative 的引擎 JavaScriptCore。

運行 ES6 的代碼相比於轉換后的 ES5 代碼有如下優點:

  • 一樣的邏輯用 ES6 實現的代碼量比 ES5 更少。
  • JavaScript 引擎對 ES6 中的語法做了性能優化,例如針對  const  申明的變量有更快的讀取速度。

所以在運行環境允許的情況下,我們要盡可能的使用原生的 ES6 代碼去運行,而不是轉換后的 ES5 代碼。

在你用上面所講的壓縮方法去壓縮 ES6 代碼時,你會發現 UglifyJS 會報錯退出,原因是 UglifyJS 只認識 ES5 語法的代碼。 為了壓縮 ES6 代碼,需要使用專門針對 ES6 代碼的 UglifyES

UglifyES 和 UglifyJS 來自同一個項目的不同分支,它們的配置項基本相同,只是接入 Webpack 時有所區別。 在給 Webpack 接入 UglifyES 時,不能使用內置的 UglifyJsPlugin,而是需要單獨安裝和使用最新版本的 uglifyjs-webpack-plugin。 安裝方法如下:

npm i -D uglifyjs-webpack-plugin@beta

Webpack 相關配置代碼如下:

const UglifyESPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
  plugins: [
    new UglifyESPlugin({
      // 多嵌套了一層
      uglifyOptions: {
        compress: {
          // 在UglifyJs刪除沒有用到的代碼時不輸出警告
          warnings: false,
          // 刪除所有的 `console` 語句,可以兼容ie瀏覽器
          drop_console: true,
          // 內嵌定義了但是只用到一次的變量
          collapse_vars: true,
          // 提取出出現多次但是沒有定義成變量去引用的靜態值
          reduce_vars: true,
        },
        output: {
          // 最緊湊的輸出
          beautify: false,
          // 刪除所有的注釋
          comments: false,
        }
      }
    })
  ]
}

同時,為了不讓 babel-loader 輸出 ES5 語法的代碼,需要去掉 babelrc  配置文件中的  babel-preset-env ,但是其它的 Babel 插件,比如  babel-preset-react  還是要保留, 因為正是  babel-preset-env  負責把 ES6 代碼轉換為 ES5 代碼。本實例提供項目完整代碼

壓縮 CSS

CSS 代碼也可以像 JavaScript 那樣被壓縮,以達到提升加載速度和代碼混淆的作用。 目前比較成熟可靠的 CSS 壓縮工具是 cssnano,基於 PostCSS。

cssnano 能理解 CSS 代碼的含義,而不僅僅是刪掉空格,例如:

margin: 10px 20px 10px 20px 被壓縮成 margin: 10px 20px
color: #ff0000 被壓縮成 color:red

還有很多壓縮規則可以去其官網查看,通常壓縮率能達到 60%。

把 cssnano 接入到 Webpack 中也非常簡單,因為 css-loader 已經將其內置了,要開啟 cssnano 去壓縮代碼只需要開啟 css-loader 的 minimize 選項。 相關 Webpack 配置如下:

const path = require('path');
const {WebPlugin} = require('web-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  module: {
    rules: [
      {
        test: /\.css/,// 增加對 CSS 文件的支持
        // 提取出 Chunk 中的 CSS 代碼到單獨的文件中
        use: ExtractTextPlugin.extract({
          // 通過 minimize 選項壓縮 CSS 代碼
          use: ['css-loader?minimize']
        }),
      },
    ]
  },
  plugins: [
    // 用 WebPlugin 生成對應的 HTML 文件
    new WebPlugin({
      template: './template.html', // HTML 模版文件所在的文件路徑
      filename: 'index.html' // 輸出的 HTML 的文件名稱
    }),
    new ExtractTextPlugin({
      filename: `[name]_[contenthash:8].css`,// 給輸出的 CSS 文件名稱加上 Hash 值
    }),
  ],
};
本實例提供項目完整代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM