第一次寫掘金,以前都是看別人的文章,此次主要是想記錄下近期項目中遇到的問題,和本身的一些成長。php
先簡述下最近項目的技術選型,公司在兩個月前前端技術方面進行升級,以後的項目均要採用主流框架來開發。在作了三個 vue 的中型項目後,有一些坑和爬坑的過程,也是對這三個項目的進行一些系統的總結吧,如文章有哪些不足之處,評論區多多交流,互相學習。更但願各位同窗看事後能有一些感觸和收穫。css
一. 項目概述:使用vue全家桶開發,但沒有使用vue-cli,至於緣由,下面會詳細解釋。
二. 項目坑點:作了三個中型項目後,業務邏輯層並無踩什麼坑,坑點主要在如下幾個方面
複製代碼
公司主項目仍是最傳統的jQ + php的架構,座標在帝都的互聯網公司,技術上其實已經與大多互聯網公司差了一大截。因此在進行新項目選型時,身爲公司惟一一個前端,立即決定使用 vue 來作,真正作到先後端分離。但肯定了主框架,那到底使用vue-cli呢,仍是vue+webpack本身搭呢?(產品給的項目排期是5天研發並測試,5天后上線),還得考慮到工期問題。html
通過斟酌,仍是選擇了本身搭建,緣由有如下幾點:前端
- 本身定製的腳手架哪出了問題本身內心清楚,從而也能培養一些前端架構的能力
- 更熟練的掌握webpack配置的能力,以及webpack3.0升級爲4.0踩坑的能力
- 若是後期項目轉型爲服務端渲染(SSR),能更快的更改配置,這個是 vue-cli不具有的能力
除了以上幾點,我的以爲,是否具備webpack配置的能力,是衡量一個前端的水平高低的標準,筆者面試不少前端,三年經驗的前端能從0配置webpage的幾乎不多,更不要說性能優化或是本身寫loader和plugin了。vue
entry
,output
,loader
,plugins
,由於本文不是具體講如何配置webpack,因此就不一一贅述了,網上的此類教程也是比比皆是。這裏主要記錄下我在配置過程當中踩過的坑和值得總結的地方。node
先簡單聊聊webpack3.0版本和4.0版本的主要的區別吧jquery
1. webpack4必須安裝webpack-cli
2. webpack4中設置加了一個mode配置,只有兩個值development | production,對不一樣的環境會提供不一樣的一些默認配置
3. 拆分單獨模塊使用optimization.splitChunks替代了CommonsChunkPlugin
4. 提取單個css文件使用MiniCssExtractPlugin替代extract-text-webpack-plugin
5. 若是是開發vue項目,基礎配置文件必須引入vue-loader/lib/plugin
6. 不在使用UglifyJsPlugin壓縮js文件,而是經過optimization.minimize設置爲true來壓縮代碼,mode爲production時,其默認爲ture
7. 引入了Tree Shaking,不打包無用代碼
複製代碼
以上就是4.0版本主要的升級,固然還有不少,在此附上官方change logwebpack
注意:
MiniCssExtractPlugin僅僅會把js中的css提取到單獨的css文件中,但並不會對其進行壓縮
壓縮css須要單獨使用optimize-css-assets-webpack-plugin,並在optimization選項中進行配置
複製代碼
optimization: {
minimizer: [
<!--壓縮css--> new OptimizeCSSAssetsPlugin({ assetNameRegExp: /\.css$/ }) ] } 複製代碼
項目配置的大體思路就是根據不一樣的環境配置不一樣的config.js,經過webpack-merge合併基礎配置,package.json中,根據不一樣的命令進行相應操做便可。看圖說話: git
"dev": "webpack-dev-server --config build/webpack.dev.config.js",
"build": "webpack --config build/webpack.prod.config.js",
"build:dll": "webpack -p --progress --config build/webpack.dll.config.js"
複製代碼
1. Tree Shakinggithub
tree shaking 是一個術語一般用於打包時移出Javascript中爲引用的代碼,它依賴於ES6模塊系統中的
import
和export
的靜態結構特性。
開發時引入一個模塊後,若是隻使用其中一個功能,上線打包時只會把用到的功能打包進對應的bundle,其餘沒用的功能都不會打包進來,從而實現最基礎的優化。
前提是使用了
import
和export
的語法進行導入導出。什麼意思呢?意思就是 若是一個模塊使用了ES6的導入導出,那在打包線上代碼時,就會shaking掉無用代碼;可是!注意咯,若是使用的是require這種commonJS規範的導入導出,那麼它不會進行shaking。
爲何require的模塊不會被加入shaking行列呢?緣由在於require是動態導入,在webpack打包時,若是是動態導入的模塊,它並不知道被導入的模塊內是否有無用代碼,因此不會被shaking掉。
2. scope hoisting做用於提高
scope hoisting 的做用是將模塊之間的關係進行結果推測(預編譯),可讓webpack打包出來的代碼文件更小,運行更快。
scope hoisting的實現原理其實很簡單:分析出模塊之間的依賴關係,儘量的把打散的模塊合併到一個函數中去,但前提是不能形成代碼冗餘,所以,只有那些被引用了一次的模塊才能被合併。
因爲scope hoisting須要分析出模塊之間的依賴關係,所以源碼必須採用ES6模塊話語句,這點和tree shaking同樣。
3. 代碼壓縮
production模式下,默認會對js代碼進行壓縮和提取(SplitChunksPlugin)
1. 儘量的少用loader
webpack打包耗時的大部分時間是由於loader預編譯這一階段,因此儘量的少用loader,以下圖
file-loader
,url-loader
,img-loader
. 可是url-loader
官方聲明:url-loader works like file-loader,意思是url-loader
相似於file-loader
,那就不要再使用file-loader
來配置(除非圖片過大,超出url-loader中配置的limit值)2. 動態導入(懶加載)
webpack默認是容許
import
語法動態導入的,可是須要babel
的插件支持,即 在.babelrc配置文件中添加@babel/plugin-syntax-dynamic-import
插件
動態導入的最大好處就是實現了懶加載,用到哪一個模塊纔會加載哪一個模塊,能夠提升SPA應用程序的首屏加載速度
3. noParse
在引入一些第三方模塊時,例如jQuery,element-ui等,咱們知道其內部不會再依賴其餘模塊,由於咱們最終用到的只是一個單獨的js文件,因此此時webpack若是再去解析jQuery內部的依賴關係,是很是耗時的。
能夠在webpack配置文件中的module節點下加上noParse,並配置正則來告訴webpack,我不須要再去解析這些模塊
module: {
noParse: /jquery|element-ui/
}
複製代碼
坑點來啦:
element-ui
若是 按需引入,注意,這裏不能使用noParse
來作element-ui
的優化,由於按需引入的element,內部會有一系列依賴關係,使用noParse,webpack並不會去解析其依賴
下面看看優化結果,打包速度提高了接近4倍
4. IgnorePlugin
項目中使用了element-ui和moment.js,這兩個插件內部都有不少語言包,尤爲是moment.js。而語言包打包時會比較佔用空間,而咱們的項目只須要中文語言包,這時就應該忽略掉全部的語言包,改成按需引入,從而使得構建效率更高,打包生成的文件更小
下面看看打包耗時和dll包的大小,結果仍是不錯的
5. 經過減小文件搜索範圍來提升性能
什麼叫減小文件搜索範圍?這塊須要先理解什麼是webpack基本原理。webpack經過配置文件,將項目中引入的第三方和公共模塊進行提取,每個提取出的模塊都有一個id,在引用到該模塊的主文件中,經過id進行映射查找。因此若是能提高文件查找速度,對webpack打包性能會有必定提高。
resolve.modules
經過配置,告訴webpack在解析模塊時應該搜索哪些目錄。import vue from 'vue'
import myCommonJs from '../src/myCommonJs'
複製代碼
上面代碼,分別引用了第三方庫和公共js,默認的webpack配置,會在當前路徑下向上遞歸的搜索文件進行打包引用。此時就可使用resolve.modules
來告訴webpack,我是要到node_modules目錄下和src目錄下去找這兩個文件。
在配置loader時,經過配置include 和exclude更精確指定要處理的目錄,這能夠減小沒必要要的遍歷,從而減小性能損失。這個是更爲簡單的方式,這裏就不進行贅述了
6. Happypack多進程進行打包構建
webpack打包構建默認是單進程進行打包,當一個babel-loader須要處理多個不一樣類型的資源文件時,node的單進程讀取文件特性就有耗性能了,這時候就須要用到 Happypack了。但多是項目規模和文件資源較爲單一的緣由,筆者經過配置Happypack,實際打包速度並無獲得提高,反而速度多了2-3s,以後0須要再仔細研究下。
7. 設置babel-loader 配置項cacheDirectory爲true
設置後,給定目錄將用於緩存加載器的結果。以後webpack構建將嘗試從緩存中讀取,以免在每次運行時運行可能昂貴的Babel從新編譯過程
8. DllPlugin 和 DllReferencePlugin
DllPlugin爲webpack提供的打包動態連接庫,通常用來打包一些版本不須要常常更新的第三方庫。單獨提供一份打包動態連接庫的配置文件(即上圖中的webpack.dll.config.js),生成環境打包以前先打包動態連接庫,打包後會生成vendor_dll.js和vendor-manifest.json,它包含從引入請求到模塊ID的映射
DllReferencePlugin,該插件爲生產環境配置文件(webpack.prod.config.js)中使用,其中的manifest選項,
require
DllPlugin打包生成的manifest.json文件,將依賴項名稱映射到模塊ID,而後使用內部__webpack_require__函數根據須要使用它們
主要思想在於,將一些不作修改的依賴文件提早打包,這樣咱們在開發代碼發佈的時候,就不須要再對這部分代碼進行打包,從而節省了打包時間
實際項目中配置此項,可提高6-8s的打包速度
坑點:
1. 生成的vendor_dll.js必須手動的引入index.html中,或者經過add-asset-html-webpack-plugin將vendor_dll.js動態的添加到html文件中
2. 再使用add-asset-html-webpack-plugin時動態引入動態連接庫生成映射後的js時,由於打包生成環境時,使用了
speed-measure-webpack-plugin進行耗時分析,從而致使打包出錯,報錯以下。
猜想應該是兩個插件不兼容吧,有大佬也遇到過此類問題和解決的方法,求分享
複製代碼
9. 引用cdn連接引入第三方庫
總結完畢,網上此類的總結有不少,但經過自身配置和經過webpack-bundle-analyzer和speed-measure-webpack-plugin來觀測打包性能,並進行優化總結,又一次加深了對webpack配置及原理的理解.