इस कोडलैब में बताया गया है कि JavaScript बंडल को छोटा करने और कंप्रेस करने से, ऐप्लिकेशन की परफ़ॉर्मेंस कैसे बेहतर होती है. इससे ऐप्लिकेशन के अनुरोध का साइज़ कम हो जाता है.
मापें
ऑप्टिमाइज़ेशन जोड़ने से पहले, ऐप्लिकेशन की मौजूदा स्थिति का विश्लेषण करना हमेशा एक अच्छा तरीका होता है.
- साइट की झलक देखने के लिए, ऐप्लिकेशन देखें दबाएं. इसके बाद, फ़ुलस्क्रीन
दबाएं.
इस ऐप्लिकेशन के बारे में, "इस्तेमाल नहीं किए गए कोड हटाएं" कोडलैब में भी बताया गया था. इससे आपको अपने पसंदीदा बिल्ली के बच्चे के लिए वोट करने का विकल्प मिलता है. 🐈
अब देखें कि यह ऐप्लिकेशन कितना बड़ा है:
- DevTools खोलने के लिए, `Control+Shift+J` (या Mac पर `Command+Option+J`) दबाएं.
- नेटवर्क टैब पर क्लिक करें.
- कैश मेमोरी बंद करें चेकबॉक्स को चुनें.
- ऐप्लिकेशन को फिर से लोड करें.
इस बंडल के साइज़ को कम करने के लिए, "इस्तेमाल न हो रहे कोड हटाएं" कोडलैब में काफ़ी काम किया गया है. हालाँकि, 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, प्रोडक्शन मोड के दौरान बंडल को डिफ़ॉल्ट रूप से पहले ही छोटा कर देता है. यह TerserWebpackPlugin
Terser के लिए प्लग इन का इस्तेमाल करता है.
Terser, JavaScript कोड को कंप्रेस करने के लिए इस्तेमाल किया जाने वाला एक लोकप्रिय टूल है.
मिनिफ़ाइड कोड कैसा दिखता है, यह जानने के लिए DevTools के नेटवर्क पैनल में रहते हुए, main.bundle.js
पर क्लिक करें. अब जवाब टैब पर क्लिक करें.
जवाब के मुख्य हिस्से में, कोड को उसके फ़ाइनल फ़ॉर्म में दिखाया जाता है. इसे छोटा और बदला गया होता है.
अगर बंडल को छोटा नहीं किया गया है, तो उसका साइज़ कितना हो सकता है, यह जानने के लिए webpack.config.js
खोलें और mode
कॉन्फ़िगरेशन अपडेट करें.
module.exports = {
mode: 'production',
mode: 'none',
//...
ऐप्लिकेशन को फिर से लोड करें और DevTools Network पैनल में जाकर, बंडल का साइज़ फिर से देखें
यह काफ़ी बड़ा अंतर है! 😅
जारी रखने से पहले, यहां किए गए बदलावों को पहले जैसा करें.
module.exports = {
mode: 'production',
mode: 'none',
//...
अपने ऐप्लिकेशन में कोड को छोटा करने की प्रोसेस को शामिल करना, आपके इस्तेमाल किए गए टूल पर निर्भर करता है:
- अगर webpack v4 या इसके बाद के वर्शन का इस्तेमाल किया जाता है, तो कोई अतिरिक्त काम करने की ज़रूरत नहीं है. ऐसा इसलिए, क्योंकि प्रोडक्शन मोड में कोड डिफ़ॉल्ट रूप से छोटा किया जाता है. 👍
- अगर webpack के पुराने वर्शन का इस्तेमाल किया जा रहा है, तो
TerserWebpackPlugin
को इंस्टॉल करें और इसे webpack की बिल्ड प्रोसेस में शामिल करें. दस्तावेज़ में इसके बारे में ज़्यादा जानकारी दी गई है. - इसके अलावा, छोटा करने वाले अन्य प्लगिन भी उपलब्ध हैं और इनका इस्तेमाल किया जा सकता है. जैसे, BabelMinifyWebpackPlugin और ClosureCompilerPlugin.
- अगर किसी मॉड्यूल बंडलर का इस्तेमाल नहीं किया जा रहा है, तो सीएलआई टूल के तौर पर Terser का इस्तेमाल करें या इसे सीधे तौर पर डिपेंडेंसी के तौर पर शामिल करें.
संपीड़न
कभी-कभी "कंप्रेशन" शब्द का इस्तेमाल, यह बताने के लिए किया जाता है कि कोड को छोटा करने की प्रोसेस के दौरान कोड को कैसे कम किया जाता है. हालांकि, असल में कोड को कंप्रेस नहीं किया जाता है.
कंप्रेशन का मतलब आम तौर पर ऐसे कोड से होता है जिसे डेटा कंप्रेस करने वाले एल्गोरिदम का इस्तेमाल करके बदला गया हो. मिनिफ़िकेशन से पूरी तरह से मान्य कोड मिलता है. हालांकि, कंप्रेस किए गए कोड का इस्तेमाल करने से पहले, उसे डीकंप्रेस करना ज़रूरी होता है.
हर एचटीटीपी अनुरोध और जवाब के साथ, ब्राउज़र और वेब सर्वर हेडर जोड़ सकते हैं. इससे, फ़ेच की जा रही या मिली ऐसेट के बारे में ज़्यादा जानकारी शामिल की जा सकती है. इसे DevTools के नेटवर्क पैनल में मौजूद Headers
टैब में देखा जा सकता है. इसमें तीन तरह के अनुरोध दिखते हैं:
- सामान्य से मतलब उन सामान्य हेडर से है जो अनुरोध-जवाब के पूरे इंटरैक्शन के लिए ज़रूरी होते हैं.
- रिस्पॉन्स हेडर में, सर्वर से मिले असली रिस्पॉन्स से जुड़े हेडर की सूची दिखती है.
- अनुरोध के हेडर में, क्लाइंट की ओर से अनुरोध में जोड़े गए हेडर की सूची दिखती है.
Request Headers
में मौजूद accept-encoding
हेडर देखें.
accept-encoding
का इस्तेमाल ब्राउज़र यह बताने के लिए करता है कि वह कॉन्टेंट एन्कोडिंग के किन फ़ॉर्मैट या कंप्रेस करने के किन एल्गोरिदम के साथ काम करता है. टेक्स्ट को कंप्रेस करने के लिए कई एल्गोरिदम उपलब्ध हैं. हालांकि, एचटीटीपी नेटवर्क अनुरोधों को कंप्रेस (और डिकंप्रेस) करने के लिए, यहां सिर्फ़ तीन एल्गोरिदम इस्तेमाल किए जा सकते हैं:
- Gzip (
gzip
): सर्वर और क्लाइंट के इंटरैक्शन के लिए, सबसे ज़्यादा इस्तेमाल किया जाने वाला कंप्रेस करने का फ़ॉर्मैट. यह 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
मिडलवेयर का इस्तेमाल करके, public/
डायरेक्ट्री में मौजूद सभी स्टैटिक एचटीएमएल, JS, और सीएसएस फ़ाइलों को लोड करता है. साथ ही, इन फ़ाइलों को हर बिल्ड के साथ webpack बनाता है.
यह पक्का करने के लिए कि जब भी ऐसेट का अनुरोध किया जाए, तब उन्हें कंप्रेस किया जाए, compression मिडलवेयर लाइब्रेरी का इस्तेमाल किया जा सकता है. इसे 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'));
//...
अब ऐप्लिकेशन को फिर से लोड करें और Network पैनल में बंडल का साइज़ देखें.
225 केबी से 61.6 केबी तक! Response Headers
में अब content-encoding
हेडर से पता चलता है कि सर्वर, इस फ़ाइल को gzip
के साथ एन्कोड करके भेज रहा है.
स्टैटिक कंप्रेस करना
स्टैटिक कंप्रेशन का मकसद, ऐसेट को कंप्रेस करके पहले से सेव करना है.
फ़ायदे
- कंप्रेशन के ज़्यादा लेवल की वजह से होने वाली लेटेन्सी अब कोई समस्या नहीं है. फ़ाइलों को कंप्रेस करने के लिए, अब कुछ भी करने की ज़रूरत नहीं है. ऐसा इसलिए, क्योंकि अब उन्हें सीधे तौर पर फ़ेच किया जा सकता है.
नुकसान
- हर बिल्ड के साथ ऐसेट को कंप्रेस करना ज़रूरी है. अगर कंप्रेस करने के ज़्यादा लेवल का इस्तेमाल किया जाता है, तो बिल्ड करने में लगने वाला समय काफ़ी बढ़ सकता है.
Node/Express और webpack के साथ स्टैटिक कंप्रेशन
स्टैटिक कंप्रेस करने की प्रोसेस में, फ़ाइलों को पहले से ही कंप्रेस कर दिया जाता है. इसलिए, webpack की सेटिंग में बदलाव करके, ऐसेट को कंप्रेस किया जा सकता है. ऐसा बिल्ड स्टेप के दौरान किया जाता है.
इसके लिए, CompressionPlugin
का इस्तेमाल किया जा सकता है.
इसे package.json
में devDependency
के तौर पर जोड़ें:
"devDependencies": {
//...
"compression-webpack-plugin": "^1.1.11"
},
किसी अन्य webpack प्लगिन की तरह, इसे कॉन्फ़िगरेशन फ़ाइल में इंपोर्ट करें,
webpack.config.js:
const path = require("path");
//...
const CompressionPlugin = require("compression-webpack-plugin");
साथ ही, इसे plugins
कैटगरी में शामिल करें:
module.exports = {
//...
plugins: [
//...
new CompressionPlugin()
]
}
डिफ़ॉल्ट रूप से, प्लग इन gzip
का इस्तेमाल करके, बिल्ड फ़ाइलों को कंप्रेस करता है. किसी दूसरे एल्गोरिदम का इस्तेमाल करने के लिए विकल्प जोड़ने या कुछ फ़ाइलों को शामिल/बाहर करने का तरीका जानने के लिए, दस्तावेज़ देखें.
ऐप्लिकेशन के फिर से लोड होने और रीबिल्ड होने पर, अब मुख्य बंडल का कंप्रेस किया गया वर्शन बन जाता है. Glitch Console खोलें और देखें कि Node सर्वर से दिखाई जाने वाली फ़ाइनल public/
डायरेक्ट्री में क्या है.
- टूल बटन पर क्लिक करें.
- Console बटन पर क्लिक करें.
- कंसोल में,
public
डायरेक्ट्री में जाने और उसकी सभी फ़ाइलें देखने के लिए, यहां दिए गए निर्देश चलाएं:
cd public
ls
बंडल का gzip किया गया वर्शन, main.bundle.js.gz
, अब यहां भी सेव हो गया है. CompressionPlugin
, डिफ़ॉल्ट रूप से index.html
को भी कंप्रेस करता है.
इसके बाद, सर्वर को यह बताना होगा कि जब भी इन फ़ाइलों के ओरिजनल JS वर्शन का अनुरोध किया जाए, तब उन्हें gzipped फ़ाइलें भेजनी हैं. इसके लिए, server.js
में एक नया रूट तय किया जा सकता है. ऐसा तब करें, जब express.static
की मदद से फ़ाइलें दिखाई जा रही हों.
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
का इस्तेमाल, सर्वर को यह बताने के लिए किया जाता है कि किसी खास एंडपॉइंट के लिए GET अनुरोध का जवाब कैसे देना है. इसके बाद, कॉलबैक फ़ंक्शन का इस्तेमाल करके यह तय किया जाता है कि इस अनुरोध को कैसे हैंडल करना है. यह सुविधा इस तरह काम करती है:
- पहले आर्ग्युमेंट के तौर पर
'*.js'
को तय करने का मतलब है कि यह हर उस एंडपॉइंट के लिए काम करता है जिसे JS फ़ाइल फ़ेच करने के लिए ट्रिगर किया जाता है. - कॉलबैक के दौरान,
.gz
को अनुरोध के यूआरएल से जोड़ा जाता है. साथ ही,Content-Encoding
रिस्पॉन्स हेडर कोgzip
पर सेट किया जाता है. - आखिर में,
next()
यह पक्का करता है कि क्रम में अगला कॉलबैक जारी रहे.
ऐप्लिकेशन के फिर से लोड होने के बाद, Network
पैनल को एक बार फिर से देखें.
पहले की तरह, बंडल के साइज़ में काफ़ी कमी आई है!
नतीजा
इस कोडलैब में, सोर्स कोड को छोटा करने और कंप्रेस करने की प्रोसेस के बारे में बताया गया है. आजकल उपलब्ध कई टूल में, इन दोनों तकनीकों का इस्तेमाल डिफ़ॉल्ट रूप से किया जाता है. इसलिए, यह जानना ज़रूरी है कि आपकी टूलचेन पहले से ही इनका इस्तेमाल करती है या आपको खुद इन दोनों प्रोसेस को लागू करना होगा.