国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

前端性能優化—js代碼打包

Rango / 938人閱讀

摘要:注意使用的版本不同,可能會導致打包出的結果不一樣。完整的優化代碼見有用的文章分離第三方庫及公用文件

現在的 web 應用,內容一般都很豐富,站點需要加載的資源也特別多,尤其要加載很多 js 文件。js 文件從服務端獲取,體積大小決定了傳輸的快慢;瀏覽器端拿到 js 文件之后,還需要經過解壓縮、解析、編譯、執行操作,所以,控制 js 代碼的體積以及按需加載對前端性能以及用戶體驗是十分的重要。

本文從 Tree Shaking代碼分割 兩部分介紹 js 打包優化,有興趣的可以跟著一起實踐。
clone 以下項目 https://github.com/jasonintju...,就是個簡單的 React SPA,一看就懂。

Tree Shaking

Tree Shaking 簡單理解就是:打包時把一些沒有用到的代碼刪除掉,保證打包后的代碼體積最小化。其詳細的介紹可以參考 Tree-Shaking性能優化實踐 - 原理篇。

項目 clone、安裝依賴后,先 npm run build 打包初始代碼,大小及分布如下(其中 src/utils/utils.js 這個文件打包后大小為11.72Kb):

src/containers/About/test.js只引用但是沒有使用到,src/utils/utils.js 這個文件是個工具函數集,有很多很多函數,而我們只用到了其中的一個。默認情況下,整個文件都被打包進 main.js 了,顯然,這是很大的冗余,正好可以使用 Tree Shaking 優化。

修改 .babelrc
{
  "presets": [["env", { "modules": false }], "react", "stage-0"]
}
修改 package.json
{
  "name": "optimizing-js",
  "version": "1.0.0",
  "sideEffects": false
}

這樣設置之后,表示所有的 module 都是無副作用的,沒有使用到的 module 都可以刪掉,此時打包結果如下:

import React from "react";
// 只引入了 arraySum, utils.js 中的其他方法不會被打包
import { arraySum } from "@utils/utils";
import "./test"; // 引用,“未使用”,不會被打包
import "./About.scss"; // 引用,“未使用”,不會被打包

class About extends React.Component {
  render() {
    const sum = arraySum([12, 3]);
    return (
      

About Page

12 plus 3 equals {sum}
); } } export default About;

如上面注釋所說,Tree Shaking 認為這些是沒有被使用的代碼,所以可以刪掉。但事實上我們知道不是這樣的,test.js 可以刪掉,但是 css、scss 是有用的代碼,我們只需引入即可。因此,需要修改一下 sideEffects 的值:

{
  "sideEffects": [
    "*.css", "*.scss", "*.sass"
  ]
}

表示,除了[]中的文件(類型),其他文件都是無副作用的,可以放心刪掉。此時打包結果:

可以看到,css 等樣式文件現在如期打包進去了。如果有其他類型的文件有副作用,但是也希望打包進去,在 sideEffects: [] 中添加即可,可以是具體的某個文件或者某種文件類型。

關于為什么修改這兩個地方就可以實現 Tree Shaking 的效果了,可以參考一下https://developers.google.com... 或者其他文章,這里不做詳細解釋了。

代碼分割

單頁應用,如果所有的資源都打包在一個 js 里面,毫無疑問,體積會非常龐大,首屏加載會有很長時間白屏,用戶體驗極差。所以,要代碼分割,分成一個一個小的 js,優化加載時間。

分離第三方庫代碼

第三方庫代碼多帶帶提取出來,和業務代碼分離,減少 js 文件體積。在 webpack.base.conf.js 中增加:

module: {...},
optimization: {
  splitChunks: {
    cacheGroups: {
      venders: {
        test: /node_modules/,
        name: "vendors",
        chunks: "all"
      }
    }
  }
},
plugins: ...

動態導入

使用 ECMAScript 提案 的 dynamic import 語法可以異步加載業務中的組件。使用方法如下:

// src/containers/App/App.js

// 注釋掉此行代碼
// import About from "@containers/About/About";

// 修改模塊為動態導入形式
 import(/* webpackChunkName: "about" */ "@containers/About/About").then(module => module.default)}/>

此時打包結果:

能看到, 組件已經被 webpack 多帶帶打包出對應的 js 文件了。同時,結合 react-router,分離 組件的同時也做到了按需加載:當訪問 About 頁面時,about.js 才會被瀏覽器加載。

