優化 Vue 項目編譯文件大小

與其說是優化 Vue,不如說主要是在 webpack 打包的配置中作些文章,使得 Vue 編譯後的文件儘量的小。如下介紹本身在項目中進行優化的過程,其中的內容也許並不適合於每一個項目,但總體思路是差很少的。

定位問題

要想進行優化,首先咱們得清楚問題所在。即:是哪些代碼/依賴包致使最後的編譯文件過大?javascript

這裏,咱們須要使用 webpack-bundle-analyzer 工具。修改 package.json 文件,添加:php

"analyze": "NODE_ENV=production npm_config_report=true npm run build"

而後執行:css

npm run analyze

便會在瀏覽器中打開一個頁面,展現編譯後的文件大小及各部份內容大小。如下是項目在優化前的分析結果:html

image_1boript2gp7jl2nqcmud7kpsm.png-524kB

從圖中能夠看出,最後編譯出的 vendor.js 文件達到了 5MB,其中主要來自 echarts。此外,因爲 element-ui 在使用時已經注意到按需加載組件,因此可優化的部分很少;而 lodash 因爲沒有按需加載,因此成爲須要優化的另外一個核心部分。vue

使用按需加載優化

這裏主要是對 lodash 進行優化。當咱們在使用 lodash 時,若是使用:java

import _ from 'lodash'

_.get(obj, 'key', 'default_value')

這種方式的話,則在編譯時會默認將 lodash 的所有內容進行編譯打包。node

webpack 的介紹中確實提到了按需加載,但這個概念可能會出現理解上的誤差,下面咱們舉例說明:webpack

// 方法一:會致使加載所有的 lodash 庫
import _ from 'lodash'
_.get()

// 方法二:只會加載其中的 get 方法
import get from 'lodash/get'
get()

即在不添加其餘插件和配置的狀況下,webpack 還作不到如此智能。nginx

想要實如今使用方法一的狀況下,也能按照咱們使用過的方法真正「按需加載」,則須要使用插件並添加配置:web

首先執行:

npm i --save-dev babel-plugin-lodash babel-cli babel-preset-es2015

而後修改 .babelrc

{
  "plugins": ["lodash"],
  "presets": ["es2015"]
}

以後修改 webpack.prod.conf.js

module: {
    loaders: [{
        'loader': 'babel-loader',
        'test': /\.js$/,
        'exclude': /node_modules/,
        'query': {
            'plugins': ['lodash'],
            'presets': ['es2015']
        }
    }]
}

這以後即可以實現按需加載 lodash 了。從新進行分析,會發現 lodash 部分的大小已經能夠忽略不計了。

對於其餘的,如 Element-UI 之類的第三方庫,若是咱們只使用到了爲數很少的組件,建議查找相應的按需加載插件和配置方式,這樣能夠極大的減小該部分編譯的大小。

路由懶加載

當咱們配合 Vue-Router 構建單頁應用時,大量的組件會致使首屏加載緩慢,如官方文檔所言:

當打包構建應用時,Javascript 包會變得很是大,影響頁面加載。若是咱們能把不一樣路由對應的組件分割成不一樣的代碼塊,而後當路由被訪問的時候才加載對應組件,這樣就更加高效了。

只需將原有的:

import Test from '../pages/test'

export default new Router({
    routes: [
        {
            path: '/test',
            name: 'test',
            component: Test
        }
    ]
});

改成:

const Test = () => import('../pages/test')

export default new Router({
    routes: [
        {
            path: '/test',
            name: 'test',
            component: Test
        }
    ]
});

注意首行的不一樣。

第三方庫懶加載

在實際開發中,可能存在這樣的場景:

在某個組件/文件中須要使用 moment 第三方庫來進行時間處理,但其餘組件根本用不到。

若是咱們這樣引入 moment:

import moment from 'moment'

export default {
    data () {
        
    },
    mounted () {
        
    }
}

則該庫會合並在 vendor.js 中,形成首屏加載緩慢。

爲了解決這個問題,咱們能夠改爲如下引入方式:

