很久沒寫文章,此次預計會帶來3篇的 Webpack 系列文章,將會在這幾天內更新完。javascript
Webpack3 自今年6月20日正式發佈而來,給咱們帶來Scope Hoisting
和Magic Comments
兩大功能,惋惜不在此次系列文章內容範疇裏,而本次文章的主要內容是從項目中總結獲得,固然也看了不少別人寫的文章,是能夠被應用到生產中。此次主要介紹三個方面,分別是壓縮 JavaScript 和 CSS、配置環境變量、ES 模塊機制帶來的Tree-shaking。css
假設咱們有一個前端開發需求,這個需求有點特別,不是業務上的需求,而是要求減小文件的大小。可知這個需求算是性能優化上範疇,減小文件大小,加速網絡傳輸,縮短網頁加載時間,增長用戶體驗,提升用戶滿意度。這是一個正向結果,得幹~html
這裏不得不提一下 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-core
、babel-loader
、babel-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-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_ENV
爲production
便可,但對於 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 的import
、export
,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-env
或 babel-preset-es2015
,就須要檢查一下這些 preset 的配置了。默認狀況下,它們都會ES 模塊機制的語法特性從新編譯爲 CommonJS,如將 ES 的import
和export
編譯爲 CommonJS 的require
和module.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