Webpack 最佳實踐總結(一)

很久沒寫文章,此次預計會帶來3篇的 Webpack 系列文章,將會在這幾天內更新完。javascript

Webpack3 自今年6月20日正式發佈而來,給咱們帶來Scope HoistingMagic Comments兩大功能,惋惜不在此次系列文章內容範疇裏,而本次文章的主要內容是從項目中總結獲得,固然也看了不少別人寫的文章,是能夠被應用到生產中。此次主要介紹三個方面,分別是壓縮 JavaScript 和 CSS、配置環境變量、ES 模塊機制帶來的Tree-shaking。css

假設咱們有一個前端開發需求,這個需求有點特別,不是業務上的需求,而是要求減小文件的大小。可知這個需求算是性能優化上範疇,減小文件大小,加速網絡傳輸,縮短網頁加載時間,增長用戶體驗,提升用戶滿意度。這是一個正向結果,得幹~html

壓縮 JavaScript

這裏不得不提一下 Google 的 Closure Compiler,一款可讓 JavaScript 下載與執行更快的工具,它的作法是執行一些"焦土"(scorched-earth)優化策略,它將函數展開,重寫變量名,過濾多餘代碼,刪除從不會調用的函數,從而生成多是最優化的代碼。以下前端

優化前java

function map(array, iteratee) {
  let index = -1
  const length = array == null ? 0 : array.length
  const result = new Array(length)

  while (++index < length) {
    result[index] = iteratee(array[index], index, array)
  }
  return result
}

優化後webpack

function map(n,e){let r=-1;for(const i=null==n?0:n.length,t=Array(i);++r<i;)t[r]=e(n[r],r,b);return t}

對比發現優化效果極好,若是使用 UglifyJS 同樣能夠達到相同的優化效果。因爲 Webpack 內置這款插件,能夠直接使用,配置以下git

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.optimize.UglifyJsPlugin()
  ]
};

使用該插件優化先後的對比結果以下說明:github

假設咱們有一段代碼,以下:web

// comments.js
import './comments.css';
export function render(data, target) {
    console.log('Rendered!');
}

Webpack 編譯以後的代碼大概以下:npm

// bundle.js (part of)
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
var __WEBPACK_IMPORTED_MODULE_0__comments_css__ =
  __webpack_require__(4);
var __WEBPACK_IMPORTED_MODULE_0__comments_css___default =
  __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__comments_css__);
__webpack_exports__["render"] = render;

function render(data, target) {
    console.log('Rendered!');
}

若是使用了 UglifyJS 插件,從新編譯以後的代碼大概以下:

// bundle.js (part of)
"use strict";function r(e,t){console.log("Rendered!")}
Object.defineProperty(t,"__esModule",{value:!0});
var o=n(4);n.n(o);t.render=r

特殊狀況說明:目前,UglifyJS 2(Webpack自帶的) 是沒法編譯 ES2015+ 的代碼,意味着若是代碼中是了類、箭頭函數或者其餘新的特性,並且你沒有將代碼編譯爲 ES5,那麼 UglifyJS 插件是沒法處理這些代碼的,這裏提供兩種處理方法:

方法1:給 Webpack 添加支持 babel,基本過程以下

安裝 babel-corebabel-loaderbabel-preset-es2015

npm i babel-core babel-loader babel-preset-es2015 --save-dev

給 Webpack 添加配置信息

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js[x]$/,
        use: [{'babel-loader', options: {
          presets: ['es2015']
        }]
      }
    ]
  }
};

方法2:使用 Babili 取代 UglifyJS 2,這是一款基於 Babel 的壓縮工具,更多瞭解查看 babili-webpack-plugin,這裏不做太多的描述

壓縮 CSS

壓縮 CSS 的方法比較簡單,css-loader 就自帶壓縮功能,配置以下:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          { loader: 'css-loader', options: { minimize: true } }
        ]
      }
    ]
  }
};

另外我還寫過 Webpack 跟 Less 和 Sass 的配置教程,具體看:here1, here2

配置環境變量

NODE_ENV設置爲production也能幫助減小前端項目大小