注意,我們現在只是簡單地使用了 dynamic import,很多邊界情況沒考慮進去,比如:加載進度、加載失敗、超時等處理。可以開發一個高階組件,把這些異常處理都包含進去。社區有個很棒的 react-loadable,大樹底下好乘涼~

npm i react-loadable

// src/containers/App/App.js
import Loadable from "react-loadable";

// 代碼分割 & 異步加載
const LoadableAbout = Loadable({
  loader: () => import(/* webpackChunkName: "about" */ "@containers/About/About"),
  loading() {
    return 
Loading...
; } }); class App extends React.Component { render() { return (
); } }

react-loadable 還提供了 preload 功能。假如有統計數據顯示,用戶在進入首頁之后大概率會進入 About 頁面,那我們就在首頁加載完成的時候去加載 about.js,這樣等用戶跳到 About 頁面的時候,js 資源都已經加載好了,用戶體驗會更好。

// src/containers/App/App.js
componentDidMount() {
  LoadableAbout.preload();
}

如果有同學對Network面板不是很熟悉,可以看一下 Chrome DevTools — Network。

提取復用的業務代碼

第三方庫代碼已經多帶帶提取出來了,但是業務代碼中也會有一些復用的代碼,典型的比如一些工具函數庫 utils.js。現在,About 組件Docs 組件都引用了 utils.js,webpack 只打包了一份 utils.jsmain.js 里面,main.js 在首頁就被加載了,其他頁面有使用到 utils.js 自然可以正常引用到,符合我們的預期。但是目前我們只是把 About 頁面異步加載了,如果把 Docs 頁面也異步加載了會怎么樣呢?

// src/containers/App/App.js
// 注釋掉此行代碼
// import Docs from "@containers/Docs/Docs";

const LoadableDocs = Loadable({
  loader: () => import(/* webpackChunkName: "docs" */ "@containers/Docs/Docs"),
  loading() {
    return 
Loading...
; } }); class App extends React.Component { render() { return (
); } }

此時打包結果:

能夠看到,about.js 和 docs.js 里面都打包了 utils.js,重復了!
webpack.base.conf.js 中增加:

module: {...},
optimization: {
  splitChunks: {
    cacheGroups: {
      venders: {
        test: /node_modules/,
        name: "vendors",
        chunks: "all"
      },
      default: {
        minSize: 0,
        minChunks: 2,
        reuseExistingChunk: true,
        name: "utils"
      }
    }
  }
},
plugins: ...

再打包看結果:

utils.js 也被多帶帶打包出來了,達到了預期。

分離非首頁使用且復用程度小的第三方庫

假如,現在 Docs.js 引用了 lodash 這個三方庫:

import React from "react";
import _ from "lodash";
import { arraySum } from "@utils/utils";
import "./Docs.scss";

class Docs extends React.Component {
  render() {
    const sum = arraySum([1, 3]);
    const b = _.sum([1, 3]);
    return (
      

Docs Page

1 plus 3 equals {sum}

use _.sum, 1 plus 3 equals {b} too.
); } } export default Docs;

打包結果:

lodash.js 只在 Docs 頁面使用,而且可能 Docs 頁面訪問量很少,把 lodash.js 打包在首頁就會加載的 venders.js 里面,實在不是明智之舉。

修改 webpack.base.conf.js

...
venders: {
  test: /node_modules/(?!(lodash)/)/, // 去除 lodash,剩余的第三方庫打成一個包,命名為 vendors-common
  name: "vendors-common",
  chunks: "all"
},
lodash: {
  test: /node_modules/lodash//, // lodash 庫多帶帶打包,并命名為 vender-lodash
  name: "vender-lodash"
},
default: {
  minSize: 0,
  minChunks: 2,
  reuseExistingChunk: true,
  name: "utils"
}
...

此時把 lodash 多帶帶打成了一個包,且配合 Docs 頁面的按需加載,達到了理想的加載效果。

緩存

項目打包后,資源部署在服務器端,客戶端需要向服務器請求下載這些資源,用戶才能看到內容。使用緩存,客戶端可以大大減少不必要的請求和時間耽擱,只有當資源有更新時,再去下載。區分一個文件是否有更新,使用 文件名 + hash 可以達到目的。本案例中,已經使用了 "[name].[contenthash:8].js"

然而,在打包的時候,webpack的運行時代碼有時候會導致某些情況出現,如:什么內容都沒改,兩次 build 代碼的 hash 不一樣;或者是,修改了 a 文件的代碼,卻導致了某些未修改代碼文件的 hash 也發生了變化。This is caused by the injection of the runtime and manifest which changes every build.

