gzip की मदद से नेटवर्क पेलोड कम करें और कंप्रेस करें

इस कोडलैब में बताया गया है कि नीचे दिए गए ऐप्लिकेशन के लिए, JavaScript बंडल को छोटा और कंप्रेस करने से, ऐप्लिकेशन के अनुरोध के साइज़ को कम करके, पेज की परफ़ॉर्मेंस कैसे बेहतर होती है.

ऐप्लिकेशन का स्क्रीनशॉट

मापें

ऑप्टिमाइज़ेशन जोड़ने से पहले, ऐप्लिकेशन की मौजूदा स्थिति का विश्लेषण करना हमेशा अच्छा होता है.

  • साइट की झलक देखने के लिए, ऐप्लिकेशन देखें दबाएं. इसके बाद, फ़ुलस्क्रीन फ़ुलस्क्रीन दबाएं.

इस ऐप्लिकेशन में, अपनी पसंदीदा बिल्ली के लिए वोट किया जा सकता है. इस ऐप्लिकेशन के बारे में "इस्तेमाल न किए गए कोड को हटाएं" कोडलैब में भी बताया गया है. 🐈

अब देखें कि यह ऐप्लिकेशन कितना बड़ा है:

  1. DevTools खोलने के लिए, `Control+Shift+J` दबाएं. Mac पर, `Command+Option+J` दबाएं.
  2. नेटवर्क टैब पर क्लिक करें.
  3. कैश मेमोरी की सुविधा बंद करें चेकबॉक्स को चुनें.
  4. ऐप्लिकेशन को फिर से लोड करें.

नेटवर्क पैनल में मूल बंडल का साइज़

इस बंडल के साइज़ को कम करने के लिए, "इस्तेमाल न किए जा रहे कोड को हटाएं" कोडलैब में काफ़ी काम किया गया है. हालांकि, 225 केबी अब भी काफ़ी ज़्यादा है.

छोटा करना

यहां दिया गया कोड ब्लॉक देखें.

function soNice() {
  let counter = 0;

  while (counter < 100) {
    console.log('nice');
    counter++;
  }
}

अगर इस फ़ंक्शन को अपनी फ़ाइल में सेव किया जाता है, तो फ़ाइल का साइज़ करीब 112 बी (बाइट) होता है.

सभी खाली जगह हटाने पर, कोड कुछ ऐसा दिखेगा:

function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}

अब फ़ाइल का साइज़ करीब 83 बी होगा. अगर वैरिएबल के नाम की लंबाई कम करके और कुछ एक्सप्रेशन में बदलाव करके, इसे और भी खराब कर दिया जाता है, तो आखिरी कोड ऐसा दिख सकता है:

function soNice(){for(let i=0;i<100;)console.log("nice"),i++}

अब फ़ाइल का साइज़ 62 बाइट हो गया है.

हर चरण के साथ, कोड को पढ़ना मुश्किल हो रहा है. हालांकि, ब्राउज़र का JavaScript इंजन इन सभी को एक ही तरह से समझता है. इस तरह से कोड को बदलने का फ़ायदा यह है कि इससे फ़ाइल का साइज़ कम हो जाता है. 112 बी का साइज़ पहले से ही कम था, लेकिन फिर भी साइज़ में 50% की कमी आई!

इस ऐप्लिकेशन में, webpack के वर्शन 4 का इस्तेमाल मॉड्यूल बंडलर के तौर पर किया गया है. खास वर्शन को package.json में देखा जा सकता है.

"devDependencies": {
  //...
  "webpack": "^4.16.4",
  //...
}

वर्शन 4, प्रोडक्शन मोड के दौरान बंडल को डिफ़ॉल्ट रूप से छोटा कर देता है. यह TerserWebpackPluginTerser के लिए प्लग इन का इस्तेमाल करता है. Terser एक लोकप्रिय टूल है, जिसका इस्तेमाल JavaScript कोड को कंप्रेस करने के लिए किया जाता है.

छोटा किया गया कोड कैसा दिखता है, यह जानने के लिए DevTools के नेटवर्क पैनल में जाकर, main.bundle.js पर क्लिक करें. अब जवाब टैब पर क्लिक करें.

छोटा किया गया जवाब

कोड को छोटा करके और बदलाव करके, उसके आखिरी फ़ॉर्म में जवाब के मुख्य हिस्से में दिखाया जाता है. अगर बंडल को छोटा नहीं किया गया होता, तो यह कितना बड़ा होता, यह जानने के लिए webpack.config.js खोलें और mode कॉन्फ़िगरेशन को अपडेट करें.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

