Front-End-Projekt extreme Performance-Optimierung

Hintergrund

Leiter: Warum wird das die ganze Zeit geladen? Es ist schon so lange offen
. I: Das erste Laden ist etwas langsam. Sie sehen hier einen Erinnerungstext.
Leiter: Diese Erfahrung ist zu schlecht. Finden Sie einen Weg, sie zu optimieren
. I: Dieses Projekt ist zu groß, fast zweihundert Ein System von 1 Seite... Back-
End-Klassenkameraden: Dann hat Taobao, Alibaba Cloud nicht mehr Seiten als unser System?
Leiter: (Der Leiter sah mich an)
Ich: Okay, der Anführer (Lächeln auf den Lippen und MMP im Herzen)

WechatIMG159.jpeg Die oben genannten Inhalte sind für den Zweck des Programms rein fiktiv, diese Optimierung erfolgt ausschließlich aus Liebe zur Technik und Begeisterung für die Arbeit.

Als nächstes werden wir das Projekt optimieren, zuerst die Ergebnisse verderben, nehmen wir das grundlegende Vue Cli3-Projekt als Beispiel:

Optimierung Vor der Optimierung Optimiert
Oberhalb der Ladezeit 30+ 2,5 Sek
Packmaß 28,9 Mio 1M

根据常规的操作思路,我们从以下几个方面考虑优化:

WEBPACK

sourceMap

Schließen Sie productionSourceMapin der Produktionsumgebung css sourceMap, da diese beiden Dinge die beiden Konfigurationen der zugeordneten Quelldatei sind, die für das Breakpoint-Debugging verwendet werden, sodass die Produktionsumgebung eine solche Zuordnung überhaupt nicht vornehmen muss.

    // vue.config.js
    const isProduction = process.env.NODE_ENV === 'production'
    // 判断是否是生产环境
    module.exports = {
        productionSourceMap: !isProduction, //关闭生产环境下的SourceMap映射文件
        css: {
            sourceMap: !isProduction, // css sourceMap 配置
            loaderOptions: {
                ...
            }
        },
        ...
    }
复制代码

webpack-bundle-analyzer

webpack-bundle-analyzerEs ist ein Artefakt-Plug-In für die Analyse von Webpack-Paketen. Nach der Installation des  webpack-bundle-analyzer Plug-Ins wird nach dem Packen ein lokaler Dienst erstellt, der die Einschlussbeziehung und Größe der gepackten Dateien klar zeigt, sodass wir nicht viel und direkt sprechennpm install webpack-bundle-analyzer -D


    // vue.config.js
    module.exports = {     
       chainWebpack: (config) => {
            // 分析打包大小
            if (process.env.npm_config_report) {
              config.plugin('webpack-bundle-analyzer')
                .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
                .end();
            }
       }
    }
    
    // package.json
    {
      "name": "name",
      "version": "0.0.1",
      "scripts": {
        "report": "set npm_config_report=true && vue-cli-service build",
      },
      ...
     }

复制代码

Führen Sie als Nächstes direkt npm run reportaus, und der Browser gibt beim Packen den folgenden Bericht über die Abhängigkeitspaketbeziehung aus:

Bild.png

Bild.png

Bild.pngÖffnen Sie den entsprechenden Dist und schauen Sie, mein Guter, die Dist-Datei ist 28,9 M, was wirklich ein bisschen groß ist. Ich habe das Wasser getrunken und war geschockt und habe weitergearbeitet.

Äußerlichkeiten

根据分析报告,直观的看到node_modules里面有几个比较大的包,我们处理一下,比如echarts、element-ui、lodash、mock等,而externals可以用来防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)

    // vue.config.js
    ....
    chainWebpack: (config) => {
        ....
        //忽略的打包文件
        config.externals({
          'vue': 'Vue',
          'vue-router': 'VueRouter',
          'vuex': 'Vuex',
          'axios': 'axios',
          'element-ui': 'ELEMENT',
          'echarts': 'echarts',
          'lodash': 'lodash',
          'mock': 'mock'
        });
        ....
    }
复制代码

拆包

一个入口app.js好几兆,这加载起来多费劲,怪不得刚才领导打开系统的时候那么慢

// vue.config.js
....
chainWebpack: (config) => {
    ...
    config.optimization && config.optimization.splitChunks({
        // 拆包配置 
        chunks: 'all', //三选一:"initial" 初始化,"all"(默认就是all),"async"(动态加载) 
        minSize: 30000, // 形成一个新代码块最小的体积,只有 >= minSize 的bundle会被拆分出来 30000
        maxSize: 0, //拆分之前最大的数值,默认为0,即不做限制
        minChunks: 1, //引入次数,如果为2 那么一个资源最少被引用两次才可以被拆分出来
        maxAsyncRequests: 5, // 按需加载的最大并行请求数
        maxInitialRequests: 3, // 一个入口最大并行请求数
        automaticNameDelimiter: '~', // 文件名的连接符
        name: true,
        cacheGroups: {
        // node_modules模块包
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'chunk-vendors',
          // name(module) {
          //   const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
          //   return `chunk.${packageName.replace('@', '')}`;
          // },
          chunks: 'all',
          priority: -10,
        },
        // UI库单独拆包
        elementUI: {
          name: 'chunk-elementUI',
          priority: 20, //  the weight needs to be larger than libs and app or it will be packaged into libs or app
          test: /[\\/]node_modules[\\/]_?element-ui(.*)/
        },
        // 共享模块
        common: {
          name: 'chunk-common',
          minChunks: 2,
          maxSize: 1024, //拆分之前最大的数值,默认为0,即不做限制
          priority: -20,
          reuseExistingChunk: true
        }
        }
    });
    ...
}
...
复制代码

