1. 程式人生 > >webpack 打包優化的四種方法(多程序打包,多程序壓縮,資源 CDN,動態 polyfill)

webpack 打包優化的四種方法(多程序打包,多程序壓縮,資源 CDN,動態 polyfill)

如今,webpack 毫無疑問是前端構建領域裡最耀眼的一顆星,無論你前端走哪條路線,都需要有很強的webpack 知識。webpack 的基本用法這裡就不展開講了。主要探討一下如何提高 webpack 的打包速度。

這篇文章以 vue cli3.0+webpack4.0+nodejs10.0+ 這幾個版本為例。

一、打包分析

1.1、速度分析

我們的目的是優化打包速度,那肯定需要一個速度分析外掛,此時 speed-measure-webpack-plugin 就派上用場了。它的作用如下:

  • 分析整個打包總耗時
  • 每個 pluginloader 的耗時情況

首先,安裝外掛

npm i -D speed-measure-webpack-plugin

然後修改 vue.config.js 配置檔案 (vuecli3+ 版本的配置檔案統一在這個檔案裡修改,如果沒有該檔案,在根目錄新建一個)

// 匯入速度分析外掛
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

// 例項化外掛
const smp = new SpeedMeasurePlugin();

module.exports = {
    configureWebpack: smp.wrap({
        plugins: [
            // 這裡是自己專案裡需要使用到的其他外掛
            new yourOtherPlugin()
        ]
    })
}

執行打包命令之後,可以看到,打包總耗時為 2min,51.99s

1.2、體積分析

分析完打包速度之後,接著我們來分析打包之後每個檔案以及每個模組對應的體積大小。使用到的外掛為 webpack-bundle-analyzer,構建完成後會在 8888 埠展示大小。

首先,安裝外掛

npm i -D webpack-bundle-analyzer

修改 vue.config.js 配置檔案

// 匯入速度分析外掛
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

// 匯入體積分析外掛
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

// 例項化速度分析外掛
const smp = new SpeedMeasurePlugin();

module.exports = {
    configureWebpack: smp.wrap({
        plugins: [
            // 例項化體積分析外掛
            new BundleAnalyzerPlugin()
        ]
    })
}

構建之後可以看到,其中黃色塊 chunk-vendors 檔案佔比最大,為 1.34MB

二、打包優化

2.1、多程序多例項構建,資源並行解析

多程序構建的方案比較知名的有以下三個:

  • thread-loader (推薦使用這個)
  • parallel-webpack
  • HappyPack

這裡以 thread-loader 為例配置多程序多例項構建
安裝 loader

npm i -D thread-loader

接下來在 vue.config.js 配置檔案中使用該 loader

// 匯入速度分析外掛
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

// 例項化外掛
const smp = new SpeedMeasurePlugin();
module.exports = {
    configureWebpack: smp.wrap({
        module: {
            rules: [
                {
                    test: /\.js$/,
                    use: ['thread-loader']
                }
            ]
        }
    })
}

然後看下構建花費的時間, 2min,49.21s,相較於之前提升了 5s

2.2、公用程式碼提取,使用 CDN 載入

對於vue,vuex,vue-router,axios,echarts,swiper等我們可以利用webpack的externals引數來配置,這裡我們設定只需要在生產環境中才需要使用。
下面配置 vue.config.js

// 匯入速度分析外掛
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

// 匯入體積分析外掛
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

//判斷是否為生產環境
const isProduction = process.env.NODE_ENV === 'production';

//定義 CDN 路徑,這裡採用 bootstrap 的 cdn
const cdn = {
    css: [
        'https://cdn.bootcss.com/Swiper/4.5.1/css/swiper.min.css'
    ],
    js: [
        'https://cdn.bootcss.com/vue/2.6.10/vue.min.js',
        'https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js',
        'https://cdn.bootcss.com/vuex/3.1.1/vuex.min.js',
        'https://cdn.bootcss.com/axios/0.19.0/axios.min.js',
        'https://cdn.bootcss.com/echarts/4.3.0/echarts.min.js',
        'https://cdn.bootcss.com/Swiper/4.5.1/js/swiper.min.js',
    ]
}