ऐप्लिकेशन को फिर से लोड करें और DevTools के नेटवर्क पैनल की मदद से, बंडल के साइज़ को फिर से देखें

बंडल का साइज़ 767 केबी होना चाहिए

इसमें काफ़ी फ़र्क़ है! 😅

आगे बढ़ने से पहले, यहां किए गए बदलावों को पहले जैसा करें.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

अपने ऐप्लिकेशन में कोड को छोटा करने की प्रोसेस शामिल करना, इस्तेमाल किए जाने वाले टूल पर निर्भर करता है:

  • अगर webpack v4 या इसके बाद के वर्शन का इस्तेमाल किया जाता है, तो आपको कुछ और करने की ज़रूरत नहीं है, क्योंकि प्रोडक्शन मोड में कोड डिफ़ॉल्ट रूप से छोटा हो जाता है. 👍
  • अगर webpack के पुराने वर्शन का इस्तेमाल किया जाता है, तो TerserWebpackPlugin को webpack की बिल्ड प्रोसेस में शामिल करें और इंस्टॉल करें. दस्तावेज़ में इस बारे में ज़्यादा जानकारी दी गई है.
  • छोटा करने वाले अन्य प्लग इन भी मौजूद हैं और इनका इस्तेमाल किया जा सकता है. जैसे, BabelMinifyWebpackPlugin और ClosureCompilerPlugin.
  • अगर किसी मॉड्यूल बंडलर का इस्तेमाल नहीं किया जा रहा है, तो Terser को सीएलआई टूल के तौर पर इस्तेमाल करें या इसे सीधे तौर पर डिपेंडेंसी के तौर पर शामिल करें.

संपीड़न

"कंप्रेशन" शब्द का इस्तेमाल कभी-कभी, छोटा करने की प्रोसेस के दौरान कोड को छोटा करने के तरीके के बारे में बताने के लिए किया जाता है. हालांकि, असल में इसे कंप्रेशन नहीं कहा जा सकता.

आम तौर पर, कंप्रेस का मतलब ऐसे कोड से होता है जिसमें डेटा को कम करने वाले एल्गोरिदम का इस्तेमाल करके बदलाव किया गया हो. छोटा करने की प्रोसेस के बाद, पूरी तरह से मान्य कोड मिलता है. वहीं, इस्तेमाल करने से पहले, संपीड़ित कोड को डिकंप्रेस करना पड़ता है.

हर एचटीटीपी अनुरोध और रिस्पॉन्स के साथ, ब्राउज़र और वेब सर्वर हेडर जोड़ सकते हैं. इससे, फ़ेच की जा रही या मिलने वाली ऐसेट के बारे में ज़्यादा जानकारी शामिल की जा सकती है. इसे DevTools के नेटवर्क पैनल में Headers टैब में देखा जा सकता है. यहां तीन तरह के रीडायरेक्ट दिखते हैं:

  • सामान्य, अनुरोध-रिस्पॉन्स इंटरैक्शन से जुड़े सामान्य हेडर दिखाता है.
  • रिस्पॉन्स हेडर, सर्वर से मिले असल रिस्पॉन्स के हिसाब से हेडर की सूची दिखाता है.
  • अनुरोध हेडर, क्लाइंट के अनुरोध से जुड़े हेडर की सूची दिखाता है.

Request Headers में accept-encoding हेडर पर एक नज़र डालें.

Accept-Encoding हेडर

ब्राउज़र, accept-encoding का इस्तेमाल यह बताने के लिए करता है कि वह कॉन्टेंट को किस तरह से एन्कोड करता है या कॉम्प्रेस करने के लिए किस एल्गोरिदम का इस्तेमाल करता है. टेक्स्ट को कम करने वाले कई एल्गोरिदम मौजूद हैं. हालांकि, एचटीटीपी नेटवर्क अनुरोधों को कम करने (और बढ़ाने) के लिए, यहां सिर्फ़ तीन एल्गोरिदम काम करते हैं:

  • Gzip (gzip): सर्वर और क्लाइंट इंटरैक्शन के लिए, सबसे ज़्यादा इस्तेमाल किया जाने वाला कंप्रेसिव फ़ॉर्मैट. यह Deflate एल्गोरिदम पर आधारित है और सभी मौजूदा ब्राउज़र पर काम करता है.
  • Deflate (deflate): आम तौर पर इसका इस्तेमाल नहीं किया जाता.
  • Brotli (br): यह कंप्रेस करने का एक नया एल्गोरिदम है. इसका मकसद, कंप्रेस करने के अनुपात को और बेहतर बनाना है. इससे पेज तेज़ी से लोड हो सकता है. यह सुविधा, ज़्यादातर ब्राउज़र के नए वर्शन पर काम करती है.