压缩js和css

如果你使用的是 webpack v5 或更高版本,是开箱机带的功能,但是你的webpack是5以下或则希望自定义配置,那么需要安装 terser-webpack-plugin。如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本。

// vue.config.js
const TerserJSPlugin = require('terser-webpack-plugin');
....
chainWebpack: (config) => {
    // 开启js、css压缩
    config.plugin('TerserJSPlugin')
      .use(new TerserJSPlugin({
        terserOptions: {
          output: {
            comments: false // 去掉注释
          },
          warnings: false,
          compress: {
            // eslint-disable-next-line camelcase
            drop_console: true,
            // eslint-disable-next-line camelcase
            drop_debugger: true,
            // pure_funcs: ['console.log'] // 移除console
          }
        }
      }));
}
复制代码

开启Gzip压缩

// 打包压缩静态文件插件
const CompressionWebpackPlugin = require("compression-webpack-plugin")
...
module.exports = {
    ...
    chainWebpack: config => {
        //生产环境开启js/css压缩
        if (isProduction) {
            config.plugin('CompressionWebpackPlugin').use(new CompressionWebpackPlugin({
                test: /\.(js)$/, // 匹配文件名
                threshold: 10240, // 对超过10k的数据压缩
                minRatio: 0.8,
                deleteOriginalAssets: true // 删除源文件
            }))
        }
    }
    ...
}
复制代码

对用服务端Nginx配置

# nginx前端静态资源配置  // data/docker/nginx/conf.d 
server { 
    listen 8080; 
    server_name _;
    gzip_static on; // 开启gzip压缩
    client_max_body_size 500m; 
    root /data/****/web/dist; 
    index index.html; 
    location ^~ /api { 
        proxy_pass http://***.**.**.***:8080/; 
        proxy_set_header Host ***.**.**.***; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    } 
}


复制代码

CDN

对于项目用到的静态资源,比如图片,静态资源库,我们直接把文件给甩到CDN上

<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.10/vue.min.js" charset="utf-8"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vuex/3.1.1/vuex.min.js" charset="utf-8"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.0.1/vue-router.min.js" charset="utf-8"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.17.1/axios.min.js" charset="utf-8"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.3/index.min.js" charset="utf-8"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js" charset="utf-8"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js" charset="utf-8"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.1-beta3/mock-min.js" charset="utf-8"></script>
复制代码

按需加载

比如我们引用某一些第三方,使用少量功能,可以选择按需加载,举个例子: 比如引用lodash的时候,如果想要按需加载,可以考虑使用webpack-lodash-pluginbabel-plugin-lodash,按需加载可以节省近1M的空间大小

    // 使用前,需要手动引入指定的模块
    const isElement = require('lodash/isElement');
    const debounce = require('lodash/debounce');

    // 使用后,放心引入
    import { isElement, debounce } from 'lodash'
复制代码

缓存

Darüber hinaus können wir den Browser-Cache, den Server-Cache und den Redis-Cache verwenden, um die Reaktionsgeschwindigkeit unseres Systems zu beschleunigen. Wir können beispielsweise einen starken Cache oder Verhandlungs-Cache mit Back-End-Studenten verwenden, um Client-Anfragen vernünftig zwischenzuspeichern, aber das sollte es Beachten Sie Folgendes: Wenn der Server Webressourcen als Proxy verwendet, darf der html.index des Eintrags nicht zwischengespeichert werden, da jedes Mal, wenn der Eintrag aktualisiert wird, einige js und CSS, von denen dieser Eintrag abhängt, entsprechend dem Hash-Fingerabdruck geändert werden. Wenn ein Cache vorhanden ist, werden Benutzer jedes Mal veröffentlichen, wenn Sie den Browser-Cache löschen müssen, um die neuesten Inhalte zu laden

# nginx前端静态资源配置  // data/docker/nginx/conf.d 
server { 
    listen 8080; 
    server_name _;
    gzip_static on; // 开启gzip压缩
    client_max_body_size 500m; 
    root /data/****/web/dist; 
    index index.html; 
    location ^~ /api { 
        proxy_pass http://***.**.**.***:8080/; 
        proxy_set_header Host ***.**.**.***; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    } 
    location = /index.html {
        add_header Cache-Control "no-cache,no-store";
    }
}

复制代码

Epilog

Sehen wir uns den Vergleich vor und nach der Optimierung an

Optimierung Vor der Optimierung Optimiert
Oberhalb der Ladezeit 26s 2,5 Sek
Packmaß 28,9 Mio 1M

herunterladen.jpegDas ist der Sprung vom handgeführten Traktor zum Lamborghini, nimm das Wasserglas in die Hand und nimm einen Schluck, der Leistungsbonus dieses Monats sollte stabil sein☕️

Bild.png

Bild.png

Bild.png

Ich denke du magst

Origin juejin.im/post/7080066104613142559
Empfohlen
Rangfolge