俗話說得好,引用依賴一時爽,一直引用一直爽。javascript
在開發項目的過程當中,咱們每每須要引用到大量的第三方模塊(node modules)。確實,經過引用第三方模塊,能大大的簡化開發的過程,提升工程質量。但不免的,也帶來了「體積」這個問題。筆者曾經開發過一個簡單的網站項目,功能簡單,業務邏輯也只是純粹的查看信息。但在通過了混淆壓縮後,依然達到了1M多。是的,這個項目毫無疑問是不及格的。由於即使在現今隨隨便便百兆網絡的時代下,因爲服務器、通路等多重因素的影響下,整個項目的加載每每須要數秒鐘。在網絡上有人是這麼描述這幾秒鐘的:css
若是網頁加載時間超過4秒,約有四分之一的人會放棄打開該網頁。
若是網頁加載時間超過10秒,50%的移動用戶會放棄該網頁,約五分之三的人不會再返回該網站。html
因此,咱們在可容許的範圍內,除了在物理層面上加強咱們的訪問速度外,還應該從項目的根源入手,儘量的減小訪問須要的時間。
在本文中,筆者總結了以前項目中一些精簡項目的方法,但願能對各位看官有所幫助。vue
通常狀況下,webpack是vue項目的不二之選。那麼,如何分析使用webpack打包後的包文件呢?在這裏就要介紹本文的核心主角包分析工具——webpack-bundle-analyzer
。 java
衆所周知的,webpack是一個將網頁元素打包的工具。在一個JS文件中,不只包含了javascript的代碼,還包含了如「html」、「css」等等元素。若是純粹的經過直接分析包中的內容,或者經過分析webpack配置(甚至在Vue Cli 三、Angular Cli 3,根本就不存在webpack配置文件),是很是不現實的事情。而webpack-bundle-analyzer
則能夠爲咱們提供圖形化的包分析。 node
在webpack-bundle-analyzer中,咱們能夠看到各個模塊所佔項目的比例,以及模塊在Stat
、Parsed
、Gzipped
狀態下的大小。嗯,是的,這樣咱們就能找出使項目臃腫的元兇了!webpack
--report
便可生成分析報告。webpack-bundle-analyzer
# NPM npm install --save-dev webpack-bundle-analyzer # Yarn yarn add -D webpack-bundle-analyzer 複製代碼
而後,添加到項目的配置文件中:git
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { plugins: [ new BundleAnalyzerPlugin() ] } 複製代碼
編譯完畢後,即會生成分析報告。github
--stats-json
將會生成一個json文件。既然咱們如今已經知道了「元兇」是誰了,那咱們如今應該去處理它了。對於,不一樣的第三方模塊咱們有不一樣的方法去解決它:web
通常最經常使用的import形式是這樣的:
import crypto from 'crypto-js' ... crypto.HmacSHA1() ... 複製代碼
這種方法將會引入整個crypto(第三方模塊)。然而,咱們每每僅須要其中的一兩個方法。這是一個很是不划算的行爲,同時也是項目中最多見的臃腫的緣由。經過局部引入須要的方法,咱們即可以很大程度的減小項目的臃腫程度:
import HmacSHA1 from 'crypto-js/hmac-sha1' ... HmacSHA1() ... 複製代碼
至於如何找到局部引入的文件,由於不一樣模塊的項目結構不盡一致,因此沒有一個標準的答案。不過,最多見的方法,就是查看第三方模塊的入口文件或者查閱官方的文檔,每每能夠找到最小化引入的方法。
影響首屏加載速度的,是那些隨着html文件「同步」下載的js文件。有很多第三方模塊是不會在首屏加載時用到的,並且他們沒法經過「最小化引入」有效減小它們的大小。此時,便應該考慮將一些無需隨着首屏加載的內容,經過異步的形式,在它們須要的時候加載。
熟悉Vue的各位大佬們大概都早已熟知Vue異步組件的寫法
... components: { asyncComponent: () => import('./asyncComponent.vue') // function(){ // return import('./asyncComponent.vue') // } } ... 複製代碼
但對於新手而言,他們可能會誤認爲這是Vue中提供的異步組件加載的方式。但實際上,這是webpack進行異步模塊加載的方法。import能夠運用在各個方面,如:加載Echarts
const Echarts = () => import('echarts') ... Echarts().then(echarts => { echarts.xxx() }) ... 複製代碼
此方法也能夠在Angular 8中使用
不少流行的UI庫是沒法直接按需引入須要的組件的(其實不少都是能夠的,但小部分組件會出現問題)。如:Element、ant-design-vue、iView 、Mint UI等等。但他們每每很是的「龐大」,多數可達2~3M。對於網頁應用而言,這確定是沒法接受的。不過萬幸的是,它們均可以經過babel-plugin-component
進行按需引入(或者直接按需引入)。具體的方法能夠參閱它們各自的官方文檔。須要注意的是,因爲css文件是全局引入的,須要注意樣式被污染的問題。
對於一些特殊的模塊而言,他們可能沒法使用「按需引入」的方法進行瘦身。就好比「moment.js」,在引入其本體的同時,它會附帶所有的多語言支持的模塊。但這些每每是咱們不須要的。
ContextReplacementPlugin 能夠經過正則表達式或其餘過濾條件忽略引入的第三方模塊的某些文件,從而達到瘦身的需求。
在webpack的官方文檔中,正是以moment.js做爲實例的。
new webpack.ContextReplacementPlugin( /moment[\/\\]locale$/, /de|fr|hu/ ) 複製代碼
在全部的方法都沒法知足功能需求>文件體積的時候,爲什麼不嘗試換一個模塊試試呢?
在npm中充斥着大量的功能類似的module,好比:querystring,我所知的就有qs\query-string\querystringify...它們大多功能類似,但因爲實現的方法、考量的形式不一樣等等方面,致使了它們之間存在很多的差別。所以,爲了減小沒必要要的文件體積,咱們能夠嘗試選擇與之類似的或者功能沒有如此強大的但剛好符合咱們需求的模塊。就如「moment.js」在多數的狀況下,能夠被「dayjs」所替代。然後者則宣稱它只佔用2kb的空間。
固然,在選擇第三方模塊的時候,也須要考量這個模塊是否足夠的成熟。
第三方模塊能幫助咱們解決不少問題。但並非全部的「複雜」功能都須要經過引入第三方模塊來解決。
舉個簡單的栗子:
若是你只須要獲取URL中的參數,你不須要引入Vue Router或者XXX Router。你只須要qs.parse(location.search)便可.甚至連qs庫都無需引入:
Object.fromEntries( location.search .slice(1) .split('&') .map(v => v.split('=')) ) 複製代碼