इस ट्यूटोरियल में दिया गया सैंपल ऐप्लिकेशन, "इस्तेमाल न किए गए कोड को हटाएं" कोडलैब में बनाए गए ऐप्लिकेशन जैसा ही है. हालांकि, अब Express का इस्तेमाल सर्वर फ़्रेमवर्क के तौर पर किया जाता है. अगले कुछ सेक्शन में, स्टैटिक और डाइनैमिक, दोनों तरह के कंप्रेसन के बारे में बताया गया है.

डाइनैमिक कंप्रेशन

डाइनैमिक कंप्रेसन में, ब्राउज़र से ऐसेट का अनुरोध मिलने पर, उन्हें फ़्लाइट पर कंप्रेस किया जाता है.

फ़ायदे

  • ऐसेट के सेव किए गए और कंप्रेस किए गए वर्शन बनाने और अपडेट करने की ज़रूरत नहीं है.
  • फ़्लाइट के दौरान कॉम्प्रेस करने की सुविधा, खास तौर पर उन वेब पेजों के लिए बेहतर काम करती है जो डाइनैमिक तौर पर जनरेट होते हैं.

नुकसान

  • बेहतर कंप्रेसन रेशियो पाने के लिए, फ़ाइलों को ज़्यादा लेवल पर कंप्रेस करने में ज़्यादा समय लगता है. इससे परफ़ॉर्मेंस पर असर पड़ सकता है, क्योंकि उपयोगकर्ता को एसेट के भेजे जाने से पहले, उनके कंप्रेस होने का इंतज़ार करना पड़ता है.

Node/Express की मदद से डाइनैमिक कंप्रेसन

server.js फ़ाइल, ऐप्लिकेशन को होस्ट करने वाले नोड सर्वर को सेट अप करने के लिए ज़िम्मेदार होती है.

const express = require('express');

const app = express();

app.use(express.static('public'));

const listener = app.listen(process.env.PORT, function() {
  console.log('Your app is listening on port ' + listener.address().port);
});

फ़िलहाल, यह सिर्फ़ express को इंपोर्ट करता है और express.static डायरेक्ट्री में सभी स्टैटिक एचटीएमएल, JS, और सीएसएस फ़ाइलों को लोड करने के लिए, express.static मध्यवर्गीय प्रोसेस का इस्तेमाल करता है. ये फ़ाइलें, हर बिल्ड के साथ वेबपैक बनाता है.public/

यह पक्का करने के लिए कि हर बार अनुरोध करने पर सभी ऐसेट को कंप्रेस किया जाए, कंप्रेस मिडलवेयर लाइब्रेरी का इस्तेमाल किया जा सकता है. package.json में इसे devDependency के तौर पर जोड़कर शुरुआत करें:

"devDependencies": {
  //...
  "compression": "^1.7.3"
},

और इसे सर्वर फ़ाइल, server.js में इंपोर्ट करें:

const express = require('express');
const compression = require('compression');

साथ ही, इसे express.static के माउंट होने से पहले मिडलवेयर के तौर पर जोड़ें:

//...

const app = express();

app.use(compression());

app.use(express.static('public'));

//...

अब ऐप्लिकेशन को फिर से लोड करें और नेटवर्क पैनल में बंडल का साइज़ देखें.

डाइनैमिक कंप्रेसन की सुविधा के साथ बंडल का साइज़

225 केबी से 61.6 केबी! अब Response Headers में, content-encoding हेडर से पता चलता है कि सर्वर, gzip से कोड की गई इस फ़ाइल को भेज रहा है.

कॉन्टेंट को एन्कोड करने वाला हेडर

स्टैटिक कंप्रेसन

स्टैटिक कंप्रेस करने का मकसद, एसेट को पहले से कंप्रेस करके सेव करना है.

फ़ायदे

  • अब वीडियो को ज़्यादा कंप्रेस करने की वजह से, इंतज़ार का समय ज़्यादा नहीं होता. फ़ाइलों को कंप्रेस करने के लिए, अब उन्हें फ़्लाइट में कुछ भी करने की ज़रूरत नहीं है, क्योंकि उन्हें अब सीधे फ़ेच किया जा सकता है.

नुकसान

  • हर बिल्ड के साथ एसेट को कंप्रेस करना ज़रूरी है. ज़्यादा कंप्रेस करने पर, बिल्ड होने में लगने वाला समय काफ़ी बढ़ सकता है.

