इस कोडलैब की मदद से, इस आसान ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाएं. इससे उपयोगकर्ता किसी भी क्रम में बिल्लियों को रेटिंग दे पाएंगे. कोड की संख्या को कम से कम करके JavaScript बंडल को ऑप्टिमाइज़ करने का तरीका जानें.
सैंपल ऐप्लिकेशन में, कोई शब्द या इमोजी चुनकर, यह बताया जा सकता है कि आपको हर बिल्ली की कितनी पसंद है. किसी बटन पर क्लिक करने से, ऐप्लिकेशन बिल्ली की मौजूदा इमेज के नीचे बटन की वैल्यू दिखाता है.
दूरी मापें
किसी भी तरह का ऑप्टिमाइज़ेशन जोड़ने से पहले, वेबसाइट की जांच करना बेहतर होता है:
- साइट की झलक देखने के लिए, ऐप्लिकेशन देखें दबाएं. इसके बाद, फ़ुलस्क्रीन दबाएं.
- DevTools खोलने के लिए, `Control+Shift+J` (या Mac पर `Command+Option+J`) दबाएं.
- नेटवर्क टैब पर क्लिक करें.
- कैश मेमोरी बंद करें चेकबॉक्स चुनें.
- ऐप्लिकेशन को फिर से लोड करें.
इस ऐप्लिकेशन के लिए 80 केबी से ज़्यादा का इस्तेमाल किया जाता है! समय, यह पता लगाने का समय है कि बंडल के कुछ हिस्सों का इस्तेमाल नहीं किया जा रहा है या नहीं:
Command मेन्यू खोलने के लिए
Control+Shift+P
(या Mac परCommand+Shift+P
) दबाएं.कवरेज टैब देखने के लिए,
Show Coverage
डालें औरEnter
दबाएं.कवरेज कैप्चर करते समय, ऐप्लिकेशन को फिर से लोड करने के लिए, कवरेज टैब में जाकर, फिर से लोड करें पर क्लिक करें.
एक नज़र डालें कि मुख्य बंडल के लिए कितने कोड का इस्तेमाल किया गया था और कितना लोड किया गया था:
आधे से ज़्यादा बंडल (44 केबी) का भी इस्तेमाल नहीं होता. ऐसा इसलिए होता है, क्योंकि इसमें मौजूद कई कोड में पॉलीफ़िल होते हैं, ताकि यह पक्का किया जा सके कि ऐप्लिकेशन पुराने ब्राउज़र पर काम करे.
@babel/preset-env का इस्तेमाल करें
JavaScript भाषा का सिंटैक्स एक स्टैंडर्ड के मुताबिक होता है, जिसे ECMAScript या ECMA-262 कहा जाता है. स्पेसिफ़िकेशन के नए वर्शन हर साल रिलीज़ किए जाते हैं. इनमें ऐसी नई सुविधाएं शामिल होती हैं जो प्रस्ताव देने की प्रोसेस को पास कर लेती हैं. हर प्रमुख ब्राउज़र इन सुविधाओं के साथ काम करने के अलग-अलग चरण में होता है.
ऐप्लिकेशन में, ES2015 की इन सुविधाओं का इस्तेमाल किया जाता है:
नीचे दी गई ES2017 सुविधा का भी इस्तेमाल किया जाता है:
इन सबका इस्तेमाल कैसे किया जाता है, यह जानने के लिए src/index.js
में सोर्स कोड को बेझिझक देखें.
ये सभी सुविधाएं Chrome के सबसे नए वर्शन में काम करती हैं, लेकिन जिन ब्राउज़र पर ये सुविधाएं काम नहीं करतीं उनका क्या? ऐप्लिकेशन में शामिल Babel, कोड को कंपाइल करने के लिए इस्तेमाल की जाने वाली सबसे लोकप्रिय लाइब्रेरी है. इसमें ऐसे कोड में नया सिंटैक्स होता है जिसे पुराने ब्राउज़र और एनवायरमेंट समझ सकते हैं. यह काम दो तरीकों से करता है:
- पॉलीफ़िल को नए ES2015+ फ़ंक्शन को एम्युलेट करने के लिए शामिल किया गया है. इससे, ब्राउज़र पर काम न करने पर भी उनके एपीआई इस्तेमाल किए जा सकते हैं. यहां
Array.includes
तरीके के polyfill का उदाहरण दिया गया है. - प्लगिन का इस्तेमाल, ES2015 या उसके बाद के कोड को पुराने ES5 सिंटैक्स में बदलने के लिए किया जाता है. ये सिंटैक्स से जुड़े बदलाव हैं, जैसे कि ऐरो फ़ंक्शन, इसलिए इन्हें पॉलीफ़िल का इस्तेमाल करके एम्युलेट नहीं किया जा सकता.
यह देखने के लिए package.json
पर देखें कि कौन-कौनसी Nearby लाइब्रेरी शामिल हैं:
"dependencies": {
"@babel/polyfill": "^7.0.0"
},
"devDependencies": {
//...
"babel-loader": "^8.0.2",
"@babel/core": "^7.1.0",
"@babel/preset-env": "^7.1.0",
//...
}
@babel/core
कोर Nearby कंपाइलर है. इससे सभी बेबल कॉन्फ़िगरेशन को प्रोजेक्ट के रूट में,.babelrc
में तय किया जाता है.babel-loader
में वेबपैक बनाने की प्रोसेस में बेबल शामिल है.
अब webpack.config.js
पर देखें कि babel-loader
को नियम के तौर पर कैसे शामिल किया गया है:
module: { rules: [ //... { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" } ] },
@babel/polyfill
किसी भी नई ECMAScript सुविधा के लिए सभी ज़रूरी पॉलीफ़िल उपलब्ध कराता है, ताकि वे उन जगहों पर काम कर सकें जो इनके साथ काम नहीं करती हैं. यह पहले से हीsrc/index.js.
में सबसे ऊपर इंपोर्ट किया गया है
import "./style.css";
import "@babel/polyfill";
@babel/preset-env
यह पहचान करता है कि टारगेट के तौर पर चुने गए किसी भी ब्राउज़र या एनवायरमेंट के लिए, कौनसे ट्रांसफ़ॉर्म और पॉलीफ़िल ज़रूरी हैं.
बेबल कॉन्फ़िगरेशन फ़ाइल .babelrc
पर एक नज़र डालें और देखें कि इसमें यह कैसे शामिल है:
{
"presets": [
[
"@babel/preset-env",
{
"targets": "last 2 versions"
}
]
]
}
यह बेबल और वेबपैक सेटअप है. अगर वेबपैक से अलग मॉड्यूल बंडलर का इस्तेमाल करना है, तो अपने ऐप्लिकेशन में बेबल को शामिल करने का तरीका जानें.
.babelrc
में targets
एट्रिब्यूट से पता चलता है कि कौनसे ब्राउज़र टारगेट किए जा रहे हैं. @babel/preset-env
ब्राउज़र की सूची के साथ इंटिग्रेट होता है. इसका मतलब है कि आपको इस फ़ील्ड में इस्तेमाल की जा सकने वाली क्वेरी की पूरी सूची मिल सकती है. इन क्वेरी का इस्तेमाल, ब्राउज़र की सूची वाले दस्तावेज़ में किया जा सकता है.
"last 2 versions"
वैल्यू, हर ब्राउज़र के पिछले दो वर्शन के लिए ऐप्लिकेशन में कोड को ट्रांसपाइल करती है.
डीबग करना
ब्राउज़र के सभी बेबल टारगेट के साथ-साथ, इसमें शामिल सभी ट्रांसफ़ॉर्म और पॉलीफ़िल को पूरा देखने के लिए, .babelrc:
में debug
फ़ील्ड जोड़ें
{
"presets": [
[
"@babel/preset-env",
{
"targets": "last 2 versions",
"debug": true
}
]
]
}
- टूल पर क्लिक करें.
- लॉग पर क्लिक करें.
ऐप्लिकेशन को फिर से लोड करें और एडिटर में सबसे नीचे Glitch का स्टेटस लॉग देखें.
टारगेट किए गए ब्राउज़र
बेबल, कंपाइल करने की प्रोसेस के बारे में कंसोल पर कई जानकारी लॉग करता है. इसमें वे सभी टारगेट एनवायरमेंट भी शामिल होते हैं जिनके लिए कोड को कंपाइल किया गया है.
ध्यान दें कि बंद किए गए ब्राउज़र, जैसे कि Internet Explorer कैसे इस सूची में शामिल किए गए हैं. यह समस्या है, क्योंकि काम न करने वाले ब्राउज़र में नई सुविधाएं नहीं जोड़ी जाएंगी और बेबल उनके लिए किसी सिंटैक्स को ट्रांसपाइल करता रहेगा. अगर उपयोगकर्ता आपकी साइट ऐक्सेस करने के लिए इस ब्राउज़र का इस्तेमाल नहीं कर रहे हैं, तो इससे आपके बंडल का साइज़ बेवजह बढ़ जाता है.
बेबल, उपयोग किए गए परिवर्तन प् लग इन की सूची भी लॉग करता है:
यह तो बहुत लंबी सूची है! यही वे सभी प्लग इन हैं जिनका इस्तेमाल Nearby को सभी टारगेट ब्राउज़र के लिए, किसी भी ES2015+ सिंटैक्स को पुराने सिंटैक्स में बदलने के लिए इस्तेमाल करना होगा.
हालांकि, बेबल इस्तेमाल किए जाने वाले कोई खास पॉलीफ़िल नहीं दिखाता है:
इसकी वजह यह है कि पूरे @babel/polyfill
को सीधे इंपोर्ट किया जा रहा है.
पॉलीफ़िल को एक-एक करके लोड करना
डिफ़ॉल्ट रूप से, @babel/polyfill
को फ़ाइल में इंपोर्ट किए जाने पर, बेबल में सभी ज़रूरी पॉलीफ़िल शामिल होते हैं. यह ES2015+ के पूरे एनवायरमेंट के लिए ज़रूरी होता है. टारगेट ब्राउज़र के लिए ज़रूरी पॉलीफ़िल को इंपोर्ट करने के लिए, कॉन्फ़िगरेशन में useBuiltIns: 'entry'
जोड़ें.
{
"presets": [
[
"@babel/preset-env",
{
"targets": "last 2 versions",
"debug": true
"useBuiltIns": "entry"
}
]
]
}
ऐप्लिकेशन को फिर से लोड करें. अब इसमें शामिल किए गए सभी खास पॉलीफ़िल देखे जा सकते हैं:
हालांकि, अब "last 2 versions"
के लिए सिर्फ़ ज़रूरी पॉलीफ़िल शामिल हैं, लेकिन यह अब भी एक लंबी सूची है! ऐसा इसलिए है, क्योंकि टारगेट ब्राउज़र के लिए हर नई सुविधा के लिए ज़रूरी पॉलीफ़िल अब भी शामिल है. एट्रिब्यूट की वैल्यू को बदलकर usage
करें, ताकि कोड में इस्तेमाल की जा रही सुविधाओं के लिए ज़रूरी वैल्यू को ही शामिल किया जा सके.
{
"presets": [
[
"@babel/preset-env",
{
"targets": "last 2 versions",
"debug": true,
"useBuiltIns": "entry"
"useBuiltIns": "usage"
}
]
]
}
इससे, ज़रूरत पड़ने पर पॉलीफ़िल अपने-आप शामिल हो जाते हैं.
इसका मतलब है कि आप src/index.js.
में @babel/polyfill
इंपोर्ट को हटा सकते हैं
import "./style.css";
import "@babel/polyfill";
अब सिर्फ़ ऐप्लिकेशन के लिए ज़रूरी पॉलीफ़िल शामिल किए गए हैं.
ऐप्लिकेशन बंडल का साइज़ काफ़ी कम हो गया है.
इस्तेमाल किए जा सकने वाले ब्राउज़र की सूची छोटी करना
शामिल किए गए ब्राउज़र टारगेट की संख्या अब भी बहुत ज़्यादा है. साथ ही, ज़्यादा उपयोगकर्ता, Internet Explorer जैसे बंद किए गए ब्राउज़र का इस्तेमाल नहीं करते. कॉन्फ़िगरेशन को यहां बताई गई चीज़ों के मुताबिक अपडेट करें:
{
"presets": [
[
"@babel/preset-env",
{
"targets": "last 2 versions",
"targets": [">0.25%", "not ie 11"],
"debug": true,
"useBuiltIns": "usage",
}
]
]
}
फ़ेच किए गए बंडल की जानकारी देखें.
ऐप्लिकेशन बहुत छोटा है, इसलिए इन बदलावों में कोई
कोई फ़र्क़ नहीं है. हालांकि, हमारा सुझाव है कि आप ब्राउज़र की मार्केट में हिस्सेदारी के प्रतिशत (जैसे कि ">0.25%"
) का इस्तेमाल करें. साथ ही, आप ऐसे ब्राउज़र को बाहर भी रखें जिनके बारे में आपको भरोसा है कि वे इस्तेमाल नहीं कर रहे हैं. इस बारे में ज़्यादा जानने के लिए, जेम्स कायल का लिखा "पिछले दो वर्शन" पढ़ें, जिन्हें नुकसान पहुंचाने वाला माना जाता है.
<script type="module"> का इस्तेमाल करें
सुधार की गुंजाइश अब भी बाकी है. हालांकि, इस्तेमाल न किए गए कई पॉलीफ़िल को हटा दिया गया है, लेकिन ऐसे कई पॉलीफ़िल हटा दिए गए हैं जो शिप किए जा रहे हैं और कुछ ब्राउज़र के लिए इनकी ज़रूरत नहीं होती है. मॉड्यूल का इस्तेमाल करके, नए सिंटैक्स को ग़ैर-ज़रूरी पॉलीफ़िल का इस्तेमाल किए बिना सीधे ब्राउज़र पर लिखा और शिप किया जा सकता है.
JavaScript मॉड्यूल सभी मुख्य ब्राउज़र में काम करने वाली नई सुविधा है.
मॉड्यूल, type="module"
एट्रिब्यूट का इस्तेमाल करके बनाए जा सकते हैं. इनकी मदद से, ऐसी स्क्रिप्ट तय की जा सकती हैं जो अन्य मॉड्यूल से इंपोर्ट और एक्सपोर्ट की जाती हैं. उदाहरण के लिए:
// math.mjs
export const add = (x, y) => x + y;
<!-- index.html -->
<script type="module">
import { add } from './math.mjs';
add(5, 2); // 7
</script>
कई नई ECMAScript सुविधाएं पहले से ही उन एनवायरमेंट में काम करती हैं जो JavaScript मॉड्यूल के साथ काम करते हैं (बबल की ज़रूरत के बजाय.) इसका मतलब है कि ब्राउज़र को आपके ऐप्लिकेशन के दो अलग-अलग वर्शन भेजने के लिए, बेबल कॉन्फ़िगरेशन में बदलाव किया जा सकता है:
- यह वर्शन नए ब्राउज़र में काम करेगा, जो मॉड्यूल के साथ काम करता है. साथ ही, इसमें ऐसा मॉड्यूल शामिल है जिसका फ़ाइल साइज़ काफ़ी हद तक ट्रांसपायल नहीं किया गया है, लेकिन उसका साइज़ छोटा है
- यह ऐसा वर्शन है जिसमें बड़ी और ट्रांसपाइल की गई स्क्रिप्ट शामिल है. यह किसी भी लेगसी ब्राउज़र में काम करती है
बेबल के साथ ES मॉड्यूल का इस्तेमाल करना
ऐप्लिकेशन के दोनों वर्शन के लिए @babel/preset-env
की अलग-अलग सेटिंग तय करने के लिए, .babelrc
फ़ाइल हटाएं. ऐप्लिकेशन के हर वर्शन के लिए दो अलग-अलग कंपाइलेशन फ़ॉर्मैट तय करके, बेबल सेटिंग को वेबपैक कॉन्फ़िगरेशन में जोड़ा जा सकता है.
webpack.config.js
में लेगसी स्क्रिप्ट के लिए, कॉन्फ़िगरेशन जोड़कर शुरुआत करें:
const legacyConfig = {
entry,
output: {
path: path.resolve(__dirname, "public"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [
["@babel/preset-env", {
useBuiltIns: "usage",
targets: {
esmodules: false
}
}]
]
}
},
cssRule
]
},
plugins
}
ध्यान दें कि "@babel/preset-env"
के लिए targets
वैल्यू का इस्तेमाल करने के बजाय,
false
वैल्यू वाला esmodules
का इस्तेमाल किया जाता है. इसका मतलब है कि जिस ब्राउज़र पर ईएस मॉड्यूल काम नहीं करता उसे टारगेट करने के लिए, बेबल में
सभी ज़रूरी ट्रांसफ़ॉर्म और पॉलीफ़िल शामिल हैं.
webpack.config.js
फ़ाइल की शुरुआत में entry
, cssRule
, और corePlugins
ऑब्जेक्ट जोड़ें. ब्राउज़र को दिखाए जाने वाले मॉड्यूल और लेगसी स्क्रिप्ट, दोनों के बीच इन सभी को शेयर किया जाता है.
const entry = {
main: "./src"
};
const cssRule = {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
};
const plugins = [
new ExtractTextPlugin({filename: "[name].css", allChunks: true}),
new HtmlWebpackPlugin({template: "./src/index.html"})
];
अब इसी तरह, यहां दी गई मॉड्यूल स्क्रिप्ट के लिए एक कॉन्फ़िगरेशन ऑब्जेक्ट बनाएं, जहां legacyConfig
तय किया गया है:
const moduleConfig = {
entry,
output: {
path: path.resolve(__dirname, "public"),
filename: "[name].mjs"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [
["@babel/preset-env", {
useBuiltIns: "usage",
targets: {
esmodules: true
}
}]
]
}
},
cssRule
]
},
plugins
}
यहां मुख्य अंतर यह है कि आउटपुट फ़ाइल नाम के लिए, .mjs
फ़ाइल एक्सटेंशन का इस्तेमाल किया जाता है. यहां esmodules
वैल्यू को 'सही' पर सेट किया गया है. इसका मतलब है कि इस मॉड्यूल में आउटपुट किया गया कोड, छोटी और कम कंपाइल की गई स्क्रिप्ट है. इस उदाहरण में, यह किसी भी तरह का बदलाव नहीं करता, क्योंकि इस्तेमाल की जाने वाली सभी सुविधाएं, मॉड्यूल के साथ काम करने वाले ब्राउज़र में पहले से ही काम करती हैं.
फ़ाइल के आखिर में, दोनों कॉन्फ़िगरेशन को एक ही अरे में एक्सपोर्ट करें.
module.exports = [
legacyConfig, moduleConfig
];
अब यह उन ब्राउज़र के लिए एक छोटा मॉड्यूल बनाता है जो इसके साथ काम करते हैं और पुराने ब्राउज़र के लिए एक बड़ी ट्रांसपाइल स्क्रिप्ट, दोनों बनाती है.
मॉड्यूल के साथ काम करने वाले ब्राउज़र, nomodule
एट्रिब्यूट वाली स्क्रिप्ट को अनदेखा कर देते हैं.
इसके ठीक उलट, जिन ब्राउज़र में मॉड्यूल काम नहीं करते उनमें type="module"
वाले स्क्रिप्ट एलिमेंट को अनदेखा कर दिया जाता है. इसका मतलब है कि आपके पास मॉड्यूल के साथ-साथ, कंपाइल किया गया फ़ॉलबैक
भी शामिल किया जा सकता है. आम तौर पर, ऐप्लिकेशन के दोनों वर्शन index.html
में इस तरह से होने चाहिए:
<script type="module" src="main.mjs"></script>
<script nomodule src="main.bundle.js"></script>
ऐसे ब्राउज़र जिन पर मॉड्यूल को फ़ेच और एक्ज़ीक्यूट करने की सुविधा काम करती है, main.mjs
उन्हें अनदेखा करते हैं
main.bundle.js.
जिन ब्राउज़र में मॉड्यूल काम नहीं करते उनका उलटा होता है.
ध्यान रखें कि सामान्य स्क्रिप्ट के उलट, मॉड्यूल स्क्रिप्ट हमेशा डिफ़ॉल्ट रूप से टाली जाती हैं.
अगर आपको मिलती-जुलती nomodule
स्क्रिप्ट को भी टालना है और सिर्फ़ पार्स करने के बाद ही चलाना है, तो आपको defer
एट्रिब्यूट जोड़ना होगा:
<script type="module" src="main.mjs"></script>
<script nomodule src="main.bundle.js" defer></script>
आपको आखिर में मॉड्यूल और लेगसी स्क्रिप्ट में module
और nomodule
एट्रिब्यूट को जोड़ना होगा. इसके लिए, webpack.config.js
के सबसे ऊपर मौजूद ScriptExtHtmlWebpackPlugin को इंपोर्ट करें:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ScriptExtHtmlWebpackPlugin = require("script-ext-html-webpack-plugin");
अब इस प्लग इन को शामिल करने के लिए, कॉन्फ़िगरेशन में plugins
कलेक्शन को अपडेट करें:
const plugins = [ new ExtractTextPlugin({filename: "[name].css", allChunks: true}), new HtmlWebpackPlugin({template: "./src/index.html"}), new ScriptExtHtmlWebpackPlugin({ module: /\.mjs$/, custom: [ { test: /\.js$/, attribute: 'nomodule', value: '' }, ] }) ];
इन प्लग इन सेटिंग में, .mjs
स्क्रिप्ट के सभी एलिमेंट के लिए एक type="module"
एट्रिब्यूट जोड़ा जाता है. साथ ही, सभी .js
स्क्रिप्ट मॉड्यूल के लिए, एक nomodule
एट्रिब्यूट भी जोड़ा जाता है.
एचटीएमएल दस्तावेज़ में मॉड्यूल दिखाना
आपको आखिर में एचटीएमएल फ़ाइल में लेगसी और मॉडर्न स्क्रिप्ट एलिमेंट, दोनों का इस्तेमाल करना होगा. माफ़ करें, फ़ाइनल एचटीएमएल फ़ाइल HTMLWebpackPlugin
बनाने वाला प्लगिन, मॉड्यूल और नोमॉड्यूल स्क्रिप्ट, दोनों के आउटपुट के लिए फ़िलहाल काम नहीं करता. हालांकि, इस समस्या को हल करने के लिए समाधान और अलग-अलग प्लगिन उपलब्ध हैं, जैसे कि BabelMultiTargetPlugin और HTMLWebpackMultiBuildPlugin. इस ट्यूटोरियल के लिए, मॉड्यूल स्क्रिप्ट एलिमेंट को मैन्युअल तौर पर जोड़ने का आसान तरीका इस्तेमाल किया जाता है.
फ़ाइल के आखिर में, src/index.js
में यह जोड़ें:
...
</form>
<script type="module" src="main.mjs"></script>
</body>
</html>
अब ऐप्लिकेशन को ऐसे ब्राउज़र में लोड करें जो Chrome के नए वर्शन जैसे मॉड्यूल की सुविधा देता हो.
सिर्फ़ मॉड्यूल फ़ेच किया जाता है, क्योंकि बंडल का साइज़ बहुत छोटा होने की वजह से इसे काफ़ी हद तक ट्रांसफ़र नहीं किया जाता है! ब्राउज़र ने दूसरे स्क्रिप्ट एलिमेंट को पूरी तरह से अनदेखा कर दिया है.
अगर ऐप्लिकेशन को किसी पुराने ब्राउज़र पर लोड किया जाता है, तो सभी ज़रूरी पॉलीफ़िल और ट्रांसफ़ॉर्म वाली बड़ी स्क्रिप्ट को ही फ़ेच किया जाता है. यहां Chrome के पुराने वर्शन (वर्शन 38) पर किए गए सभी अनुरोधों का स्क्रीनशॉट दिया गया है.
नतीजा
अब आपको समझ आ गया है कि टारगेट किए गए ब्राउज़र के लिए, सिर्फ़ ज़रूरी पॉलीफ़िल उपलब्ध कराने के लिए @babel/preset-env
का इस्तेमाल कैसे करते हैं. आपको यह भी पता है कि JavaScript मॉड्यूल किस तरह किसी ऐप्लिकेशन के दो अलग-अलग ट्रांसपाइल वर्शन शिप करके
परफ़ॉर्मेंस को और बेहतर बना सकता है. इन दोनों तकनीकों से आपके बंडल के साइज़ को
काफ़ी कम कैसे किया जा सकता है, इस बारे में अच्छी तरह से समझते हुए, आगे बढ़ें और ऑप्टिमाइज़ करें!