注意:使用的 webpack 版本不同,可能會導致打包出的結果不一樣。較新的版本或許沒有這種 hash 問題,但為了安全起見,還是建議按照下面的步驟處理一下。
分離 webpack runtimeChunk code
// webpack.base.conf.js
optimization: {
  runtimeChunk: {
    name: "manifest"
  },
  splitChunks: {...}
}

此時,能達到:修改某個文件,只有這個文件和 manifest.js 文件的 hash 會發生變化,其他文件的 hash 不變。
打包前:

// About.scss
.page-about {
  padding-left: 30px;
  color: #545880; // 修改字體顏色
}

修改后:

HashedModuleIdsPlugin

增加、刪除一些模塊,可能會導致不相關文件的 hash 發生變化,這是因為 webpack 打包時,按照導入模塊的順序,module.id 自增,會導致某些模塊的 module.id 發生變化,進而導致文件的 hash 變化。

解決方式: 使用 webpack 內置的 HashedModuleIdsPlugin,該插件基于導入模塊的相對路徑生成相應的 module.id,這樣如果內容沒有變化加上 module.id 也沒變化,則生成的 hash 也就不會變化了。

// webpack.prod.conf.js
const webpack = require("webpack");
...
plugins: [new webpack.HashedModuleIdsPlugin(), new BundleAnalyzerPlugin()]

完整的優化代碼見 https://github.com/jasonintju...

有用的文章:
webpack分離第三方庫及公用文件
https://developers.google.com...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97611.html

相關文章

  • 前端進階(14) - 如何提升前端性能和響應速度

    摘要:一般建議文件最大不超過。按需加載可以減小首屏加載文件的體積,達到提高響應速度的目的。如果你的項目不需要處理靜態資源如圖片,也不需要按需加載,并追求前端高性能的話,可以嘗試。 如何提升前端性能和響應速度 下面大多是從前端工程化的角度給出的優化建議,如果需要了解語法上的優化,可以參考: 如何提高頁面加載速度 編寫高效的JavaScript Web前端性能優化進階 - 完結篇 1. 原生...

    lylwyy2016 評論0 收藏0
  • 前端進階(14) - 如何提升前端性能和響應速度

    摘要:一般建議文件最大不超過。按需加載可以減小首屏加載文件的體積,達到提高響應速度的目的。如果你的項目不需要處理靜態資源如圖片,也不需要按需加載,并追求前端高性能的話,可以嘗試。 如何提升前端性能和響應速度 下面大多是從前端工程化的角度給出的優化建議,如果需要了解語法上的優化,可以參考: 如何提高頁面加載速度 編寫高效的JavaScript Web前端性能優化進階 - 完結篇 1. 原生...

    Airy 評論0 收藏0
  • 如何構建前端代碼

    摘要:首先散文件是有害處的,第一是,散文件可能沒有版本號的區分,這樣因為緩存導致第二是散文件會嚴重拖慢性能,因為很多散文件不僅消耗請求資源,而且是在串行消耗。 基本認識 開發環境和線上環境的區別 在很久以前,前端的部署其實比較簡單,開發環境下,靜態資源往服務器上面一扔就ok了,如果考慮下優化或者代碼保護,也只是加一個代碼壓縮和混淆。沒錯,剛入行的時候我就是這么干的。。。 但是隨著前...

    jhhfft 評論0 收藏0
  • 前端進階(9) - js 性能優化利器:prepack

    摘要:性能優化利器性能優化性能優化不外乎從三個角度入手開發者在編寫程序時,盡量避免不必要的冗余代碼,包括冗余的第三方庫首先要避免不必要的冗余代碼,包括不必要的閉包不必要的變量與函數聲明不必要的模塊分割等。 js 性能優化利器:prepack 1. js 性能優化 js 性能優化不外乎從三個角度入手: 1.1 開發者在編寫程序時,盡量避免不必要的冗余代碼,包括冗余的第三方庫 首先要避免不必要的...

    JouyPub 評論0 收藏0
  • 前端構建】WebPack實例與前端性能優化

    摘要:感受構建工具給前端優化工作帶來的便利。多多益處邏輯清晰,程序注重數據與表現分離,可讀性強,利于規避和排查問題構建工具層出不窮。其實工具都能滿足需求,關鍵是看怎么用,工具的使用背后是對前端性能優化的理解程度。 這篇主要介紹一下我在玩Webpack過程中的心得。通過實例介紹WebPack的安裝,插件使用及加載策略。感受構建工具給前端優化工作帶來的便利。 showImg(https://se...

    QiShare 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<