// 例項化外掛
const smp = new SpeedMeasurePlugin();
module.exports = {
    chainWebpack: config => {
        // 生產環境配置
        if (isProduction) {
            // 生產環境注入 cdn
            config.plugin('html')
                .tap(args => {
                    args[0].cdn = cdn;
                    return args;
                });
        }
    },
    configureWebpack: smp.wrap({
        module: {
            rules: [
                {
                    test: /\.js$/,
                    use: ['thread-loader']
                }
            ]
        },
        plugins: [
            new BundleAnalyzerPlugin()
        ],
        //生產環境注入 cdn
        externals: isProduction && {
            'vue': 'Vue',
            'vuex': 'Vuex',
            'vue-router': 'VueRouter',
            'axios': 'axios',
            'echarts': 'echarts',
            'swiper': 'Swiper'
        } || {}
    })
}

緊接著,改造 html 頁面。用於讓我們配置的 cdn 路徑注入到 html 頁面

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <!-- 使用 CDN 的 CSS 檔案 -->
  <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
  <% } %>
</head>

<body>
  <noscript>
    <strong>We're sorry but eye-admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->

 <!-- 使用 CDN 的 JS 檔案 -->
  <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
  <% } %>
</body>

</html>

最重要的一步,看下效果,可以看到現在耗時 1min,39.19s,整整提升了 1 分多鐘!

2.3、多程序多例項並行壓縮

並行壓縮主流有以下三種方案

  • 使用 parallel-uglify-plugin 外掛
  • uglifyjs-webpack-plugin 開啟 parallel 引數
  • terser-webpack-plugin 開啟 parallel 引數 (推薦使用這個,支援 ES6 語法壓縮)

安裝外掛依賴

npm i -D terser-webpack-plugin

接下來在 vue.config.js 配置檔案中使用外掛,最終的配置檔案如下

// 匯入速度分析外掛
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

// 匯入程式碼壓縮外掛
const TerserPlugin = require("terser-webpack-plugin");

// 匯入體積分析外掛
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

//判斷是否為生產環境
const isProduction = process.env.NODE_ENV === 'production';

//定義 CDN 路徑,這裡採用 bootstrap 的 cdn
const cdn = {
    css: [
        'https://cdn.bootcss.com/Swiper/4.5.1/css/swiper.min.css'
    ],
    js: [
        'https://cdn.bootcss.com/vue/2.6.10/vue.min.js',
        'https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js',
        'https://cdn.bootcss.com/vuex/3.1.1/vuex.min.js',
        'https://cdn.bootcss.com/axios/0.19.0/axios.min.js',
        'https://cdn.bootcss.com/echarts/4.3.0/echarts.min.js',
        'https://cdn.bootcss.com/Swiper/4.5.1/js/swiper.min.js',
    ]
}

// 例項化外掛
const smp = new SpeedMeasurePlugin();
module.exports = {
    chainWebpack: config => {
        // 生產環境配置
        if (isProduction) {
            // 生產環境注入 cdn
            config.plugin('html')
                .tap(args => {
                    args[0].cdn = cdn;
                    return args;
                });
        }
    },
    configureWebpack: smp.wrap({
        module: {
            rules: [
                {
                    test: /\.js$/,
                    use: ['thread-loader']
                }
            ]
        },
        plugins: [
            new BundleAnalyzerPlugin()
        ],
        //生產環境注入 cdn
        externals: isProduction && {
            'vue': 'Vue',
            'vuex': 'Vuex',
            'vue-router': 'VueRouter',
            'axios': 'axios',
            'echarts': 'echarts',
            'swiper': 'Swiper'
        } || {},
        optimization: {
            minimizer: [
                new TerserPlugin({
                    parallel: 4
                })
            ]
        }
    })
}

2.4、使用 polyfill 動態服務

動態 polyfill 指的是根據不同的瀏覽器,動態載入需要的 polyfillPolyfill.io 通過嘗試使用 polyfill 重新建立缺少的功能,可以更輕鬆地支援不同的瀏覽器,並且可以大幅度的減少構建體積。

Polyfill Service 原理

識別 User Agent,下發不同的 Polyfill

使用方法:在 index.html 中引入如下 script 標籤

<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js"></script>

三、完結

At last,看完之後有什麼不懂的,可以留言反饋。

轉載請註明出處:https://www.jianshu.com/p/481e7214a134
作者:TSY
個人空間:https://hxkj.vip