<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          記一次 Nuxt.js 登錄頁性能優(yōu)化(性能提升十倍加)

          共 5290字,需瀏覽 11分鐘

           ·

          2020-11-04 10:14

          Nuxt.js 登錄頁性能優(yōu)化

          "color:rgb(255,255,255);">前言

          最近有測試和 local 投訴,我們管理系統(tǒng)的登錄頁面經(jīng)常加載很久,常常會(huì)有頁面已經(jīng)出來了,但是點(diǎn)擊登錄毫無反應(yīng),直到全部加載后才能登錄。于是,他們提出讓我們?nèi)?yōu)化。

          這是一個(gè)好問題,登錄頁雖然不是移動(dòng)端那種首頁,但也是最先呈現(xiàn)給內(nèi)部用戶的。

          "color:rgb(255,255,255);">定位耗時(shí)

          遇到這種問題,首先需要找出耗時(shí)都花在了哪里,然后再去想具體辦法去解決。

          首先,打開登錄頁面控制面板,Disable Cache 之后查看一下每個(gè)資源的耗時(shí)。

          a1a5a0ff9676677d765695b105b8efa3.webp

          從圖上可以明顯看出來,有一個(gè) 2.2m 的文件足足耗時(shí)5s之久,文件的耗時(shí)主要在下載上面,看來主要的性能瓶頸就在這里了。

          由于 JS 文件在騰訊云 CDN 上面配置了協(xié)商緩存(etag),所以在第二次加載的時(shí)候速度提升非常大,基本上不到 1s 就可以加載出來了。

          7187b4c96f6dfc9a5f0e83ec46f48e46.webp

          image

          那么這個(gè)大文件是什么文件呢?

          我去 Jenkins 上看一下構(gòu)建記錄,在 build 的時(shí)候看到這個(gè)文件就是基于第三方包打出來的 vendors 文件。

          e7ff69fa652b156871576e4733be4e53.webp

          image

          "color:rgb(255,255,255);">webpack4 splitChunks

          既然知道這個(gè)是 vendors 文件了,那就來分析一下 webpack 構(gòu)建。

          在 webpack4 里面出現(xiàn)了 splitChunk 來拆分 chunk 文件,webpack4 會(huì)有一個(gè)默認(rèn)的 vendors chunk,它會(huì)把 node_modules 都給打成一個(gè)包,類似于:

          optimization:?{
          ????"color:#d19a66;">splitChunks:?{
          ??????"color:#d19a66;">chunks:?"color:#98c379;">'initial',
          ??????"color:#d19a66;">cacheGroups:?{
          ????????"color:#d19a66;">vendors:?{****
          ??????????test:?"color:#98c379;">/[\\/]node_modules[\\/]/,
          ??????????"color:#d19a66;">priority:?"color:#d19a66;">-10
          ????????}
          ??????}
          ????}
          ??}

          只不過,Nuxt 在這個(gè)基礎(chǔ)上又拆分出了一個(gè) commons ,配置規(guī)則如下:

          optimization.splitChunks.cacheGroups.commons?=?{
          ??"color:#d19a66;">test:?"color:#98c379;">/node_modules[\\/](vue|vue-loader|vue-router|vuex|vue-meta|core-js|@babel\/runtime|axios|webpack|setimmediate|timers-browserify|process|regenerator-runtime|cookie|js-cookie|is-buffer|dotprop|nuxt\.js)[\\/]/,
          ??"color:#d19a66;">chunks:?"color:#98c379;">'all',
          ??"color:#d19a66;">priority:?"color:#d19a66;">10,
          ??"color:#d19a66;">name:?"color:#56b6c2;">true
          }

          priority 代表優(yōu)先級,如果兩個(gè) cacheGroups 里面都引用了同一個(gè)庫,那么就根據(jù)優(yōu)先級來判斷優(yōu)先把這個(gè)庫打進(jìn)哪個(gè) chunk 里面。

          很明顯 commons 的優(yōu)先級要高于 vendors,所以會(huì)把 test 規(guī)則匹配到的第三方包優(yōu)先拆分出來,這幾個(gè)主要是 Nuxt 中依賴的一些庫。

          本地執(zhí)行了一次 analyze 后,得到的構(gòu)建圖是這樣的,可以看出來 vendors 明顯遠(yuǎn)比其他的包都要大,尤其是 xlsx、iview、moment、lodash 這幾個(gè)庫,幾乎占了一大半體積。

          d970055ed45da75937b27e4c9bd227cb.webp

          image

          "color:rgb(255,255,255);">優(yōu)化

          生成多 HTML

          既然知道 vendors 包里面都是一些第三方庫了,那么是否可以只打出登錄頁依賴的第三方庫,然后只去加載這個(gè) chunk 文件呢?

          我看了一下登錄頁邏輯很簡單,不需要 lodash、moment,甚至連 iview 都不需要,完全可以自己去實(shí)現(xiàn)樣式,這樣就不必去加載體積這么大的 vendors chunk 了。

          真是個(gè)好主意,可是問題來了,怎么才能不去加載 vendors 呢?

          如果是在 webpack 里面,這個(gè)很容易,我們可以通過 html-webpack-plugin 來加載多個(gè) HTML 文件,針對登錄頁生成一個(gè) HTML 文件,讓它只去加載自身依賴的 chunk 文件。

          于是我去看了一下 Nuxt 源碼,發(fā)現(xiàn)這里還是暴露了配置給我們?nèi)ザx一個(gè)新的 HTML 模板的。

          當(dāng)然,到最后我也沒去嘗試這種方法,只是覺得應(yīng)該可以實(shí)現(xiàn)。

          bc076204871cb445aa180edb9fd8e18a.webp

          image

          從 HTML 模板中刪除

          Nuxt 會(huì)暴露給我們一個(gè) app.html 模板文件,它會(huì)在服務(wù)端渲染出來數(shù)據(jù),最后替換到這個(gè)文件里面。


          <"color:#e06c75;">html?{{?HTML_ATTRS?}}>
          ??<"color:#e06c75;">head?{{?HEAD_ATTRS?}}>
          ????{{?HEAD?}}
          ??head>
          ??<"color:#e06c75;">body?{{?BODY_ATTRS?}}>
          ????{{?APP?}}
          ??body>
          html>

          那么我們有沒有可能在 Nuxt 替換這些占位符之前先去除掉不需要加載的 chunk 文件呢?其實(shí)也是可以的,只是需要修改到 Nuxt 的源碼。

          修改了源碼之后,還需要用 patch-package 去打一個(gè)補(bǔ)丁,這樣就可以做到修改 node_modules 里面的代碼。

          打開項(xiàng)目的 node_modules 文件夾,找到 @nuxt/vue-renderer/dist/vue-renderer.js,在 SSRRenderer 這個(gè)類里面的 render 方法中,我們可以看到如下代碼:

          c8ddbf1d546da2081aa75fc698bc9166.webpimage

          m.script.text({ body: true }) 這句代碼拿到的就是最后頁面上渲染出來的 script 標(biāo)簽,如果在這里匹配到 vendors 包,把它給排除掉,之后在頁面上就不會(huì)加載這個(gè) JS 文件了。

          我這里的方案是這樣的,首先把登錄頁不需要且體積很大的幾個(gè)包(iview、moment、lodash)給單獨(dú)打了一個(gè) my-vendors 的包。

          在 Nuxt 源碼中用正則表達(dá)式去匹配這個(gè)文件名,然后手動(dòng) replace 掉(記得要把 link 標(biāo)簽里面預(yù)加載的也一起替換掉)

          "color:#5c6370;font-style:italic;">//?nuxt.config.js
          config.optimization.splitChunks.cacheGroups.myVendors?=?{
          ??????????"color:#d19a66;">test:?"color:#98c379;">/node_modules[\\/](view-design|moment|moment-timezone|dayjs|crypto-js|simple-uploader\.js|vue2-google-maps|vuex-class|axios)[\\/]/,
          ??????????"color:#5c6370;font-style:italic;">//?cacheGroupKey?here?is?`commons`?as?the?key?of?the?cacheGroup
          ??????????automaticNamePrefix:?"color:#98c379;">'my-vendors',?"color:#5c6370;font-style:italic;">//?文件名以?my-vendors?為前綴
          ??????????name:?"color:#56b6c2;">true,
          ??????????"color:#d19a66;">chunks:?"color:#98c379;">'all',
          ??????????"color:#d19a66;">priority:?"color:#d19a66;">10
          ??????????reuseExistingChunk:?"color:#56b6c2;">true
          }

          "color:#5c6370;font-style:italic;">//?vue-renderer.js
          "color:#c678dd;">const?scripts?=?APP.match("color:#98c379;">/(\
          ??????
          ??????
          ????????

          ????????
          ??????????
          ????????????
          ??????????????
          ??????????????????????????????????slot="title"
          ??????????????????style="text-transform:?capitalize;?color:?#595d65;?font-size:?16px;?display:?flex;?height:?25px;"
          ????????????????>
          ??????????????????${
          ????????????????????config.cdnServer.staticUrl
          ??????????????????}/static/admin-website/logo.png"?alt="logo"?class="login-logo"?/>
          ????????????????


          ??????????????

          ??????????????
          ????????????????
          ??????????????????

          ??????????????????
          ????????????????

          ??????????????
          ????????????
          ??????????
          ????????
          ????????
          ????????
          ??????
          ????
          ??`
          }

          然后,在 /login 路由下面引入這個(gè)模塊,傳入必要的配置后直接輸出,記得設(shè)置 Content-Typetext/html。

          "color:#5c6370;font-style:italic;">//?login/index.ts
          "color:#e6c07b;">module.exports?=?"color:#c678dd;">function(
          ??fastify:?Fastify.FastifyInstance,
          ??opts:?Fastify.RouteShorthandOptions,
          ??next:?Function
          )?{
          ??fastify.get("color:#98c379;">'/login',?"color:#c678dd;">async?(request,?reply)?=>?{
          ????reply
          ??????.code("color:#d19a66;">200)
          ??????.header("color:#98c379;">'Content-Type',?"color:#98c379;">'text/html;?charset=utf-8')
          ??????.send(login(Config))
          ??})
          ??next()
          }

          "color:#5c6370;font-style:italic;">//?server/index.ts
          fastify.register("color:#e6c07b;">require("color:#98c379;">'./routes/login'),?{?"color:#d19a66;">prefix:?"color:#98c379;">'/'?})

          最后優(yōu)化的效果也是非常明顯的,不使用緩存的情況下耗時(shí)只有幾百毫秒。

          91a2e898662967e914a4976df8d7a8b5.webp

          image

          在開啟了緩存之后,幾乎是秒開,耗時(shí)只有短短 100ms,可以說性能得到了幾十倍的提升。

          a86eb5ff95f8d2dfe16d9374bc071b22.webp

          image

          "color:rgb(255,255,255);">總結(jié)

          很多時(shí)候我們總會(huì)抱怨現(xiàn)在的工作都是重復(fù)勞動(dòng),找不到可以提升自己的地方。

          但如果用心去找,還是能發(fā)現(xiàn)團(tuán)隊(duì)開發(fā)中的不少痛點(diǎn)的,自己在解決這些痛點(diǎn)的時(shí)候也能學(xué)習(xí)到很多新知識。

          "padding-left:10px;font-size:18px;color:rgb(89,89,89);">??愛心三連擊

          1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的「"color:rgb(255,0,0);">點(diǎn)贊,"color:rgb(255,0,0);">在看是我創(chuàng)作的動(dòng)力。

          2.關(guān)注公眾號程序員成長指北,回復(fù)「1」加入Node進(jìn)階交流群!「在這里有好多 Node 開發(fā)者,會(huì)討論 Node 知識,互相學(xué)習(xí)」!

          3.也可添加微信【ikoala520】,一起成長。


          "background-color:rgb(255,202,0);color:rgb(255,255,255);">“在看轉(zhuǎn)發(fā)”是最大的支持

          瀏覽 41
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色婷婷无码在线 | 日韩无码免费播放 | 99在线免费观看视频 | 日本AⅤ中文字幕 | 老司机日比视频 |