NODE_ENV一般做爲環境變量被各類js框架或庫做爲判斷條件去做爲哪一種執行模式,如開發模式或是生產模式,這些框架或者庫根據NODE_ENV的值去表現對應的行爲。例如,當處於開發模式時,React 會作額外的檢測和打印警告:

// …
if (process.env.NODE_ENV !== 'production') {
  validateTypeDef(Constructor, propTypes, 'prop');
}
// …

若是要打包構建項目到生產環境中,最好能夠告訴項目中的框架或庫當前的環境變量是生產環境。對於適用於 Node.js 的庫來講,直接配置NODE_ENVproduction便可,但對於 Web 端來講,可使用 Webpack 自帶的插件實現對
process.env.NODE_ENV的設置,以下

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: {
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"'
    })
  }
};

DefinePlugin 容許咱們建立全局變量,同時這些變量會做用於webpack的打包編譯期內。它會代替全部的process.env.NODE_ENV實例的值爲"production",從而使 UglifyJS 知道那些判斷表達式老是錯誤的,從而刪除相關代碼,進一步壓縮打包文件

ECMAScript模塊機制

項目中使用 ECMAScript 的importexport,Webpack 經過 tree-shaking 也能經過打包有用的代碼,進一步減小大小。 Tree-shaking 能夠檢查整個打包依賴樹,找到使用的部分。因此若是使用 ECMAScript 模塊機制,Webpack 會去掉無用的代碼,以下:

假設寫了兩個文件,但只使用了其中一個文件

// comments.js
export const commentRestEndpoint = '/rest/comments';
export const render = () => { return 'Rendered!'; };

// index.js
import { render } from './a.js';
render();

Webpack 知道componentRestEndpoint是沒有被使用,打包文件也不會有該入口

// bundle.js (part of)
(function(module, __webpack_exports__, __webpack_require__) {
  "use strict";
  /* unused harmony export commentRestEndpoint */
  /* harmony export */__webpack_exports__["b"] = render;

  var commentRestEndpoint = '/rest/comments';
  var render = function () { return 'Rendered!'; }
})

UglifyJS 插件去掉無用部分

// bundle.js (part of)
(function(n,e){"use strict";e.b=r;var r=function(){return"Rendered!"}})

若是 JavaScript 框架或庫使用了 ECMAScript 模塊機制,那麼 Tree-shaking 是對其也是有效滴

注意事項

一、 若是沒有 UglifyJS ,tree-shaking 將不做用

實際上,去掉無用的代碼不是 Webpack 自己,而是 UglifyJS。Webpack 只是去掉 export 表達式使那些 exports 再也不使用,從而能夠在壓縮的時候被去掉。所以,若是你打包的時候沒有使用壓縮,打包文件就不會變得更小

二、不要將 ES 模塊機制編譯爲 CommonJS

若是你使用了 babel-preset-envbabel-preset-es2015,就須要檢查一下這些 preset 的配置了。默認狀況下,它們都會ES 模塊機制的語法特性從新編譯爲 CommonJS,如將 ES 的importexport編譯爲 CommonJS 的requiremodule.exports。咱們可使用 { modules: false } 禁止編譯行爲,以下:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js[x]$/,
        use: [{'babel-loader', options: {
          presets: [['es2015', { modules: false }]]
        }]
      }
    ]
  }
};

三、在特殊條件下 Webpack 不會進行優化

當你使用了export * from 'file.js' 或者是 TypeScript,Webpack 是不會進行優化。這些特殊條件在代碼中很難被發覺,也很難知道這些特殊條件的代碼是否被修復,更多瞭解能夠查看 here

總結

Webpack 對前端項目優化有不少種,這裏提供了四種技巧,分別是經過 UglifyJS 插件實現對 JavaScript 文件的壓縮,css-loader 提供的壓縮功能,配置NODE_ENV能夠進一步去掉無用代碼,tree-shaking幫助找到更多無用代碼

內容較多,大概就這樣~

文章首發於:https://www.linpx.com/p/webpa...
歡迎訪問個人博客:https://www.linpx.com

相關文章
相關標籤/搜索