export default {
    name: '',
    beforeCreate () {
        import('moment').then(module => {
            this.moment = module;
        });
    },
    data () {
        return {
            moment: null
        }
    }
}

這種方式可使得 moment 庫只在該組件使用處引入。注意,這種方式須要考慮「moment 調用時機與 moment 使用的前後問題」。

注:若是該組件是頁面級別的組件,則使用「路由懶加載」中的方法就能夠了。

使用 CDN 外部加載

如上所示,echarts 模塊佔了很大的部分,因爲沒有找到 echarts 按需加載的插件,這裏咱們經過外部引用的方式來減小編譯的大小。

首先,咱們修改 index.html,從 CDN 中引入 echarts 文件:

<script src="https://cdn.bootcss.com/echarts/3.7.0/echarts.min.js"></script>

注意,若是須要地圖組件,也須要一併引入。

這以後咱們須要刪除全部 import echarts from 'echarts' 的代碼,即再也不經過這種方式引入 echarts。

但問題來了,若是這麼作的話,webpack 在打包的時候會發現 echarts 變量不存在而中止編譯。解決辦法是,咱們須要在 webpack 配置中告知編譯器,對於 echarts 變量使用了引入外部資源的方式。須要修改 webpack.base.config.js

module.exports = {
    externals: {
        "echarts": "echarts"
    },
}

這以後咱們即可以直接使用 echarts 這一變量而不會致使編譯錯誤了。

當咱們將全部採用以前方式引入 echarts 的代碼刪除或註釋以後,再次進行分析,會發現編譯大小少了不少。

通過以上兩步,本來 5M 的編譯文件變爲了 1.67 M。

image_1borqhoh016un1gt7b8f1b25djp13.png-505.8kB

這以後,咱們還能夠根據分析結果,針對性地進行優化。如更換時間庫爲更輕量級的 spacetime 等。

服務器端開啓 gzip

使用 gzip 能夠進一步壓縮文件,使得服務器傳遞給瀏覽器的文件是經由壓縮以後的,待瀏覽器收到以後再解壓縮。要使用這一方式,須要服務器端的支持,這裏以 Nginx 爲例。

nginx.conf 中,添加以下配置:

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
#gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/javascript;
gzip_vary off;

以後刷新頁面( 注意禁用緩存 ),觀察 js、css 等資源文件的請求中是否包含 Content-Encoding: gzip,若是存在,則代表 gzip 已成功。

注意,在 gzip_types 中規定了哪些請求類型會使用 gzip 進行壓縮。對於沒有使用 gzip 的資源文件,可將其 Content-type 類型加入 gzip_types 之中。

服務器端渲染

注意,在以上對打包過程的優化中,受影響的主要是 vendor.js 文件中第三方庫的部分( gzip 方法會影響所有資源文件 )。

若是咱們想繼續進行優化,就須要考慮服務器端渲染了。

Vue 的做用機制實際是使用 js 向 html 中掛載組件,若是咱們可以將這一過程放在服務器端進行,就能夠再也不向瀏覽器傳輸一部分驅動文件,從而進一步減小瀏覽器所需的文件大小。不過這一過程須要服務器的額外支持,有興趣的同窗能夠參考:實例 PK ( Vue服務端渲染 VS Vue 瀏覽器端渲染 )


參考

  1. 實例 PK ( Vue服務端渲染 VS Vue 瀏覽器端渲染 ) - segmentfault
  2. 使用vue-cli生成的vendor.js文件太大,有辦法減小體積嗎? - segmentfault
  3. Webpack 打包優化之體積篇
  4. babel-plugin-lodash
  5. Nginx開啓Gzip壓縮大幅提升頁面加載速度 - 博客園
  6. Nginx啓用Gzip壓縮js無效的緣由 - 博客園
  7. Wabpack系列:在webpack+vue開發環境中使用echarts致使編譯文件過大怎麼辦? - 博客園
  8. Webpack 打包優化之速度篇
  9. 開啓gzip 若是瀏覽器端不支持解壓 頁面會怎麼樣? - 知乎
  10. 如何寫一手漂亮的 Vue
相關文章
相關標籤/搜索