Node/Express और webpack की मदद से स्टैटिक कंप्रेसन

स्टैटिक कंप्रेसन में, फ़ाइलों को पहले से कंप्रेस करना शामिल होता है. इसलिए, वेबपैक की सेटिंग में बदलाव करके, एसेट को बिल्ड करने के दौरान कंप्रेस किया जा सकता है. इसके लिए, CompressionPlugin का इस्तेमाल किया जा सकता है.

package.json में इसे devDependency के तौर पर जोड़कर शुरुआत करें:

"devDependencies": {
  //...
  "compression-webpack-plugin": "^1.1.11"
},

किसी भी अन्य वेबपैक प्लग इन की तरह, इसे कॉन्फ़िगरेशन फ़ाइल में इंपोर्ट करें, webpack.config.js:

const path = require("path");

//...

const CompressionPlugin = require("compression-webpack-plugin");

और इसे plugins कलेक्शन में शामिल करें:

module.exports = {
  //...
  plugins: [
    //...
    new CompressionPlugin()
  ]
}

डिफ़ॉल्ट रूप से, प्लग इन gzip का इस्तेमाल करके बिल्ड फ़ाइलों को कंप्रेस करता है. किसी दूसरे एल्गोरिदम का इस्तेमाल करने या कुछ फ़ाइलों को शामिल करने/बाहर रखने के विकल्प जोड़ने का तरीका जानने के लिए, दस्तावेज़ देखें.

ऐप्लिकेशन फिर से लोड होने और फिर से बनने के बाद, मुख्य बंडल का कंप्रेस किया गया वर्शन बन जाता है. Node सर्वर से दिखाई गई public/ डायरेक्ट्री में क्या है, यह देखने के लिए Glitch कंसोल खोलें.

  • टूल बटन पर क्लिक करें.
  • कंसोल बटन पर क्लिक करें.
  • कंसोल में, public डायरेक्ट्री में जाने और उसकी सभी फ़ाइलें देखने के लिए, ये निर्देश चलाएं:
cd public
ls

सार्वजनिक डायरेक्ट्री में आउटपुट की गई फ़ाइलें

बंडल main.bundle.js.gz का ज़िप किया गया वर्शन भी अब यहां सेव किया गया है. CompressionPlugin, डिफ़ॉल्ट रूप से index.html को भी कंप्रेस करता है.

इसके बाद, सर्वर को यह बताना होगा कि जब भी उनके ओरिजनल JS वर्शन का अनुरोध किया जाए, तब इन ज़िप की गई फ़ाइलों को भेजें. ऐसा करने के लिए, express.static के साथ फ़ाइलें दिखाने से पहले, server.js में नया रूट तय करें.

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  req.url = req.url + '.gz';
  res.set('Content-Encoding', 'gzip');
  next();
});

app.use(express.static('public'));

//...

app.get का इस्तेमाल, सर्वर को यह बताने के लिए किया जाता है कि किसी खास एंडपॉइंट के लिए, जीईटी अनुरोध का जवाब कैसे दिया जाए. इसके बाद, इस अनुरोध को मैनेज करने का तरीका तय करने के लिए, कॉलबैक फ़ंक्शन का इस्तेमाल किया जाता है. यह रूट इस तरह काम करता है:

  • '*.js' को पहले आर्ग्युमेंट के तौर पर बताने का मतलब है कि यह हर उस एंडपॉइंट के लिए काम करता है जिसे JS फ़ाइल फ़ेच करने के लिए ट्रिगर किया जाता है.
  • कॉलबैक में, .gz को अनुरोध के यूआरएल से अटैच किया जाता है और Content-Encoding रिस्पॉन्स हेडर को gzip पर सेट किया जाता है.
  • आखिर में, next() यह पक्का करता है कि क्रम, अगले किसी भी कॉलबैक पर जारी रहे.

ऐप्लिकेशन फिर से लोड होने के बाद, Network पैनल को फिर से देखें.

स्टैटिक कंप्रेशन की मदद से बंडल का साइज़ कम करना

पहले की तरह ही, बंडल के साइज़ में काफ़ी कमी आई है!

नतीजा

इस कोडलैब में, सोर्स कोड को छोटा करने और कंप्रेस करने की प्रोसेस के बारे में बताया गया है. फ़िलहाल, ये दोनों तकनीकें, उपलब्ध कई टूल में डिफ़ॉल्ट तौर पर काम करती हैं. इसलिए, यह पता करना ज़रूरी है कि आपका टूल चेन पहले से ही इनका इस्तेमाल करता है या आपको दोनों प्रोसेस को खुद लागू करना होगा.