কিভাবে আমরা PROXX এ কোড স্প্লিটিং, কোড ইনলাইনিং এবং সার্ভার-সাইড রেন্ডারিং ব্যবহার করেছি।
Google I/O 2019 এ Mariko, Jake, এবং আমি PROXX পাঠিয়েছি, ওয়েবের জন্য একটি আধুনিক মাইনসুইপার-ক্লোন। এমন কিছু যা PROXX কে আলাদা করে তা হল অ্যাক্সেসিবিলিটির উপর ফোকাস (আপনি এটি একটি স্ক্রিনরিডার দিয়ে চালাতে পারেন!) এবং হাই-এন্ড ডেস্কটপ ডিভাইসের মতো ফিচার ফোনেও চালানোর ক্ষমতা। ফিচার ফোন একাধিক উপায়ে সীমাবদ্ধ:
- দুর্বল সিপিইউ
- দুর্বল বা অস্তিত্বহীন জিপিইউ
- স্পর্শ ইনপুট ছাড়া ছোট পর্দা
- মেমরি খুব সীমিত পরিমাণ
কিন্তু তারা একটি আধুনিক ব্রাউজার চালায় এবং খুব সাশ্রয়ী মূল্যের। এই কারণে, ফিচার ফোনগুলি উদীয়মান বাজারে একটি পুনরুত্থান ঘটাচ্ছে। তাদের মূল্য বিন্দু একটি সম্পূর্ণ নতুন শ্রোতাদের অনুমতি দেয়, যারা আগে এটি বহন করতে পারেনি, অনলাইনে আসতে এবং আধুনিক ওয়েব ব্যবহার করতে পারে৷ 2019 এর জন্য এটি অনুমান করা হয়েছে যে প্রায় 400 মিলিয়ন ফিচার ফোন শুধুমাত্র ভারতেই বিক্রি হবে , তাই ফিচার ফোনের ব্যবহারকারীরা আপনার দর্শকদের একটি উল্লেখযোগ্য অংশ হয়ে উঠতে পারে। তা ছাড়াও, 2G-এর মতো সংযোগের গতি উদীয়মান বাজারে আদর্শ। আমরা কীভাবে ফিচার ফোনের শর্তে PROXX কে ভালভাবে কাজ করতে পরিচালনা করেছি?
পারফরম্যান্স গুরুত্বপূর্ণ, এবং এতে লোডিং পারফরম্যান্স এবং রানটাইম পারফরম্যান্স উভয়ই অন্তর্ভুক্ত। এটি দেখানো হয়েছে যে ভাল পারফরম্যান্স বর্ধিত ব্যবহারকারীর ধারণ, উন্নত রূপান্তর এবং সবচেয়ে গুরুত্বপূর্ণভাবে-বর্ধিত অন্তর্ভুক্তির সাথে সম্পর্কযুক্ত। কেন পারফরম্যান্স গুরুত্বপূর্ণ সে সম্পর্কে জেরেমি ওয়াগনারের অনেক বেশি ডেটা এবং অন্তর্দৃষ্টি রয়েছে৷
এটি একটি দুই পর্বের সিরিজের পার্ট 1। পার্ট 1 লোডিং পারফরম্যান্সের উপর ফোকাস করে , এবং পার্ট 2 রানটাইম পারফরম্যান্সের উপর ফোকাস করবে।
স্থিতাবস্থা ক্যাপচার করা
একটি বাস্তব ডিভাইসে আপনার লোডিং কর্মক্ষমতা পরীক্ষা করা গুরুত্বপূর্ণ। যদি আপনার হাতে একটি বাস্তব ডিভাইস না থাকে, আমি সুপারিশ করি WebPageTest , বিশেষ করে "সহজ" সেটআপ । WPT একটি ইমুলেটেড 3G সংযোগ সহ একটি বাস্তব ডিভাইসে লোডিং পরীক্ষার একটি ব্যাটারি চালায়।
3G একটি ভাল গতি পরিমাপ. যদিও আপনি 4G, LTE বা শীঘ্রই এমনকি 5G-তে অভ্যস্ত হতে পারেন, মোবাইল ইন্টারনেটের বাস্তবতা বেশ ভিন্ন দেখায়। হতে পারে আপনি একটি ট্রেনে, একটি সম্মেলনে, একটি কনসার্টে, বা একটি ফ্লাইটে। আপনি সেখানে যা অনুভব করবেন তা সম্ভবত 3G এর কাছাকাছি এবং কখনও কখনও আরও খারাপ।
বলা হচ্ছে, আমরা এই নিবন্ধে 2G-এর উপর ফোকাস করতে যাচ্ছি কারণ PROXX স্পষ্টভাবে ফিচার ফোন এবং উদীয়মান বাজারগুলিকে তার লক্ষ্য দর্শকদের মধ্যে টার্গেট করছে। WebPageTest এর পরীক্ষা চালানো হয়ে গেলে, আপনি একটি জলপ্রপাত (আপনি DevTools-এ যা দেখেন তার অনুরূপ) পাশাপাশি শীর্ষে একটি ফিল্মস্ট্রিপ পাবেন। ফিল্ম স্ট্রিপ দেখায় যে আপনার অ্যাপ লোড হওয়ার সময় আপনার ব্যবহারকারী কী দেখেন। 2G-তে, PROXX-এর অপ্টিমাইজ করা সংস্করণের লোডিং অভিজ্ঞতা বেশ খারাপ:
3G এর উপর লোড করা হলে, ব্যবহারকারী 4 সেকেন্ডের সাদা শূন্যতা দেখতে পান। 2G-এর উপরে ব্যবহারকারী 8 সেকেন্ডের জন্য একেবারে কিছুই দেখতে পায় না। কর্মক্ষমতা কেন গুরুত্বপূর্ণ তা যদি আপনি পড়েন তবে আপনি জানেন যে আমরা এখন অধৈর্যতার কারণে আমাদের সম্ভাব্য ব্যবহারকারীদের একটি ভাল অংশ হারিয়ে ফেলেছি। স্ক্রিনে কিছু দেখাতে ব্যবহারকারীকে 62 KB জাভাস্ক্রিপ্টের সমস্ত ডাউনলোড করতে হবে। এই দৃশ্যের রূপালী আস্তরণ হল যে দ্বিতীয় কিছু পর্দায় প্রদর্শিত হয় এটিও ইন্টারেক্টিভ। নাকি এটা?

প্রায় 62 KB gzip'd JS ডাউনলোড হওয়ার পরে এবং DOM তৈরি হওয়ার পরে, ব্যবহারকারী আমাদের অ্যাপটি দেখতে পাবেন। অ্যাপটি প্রযুক্তিগতভাবে ইন্টারেক্টিভ। তবে ভিজ্যুয়াল দেখলে ভিন্ন বাস্তবতা দেখা যায়। ওয়েব ফন্টগুলি এখনও ব্যাকগ্রাউন্ডে লোড হচ্ছে এবং তারা প্রস্তুত না হওয়া পর্যন্ত ব্যবহারকারী কোনও পাঠ্য দেখতে পাবে না। যদিও এই স্টেটটি ফার্স্ট মিনিংফুল পেইন্ট (FMP) হিসাবে যোগ্যতা অর্জন করে, এটি অবশ্যই সঠিকভাবে ইন্টারেক্টিভ হিসাবে যোগ্যতা অর্জন করে না, কারণ ব্যবহারকারী বলতে পারে না যে কোন ইনপুটগুলি কী। অ্যাপটি চালু না হওয়া পর্যন্ত এটি 3G-তে আরও একটি সেকেন্ড এবং 2G-তে 3 সেকেন্ড সময় নেয়। সব মিলিয়ে, অ্যাপটি ইন্টারেক্টিভ হতে 3G-তে 6 সেকেন্ড এবং 2G-তে 11 সেকেন্ড সময় নেয়।
জলপ্রপাত বিশ্লেষণ
এখন যেহেতু আমরা জানি ব্যবহারকারী কী দেখে, আমাদের কেন তা খুঁজে বের করতে হবে। এর জন্য আমরা জলপ্রপাতটি দেখতে পারি এবং বিশ্লেষণ করতে পারি কেন সংস্থানগুলি খুব দেরিতে লোড হচ্ছে। PROXX-এর জন্য আমাদের 2G ট্রেসে আমরা দুটি প্রধান লাল পতাকা দেখতে পাচ্ছি:
- একাধিক, বহু রঙের পাতলা লাইন আছে।
- জাভাস্ক্রিপ্ট ফাইল একটি চেইন গঠন করে। উদাহরণস্বরূপ, প্রথম সংস্থানটি শেষ হওয়ার পরে দ্বিতীয় সংস্থানটি কেবলমাত্র লোড হওয়া শুরু করে এবং দ্বিতীয় সংস্থানটি শেষ হলেই তৃতীয় সংস্থানটি শুরু হয়।

সংযোগের সংখ্যা হ্রাস করা
প্রতিটি পাতলা লাইন ( dns
, connect
, ssl
) একটি নতুন HTTP সংযোগ তৈরির জন্য দাঁড়ায়। একটি নতুন সংযোগ সেট আপ করা ব্যয়বহুল কারণ এটি 3G তে প্রায় 1s এবং 2G তে প্রায় 2.5s লাগে৷ আমাদের জলপ্রপাতে আমরা এর জন্য একটি নতুন সংযোগ দেখতে পাচ্ছি:
- অনুরোধ #1: আমাদের
index.html
- অনুরোধ #5:
fonts.googleapis.com
থেকে ফন্ট শৈলী - অনুরোধ #8: Google Analytics
- অনুরোধ #9:
fonts.gstatic.com
থেকে একটি ফন্ট ফাইল - অনুরোধ #14: ওয়েব অ্যাপ ম্যানিফেস্ট
index.html
এর জন্য নতুন সংযোগ অনিবার্য। বিষয়বস্তু পেতে ব্রাউজারকে আমাদের সার্ভারের সাথে একটি সংযোগ তৈরি করতে হবে । Google Analytics-এর জন্য নতুন সংযোগটি Minimal Analytics-এর মতো কিছু ইনলাইন করে এড়ানো যেতে পারে, কিন্তু Google Analytics আমাদের অ্যাপকে রেন্ডারিং বা ইন্টারেক্টিভ হতে বাধা দিচ্ছে না, তাই এটি কত দ্রুত লোড হয় সে বিষয়ে আমরা সত্যিই চিন্তা করি না। আদর্শভাবে, Google Analytics অলস সময়ে লোড করা উচিত, যখন বাকি সবকিছু ইতিমধ্যে লোড হয়ে গেছে। এইভাবে এটি প্রাথমিক লোডের সময় ব্যান্ডউইথ বা প্রক্রিয়াকরণ শক্তি গ্রহণ করবে না। ওয়েব অ্যাপ ম্যানিফেস্টের জন্য নতুন সংযোগ ফেচ স্পেক দ্বারা নির্ধারিত হয়, কারণ ম্যানিফেস্টটিকে একটি অ-প্রমাণপত্রবিহীন সংযোগে লোড করতে হবে৷ আবার, ওয়েব অ্যাপ ম্যানিফেস্ট আমাদের অ্যাপকে রেন্ডারিং বা ইন্টারেক্টিভ হতে বাধা দেয় না, তাই আমাদের এতটা যত্ন নেওয়ার দরকার নেই।
দুটি ফন্ট এবং তাদের শৈলী, তবে, একটি সমস্যা কারণ তারা রেন্ডারিং এবং ইন্টারঅ্যাক্টিভিটি ব্লক করে। আমরা যদি fonts.googleapis.com
দ্বারা বিতরণ করা CSS-এর দিকে তাকাই, তবে এটি শুধুমাত্র দুটি @font-face
নিয়ম, প্রতিটি ফন্টের জন্য একটি। ফন্ট শৈলীগুলি আসলে এতই ছোট যে আমরা একটি অপ্রয়োজনীয় সংযোগ সরিয়ে এটিকে আমাদের HTML এ ইনলাইন করার সিদ্ধান্ত নিয়েছি। ফন্ট ফাইলগুলির জন্য সংযোগ সেটআপের খরচ এড়াতে, আমরা সেগুলিকে আমাদের নিজস্ব সার্ভারে অনুলিপি করতে পারি।
সমান্তরাল লোড
জলপ্রপাতের দিকে তাকিয়ে, আমরা দেখতে পাচ্ছি যে একবার প্রথম জাভাস্ক্রিপ্ট ফাইলটি লোড হওয়ার পরে, নতুন ফাইলগুলি অবিলম্বে লোড হতে শুরু করে। এটি মডিউল নির্ভরতার জন্য সাধারণ। আমাদের প্রধান মডিউলে সম্ভবত স্ট্যাটিক ইম্পোর্ট আছে, তাই সেই ইম্পোর্ট লোড না হওয়া পর্যন্ত JavaScript চলতে পারে না। এখানে উপলব্ধি করা গুরুত্বপূর্ণ বিষয় হল যে এই ধরনের নির্ভরতাগুলি নির্মাণের সময় পরিচিত হয়। আমরা আমাদের এইচটিএমএল পাওয়ার সাথে সাথে সমস্ত নির্ভরতা লোড হওয়া শুরু করে তা নিশ্চিত করতে আমরা <link rel="preload">
ট্যাগ ব্যবহার করতে পারি।
ফলাফল
আমাদের পরিবর্তনগুলি কী অর্জন করেছে তা একবার দেখে নেওয়া যাক। আমাদের পরীক্ষার সেটআপে অন্য কোনও ভেরিয়েবল পরিবর্তন না করা গুরুত্বপূর্ণ যা ফলাফলগুলিকে তির্যক করতে পারে, তাই আমরা এই নিবন্ধের বাকি অংশের জন্য WebPageTest এর সাধারণ সেটআপ ব্যবহার করব এবং ফিল্মস্ট্রিপটি দেখব:
এই পরিবর্তনগুলি আমাদের TTI 11 থেকে 8.5 এ কমিয়েছে , যা মোটামুটিভাবে সংযোগ সেটআপের 2.5 সেকেন্ড যা আমরা অপসারণের লক্ষ্য রেখেছি। ভাল হয়েছে আমাদের.
প্রি-রেন্ডারিং
যদিও আমরা সবেমাত্র আমাদের TTI কমিয়েছি, আমরা সত্যিই চিরকালের দীর্ঘ সাদা স্ক্রীনকে প্রভাবিত করিনি যা ব্যবহারকারীকে 8.5 সেকেন্ডের জন্য সহ্য করতে হয়। আপনার index.html
এ স্টাইল করা মার্কআপ পাঠিয়ে FMP-এর জন্য সবচেয়ে বড় উন্নতি করা যেতে পারে । এটি অর্জনের সাধারণ কৌশলগুলি হল প্রিরেন্ডারিং এবং সার্ভার-সাইড রেন্ডারিং, যা ঘনিষ্ঠভাবে সম্পর্কিত এবং ওয়েবে রেন্ডারিং -এ ব্যাখ্যা করা হয়েছে। উভয় কৌশলই নোডে ওয়েব অ্যাপ চালায় এবং ফলস্বরূপ DOM-কে HTML-এ সিরিয়ালাইজ করে। সার্ভার-সাইড রেন্ডারিং, ভাল, সার্ভার সাইডে অনুরোধ অনুসারে এটি করে, যখন প্রি-রেন্ডারিং বিল্ড টাইমে এটি করে এবং আউটপুটটিকে আপনার নতুন index.html
হিসাবে সংরক্ষণ করে। যেহেতু PROXX একটি JAMStack অ্যাপ এবং এর কোনো সার্ভার সাইড নেই, তাই আমরা প্রি-রেন্ডারিং বাস্তবায়ন করার সিদ্ধান্ত নিয়েছি।
প্রি-রেন্ডারার বাস্তবায়নের অনেক উপায় আছে। PROXX-এ আমরা Puppeteer ব্যবহার করা বেছে নিয়েছি, যা কোনো UI ছাড়াই ক্রোম শুরু করে এবং আপনাকে নোড API-এর সাহায্যে সেই উদাহরণটিকে রিমোট কন্ট্রোল করার অনুমতি দেয়। আমরা আমাদের মার্কআপ এবং আমাদের জাভাস্ক্রিপ্ট ইনজেক্ট করার জন্য এটি ব্যবহার করি এবং তারপর এইচটিএমএল এর একটি স্ট্রিং হিসাবে DOM কে আবার পড়ি। যেহেতু আমরা CSS মডিউল ব্যবহার করছি, আমরা বিনামূল্যের জন্য আমাদের প্রয়োজনীয় শৈলীগুলির CSS ইনলাইনিং পাই।
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(rawIndexHTML);
await page.evaluate(codeToRun);
const renderedHTML = await page.content();
browser.close();
await writeFile("index.html", renderedHTML);
এটির সাথে, আমরা আমাদের FMP-এর জন্য একটি উন্নতি আশা করতে পারি। আমাদের এখনও আগের মতো একই পরিমাণ জাভাস্ক্রিপ্ট লোড এবং এক্সিকিউট করতে হবে, তাই আমাদের টিটিআই খুব বেশি পরিবর্তনের আশা করা উচিত নয়। যদি কিছু হয়, আমাদের index.html
বড় হয়েছে এবং আমাদের TTI কে কিছুটা পিছিয়ে দিতে পারে। খুঁজে বের করার একমাত্র উপায় আছে: ওয়েবপেজটেস্ট চালানো।
আমাদের প্রথম অর্থপূর্ণ পেইন্ট 8.5 সেকেন্ড থেকে 4.9 সেকেন্ডে চলে গেছে, একটি ব্যাপক উন্নতি। আমাদের TTI এখনও প্রায় 8.5 সেকেন্ডে ঘটে তাই এটি এই পরিবর্তনের দ্বারা অনেকাংশে প্রভাবিত হয়নি। আমরা এখানে যা করেছি তা একটি উপলব্ধিগত পরিবর্তন। কেউ কেউ এটাকে হাতের তুচ্ছতাচ্ছিল্যও বলতে পারে। গেমের একটি মধ্যবর্তী ভিজ্যুয়াল রেন্ডার করার মাধ্যমে, আমরা অনুভূত লোডিং কর্মক্ষমতা আরও ভাল করার জন্য পরিবর্তন করছি।
ইনলাইনিং
আরেকটি মেট্রিক যা DevTools এবং WebPageTest উভয়ই আমাদের দেয় তা হল টাইম টু ফার্স্ট বাইট (TTFB) । রিকোয়েস্ট পাঠানোর প্রথম বাইট থেকে সাড়া পাওয়ার প্রথম বাইট পর্যন্ত এই সময় লাগে। এই সময়টিকে প্রায়ই রাউন্ড ট্রিপ টাইম (RTT) বলা হয়, যদিও প্রযুক্তিগতভাবে এই দুটি সংখ্যার মধ্যে পার্থক্য রয়েছে: RTT সার্ভারের দিকে অনুরোধের প্রক্রিয়াকরণের সময় অন্তর্ভুক্ত করে না। DevTools এবং WebPageTest অনুরোধ/প্রতিক্রিয়া ব্লকের মধ্যে হালকা রঙের সাথে TTFB কে কল্পনা করে।
আমাদের জলপ্রপাতের দিকে তাকিয়ে, আমরা দেখতে পাচ্ছি যে সমস্ত অনুরোধ তাদের বেশিরভাগ সময় ব্যয় করে প্রতিক্রিয়ার প্রথম বাইট আসার অপেক্ষায় ।
এই সমস্যাটি HTTP/2 পুশের জন্য মূলত ধারণা করা হয়েছিল। অ্যাপ ডেভেলপার জানেন যে নির্দিষ্ট সংস্থানগুলির প্রয়োজন এবং সেগুলিকে তারের নিচে ঠেলে দিতে পারে৷ ক্লায়েন্ট যখন বুঝতে পারে যে এটিকে অতিরিক্ত সংস্থান আনতে হবে, তারা ইতিমধ্যেই ব্রাউজারের ক্যাশে রয়েছে৷ এইচটিটিপি/2 পুশ সঠিক হওয়া খুব কঠিন বলে প্রমাণিত হয় এবং এটিকে নিরুৎসাহিত করা হয়। HTTP/3 এর প্রমিতকরণের সময় এই সমস্যা স্থানটি পুনরায় দেখা হবে। আপাতত, সবচেয়ে সহজ সমাধান হল ক্যাশিং দক্ষতার খরচে সমস্ত গুরুত্বপূর্ণ সংস্থান ইনলাইন করা ।
আমাদের সমালোচনামূলক CSS ইতিমধ্যেই ইনলাইন করা হয়েছে CSS মডিউল এবং আমাদের Puppeteer-ভিত্তিক প্রিরেন্ডারারকে ধন্যবাদ। জাভাস্ক্রিপ্টের জন্য আমাদের গুরুত্বপূর্ণ মডিউল এবং তাদের নির্ভরতা ইনলাইন করতে হবে। আপনি যে বান্ডলার ব্যবহার করছেন তার উপর ভিত্তি করে এই কাজটিতে বিভিন্ন অসুবিধা রয়েছে।
এটি আমাদের TTI বন্ধ 1 সেকেন্ড চাঁচা. আমরা এখন এমন পর্যায়ে পৌঁছেছি যেখানে আমাদের index.html
প্রাথমিক রেন্ডার এবং ইন্টারেক্টিভ হওয়ার জন্য প্রয়োজনীয় সবকিছু রয়েছে। এইচটিএমএল এখনও ডাউনলোড করার সময় রেন্ডার করতে পারে, আমাদের এফএমপি তৈরি করে। যে মুহূর্তে HTML পার্সিং এবং এক্সিকিউট করা হয়, অ্যাপটি ইন্টারেক্টিভ হয়।
আক্রমনাত্মক কোড বিভাজন
হ্যাঁ, আমাদের index.html
ইন্টারেক্টিভ হওয়ার জন্য প্রয়োজনীয় সবকিছু রয়েছে। কিন্তু ঘনিষ্ঠভাবে পরিদর্শন করলে দেখা যায় এতে অন্য সব কিছু রয়েছে। আমাদের index.html
প্রায় 43 KB. চলুন শুরুতে ব্যবহারকারীর সাথে কী ইন্টারঅ্যাক্ট করতে পারে তার সাথে সম্পর্কিত করা যাক: গেমটি কনফিগার করার জন্য আমাদের কাছে কয়েকটি উপাদান, একটি স্টার্ট বোতাম এবং ব্যবহারকারীর সেটিংস টিকে থাকার এবং লোড করার জন্য সম্ভবত কিছু কোড রয়েছে। যে বেশ এটা. 43 KB অনেকটা মনে হচ্ছে।

আমাদের বান্ডেলের আকার কোথা থেকে আসছে তা বোঝার জন্য আমরা একটি সোর্স ম্যাপ এক্সপ্লোরার বা অনুরূপ টুল ব্যবহার করতে পারি যা বান্ডিলটিতে কী আছে তা ভেঙে দিতে পারি। যেমন ভবিষ্যদ্বাণী করা হয়েছে, আমাদের বান্ডেলে রয়েছে গেম লজিক, রেন্ডারিং ইঞ্জিন, উইন স্ক্রিন, লস স্ক্রিন এবং একগুচ্ছ ইউটিলিটি। ল্যান্ডিং পৃষ্ঠার জন্য এই মডিউলগুলির শুধুমাত্র একটি ছোট উপসেট প্রয়োজন। অলসভাবে লোড করা মডিউলে ইন্টারঅ্যাক্টিভিটির জন্য কঠোরভাবে প্রয়োজনীয় নয় এমন সমস্ত কিছু স্থানান্তরিত করা TTI উল্লেখযোগ্যভাবে হ্রাস পাবে।
আমাদের যা করতে হবে তা হল কোড বিভক্ত । কোড স্প্লিটিং আপনার একচেটিয়া বান্ডিলকে ছোট ছোট অংশে বিভক্ত করে যা অলস-লোড-অন-ডিমান্ড হতে পারে। জনপ্রিয় বান্ডলার যেমন ওয়েবপ্যাক , রোলআপ , এবং পার্সেল সমর্থন কোড বিভাজন ডায়নামিক import()
ব্যবহার করে। বান্ডলার আপনার কোড বিশ্লেষণ করবে এবং স্ট্যাটিকভাবে আমদানি করা সমস্ত মডিউল ইনলাইন করবে । আপনি যা কিছু গতিশীলভাবে আমদানি করবেন তার নিজস্ব ফাইলে রাখা হবে এবং import()
কলটি কার্যকর হলেই কেবল নেটওয়ার্ক থেকে আনা হবে। অবশ্যই নেটওয়ার্কে আঘাত করার একটি খরচ আছে এবং আপনার হাতে সময় থাকলেই তা করা উচিত। এখানে মন্ত্রটি হল লোডের সময় সমালোচনামূলকভাবে প্রয়োজনীয় মডিউলগুলিকে স্ট্যাটিকভাবে আমদানি করা এবং অন্য সব কিছুকে গতিশীলভাবে লোড করা। তবে আপনার অলস-লোড মডিউলগুলির জন্য একেবারে শেষ মুহুর্ত পর্যন্ত অপেক্ষা করা উচিত নয় যা অবশ্যই ব্যবহার করা হবে। ফিল ওয়ালটনের Idle Until Urgent অলস লোডিং এবং আগ্রহী লোডিংয়ের মধ্যে একটি স্বাস্থ্যকর মধ্যম স্থলের জন্য একটি দুর্দান্ত প্যাটার্ন।
PROXX-এ আমরা একটি lazy.js
ফাইল তৈরি করেছি যা স্ট্যাটিকভাবে আমাদের প্রয়োজন নেই এমন সবকিছু আমদানি করে। আমাদের প্রধান ফাইলে, আমরা গতিশীলভাবে lazy.js
আমদানি করতে পারি। যাইহোক, আমাদের কিছু Preact কম্পোনেন্ট lazy.js
এ শেষ হয়েছে, যা কিছুটা জটিলতার মধ্যে পরিণত হয়েছে কারণ Preact বাক্সের বাইরে অলসভাবে লোড করা উপাদানগুলি পরিচালনা করতে পারে না। এই কারণে আমরা একটি সামান্য deferred
কম্পোনেন্ট র্যাপার লিখেছি যা প্রকৃত কম্পোনেন্ট লোড না হওয়া পর্যন্ত আমাদের একটি স্থানধারক রেন্ডার করতে দেয়।
export default function deferred(componentPromise) {
return class Deferred extends Component {
constructor(props) {
super(props);
this.state = {
LoadedComponent: undefined
};
componentPromise.then(component => {
this.setState({ LoadedComponent: component });
});
}
render({ loaded, loading }, { LoadedComponent }) {
if (LoadedComponent) {
return loaded(LoadedComponent);
}
return loading();
}
};
}
এটির সাথে, আমরা আমাদের render()
ফাংশনে একটি কম্পোনেন্টের প্রতিশ্রুতি ব্যবহার করতে পারি। উদাহরণস্বরূপ, <Nebula>
উপাদান, যা অ্যানিমেটেড ব্যাকগ্রাউন্ড ইমেজ রেন্ডার করে, কম্পোনেন্টটি লোড হওয়ার সময় একটি খালি <div>
দ্বারা প্রতিস্থাপিত হবে। কম্পোনেন্ট লোড হয়ে গেলে এবং ব্যবহারের জন্য প্রস্তুত হলে, <div>
আসল কম্পোনেন্ট দিয়ে প্রতিস্থাপিত হবে।
const NebulaDeferred = deferred(
import("/components/nebula").then(m => m.default)
);
return (
// ...
<NebulaDeferred
loading={() => <div />}
loaded={Nebula => <Nebula />}
/>
);
এই সব জায়গায় রেখে, আমরা আমাদের index.html
কে কমিয়েছি মাত্র 20 KB, আসল আকারের অর্ধেকেরও কম। এটি এফএমপি এবং টিটিআই-এর উপর কী প্রভাব ফেলে? WebPageTest বলে দেবে!
আমাদের FMP এবং TTI শুধুমাত্র 100ms দূরে, কারণ এটি শুধুমাত্র ইনলাইন করা জাভাস্ক্রিপ্ট পার্সিং এবং এক্সিকিউট করার বিষয়। 2G-তে মাত্র 5.4s পরে, অ্যাপটি সম্পূর্ণ ইন্টারেক্টিভ। অন্য সব, কম প্রয়োজনীয় মডিউল পটভূমিতে লোড করা হয়।
হাতের আরও স্লাইট
আপনি যদি উপরে আমাদের সমালোচনামূলক মডিউলগুলির তালিকাটি দেখেন তবে আপনি দেখতে পাবেন যে রেন্ডারিং ইঞ্জিনটি সমালোচনামূলক মডিউলগুলির অংশ নয়৷ অবশ্যই, গেমটি রেন্ডার করার জন্য আমাদের রেন্ডারিং ইঞ্জিন না হওয়া পর্যন্ত গেমটি শুরু করা যাবে না। আমাদের রেন্ডারিং ইঞ্জিন গেমটি শুরু করার জন্য প্রস্তুত না হওয়া পর্যন্ত আমরা "স্টার্ট" বোতামটি অক্ষম করতে পারি, তবে আমাদের অভিজ্ঞতায় ব্যবহারকারী সাধারণত তাদের গেম সেটিংস কনফিগার করতে যথেষ্ট সময় নেয় যে এটি প্রয়োজনীয় নয়। বেশিরভাগ সময় রেন্ডারিং ইঞ্জিন এবং অন্যান্য অবশিষ্ট মডিউলগুলি লোড করা হয় যখন ব্যবহারকারী "স্টার্ট" চাপেন। বিরল ক্ষেত্রে যে ব্যবহারকারী তাদের নেটওয়ার্ক সংযোগের চেয়ে দ্রুত, আমরা একটি সাধারণ লোডিং স্ক্রিন দেখাই যা অবশিষ্ট মডিউলগুলি শেষ হওয়ার জন্য অপেক্ষা করে।
উপসংহার
পরিমাপ গুরুত্বপূর্ণ। বাস্তব নয় এমন সমস্যায় সময় ব্যয় এড়াতে, আমরা সর্বদা অপ্টিমাইজেশান প্রয়োগ করার আগে প্রথমে পরিমাপ করার পরামর্শ দিই। অতিরিক্তভাবে, পরিমাপ করা উচিত বাস্তব ডিভাইসে 3G সংযোগে বা WebPageTest- এ যদি কোনো বাস্তব ডিভাইস হাতে না থাকে।
ফিল্মস্ট্রিপ আপনার অ্যাপ লোড করা ব্যবহারকারীর জন্য কেমন অনুভব করে তার অন্তর্দৃষ্টি দিতে পারে। জলপ্রপাতটি আপনাকে বলতে পারে যে সম্ভাব্য দীর্ঘ লোডিং সময়ের জন্য কোন সংস্থানগুলি দায়ী। লোডিং কর্মক্ষমতা উন্নত করতে আপনি যা করতে পারেন তার একটি চেকলিস্ট এখানে রয়েছে:
- একটি সংযোগে যতটা সম্ভব সম্পদ সরবরাহ করুন।
- প্রিলোড বা এমনকি ইনলাইন সংস্থান যা প্রথম রেন্ডার এবং ইন্টারঅ্যাক্টিভিটির জন্য প্রয়োজনীয়।
- অনুভূত লোডিং কর্মক্ষমতা উন্নত করতে আপনার অ্যাপ প্রি-রেন্ডার করুন।
- ইন্টারঅ্যাক্টিভিটির জন্য প্রয়োজনীয় কোডের পরিমাণ কমাতে আক্রমণাত্মক কোড বিভাজন ব্যবহার করুন।
পার্ট 2 এর জন্য সাথে থাকুন যেখানে আমরা হাইপার-সংবদ্ধ ডিভাইসগুলিতে রানটাইম পারফরম্যান্সকে কীভাবে অপ্টিমাইজ করতে হয় তা নিয়ে আলোচনা করব।
,কিভাবে আমরা PROXX এ কোড স্প্লিটিং, কোড ইনলাইনিং এবং সার্ভার-সাইড রেন্ডারিং ব্যবহার করেছি।
Google I/O 2019 এ Mariko, Jake, এবং আমি PROXX পাঠিয়েছি, ওয়েবের জন্য একটি আধুনিক মাইনসুইপার-ক্লোন। এমন কিছু যা PROXX কে আলাদা করে তা হল অ্যাক্সেসিবিলিটির উপর ফোকাস (আপনি এটি একটি স্ক্রিনরিডার দিয়ে চালাতে পারেন!) এবং হাই-এন্ড ডেস্কটপ ডিভাইসের মতো ফিচার ফোনেও চালানোর ক্ষমতা। ফিচার ফোন একাধিক উপায়ে সীমাবদ্ধ:
- দুর্বল সিপিইউ
- দুর্বল বা অস্তিত্বহীন জিপিইউ
- স্পর্শ ইনপুট ছাড়া ছোট পর্দা
- মেমরি খুব সীমিত পরিমাণ
কিন্তু তারা একটি আধুনিক ব্রাউজার চালায় এবং খুব সাশ্রয়ী মূল্যের। এই কারণে, ফিচার ফোনগুলি উদীয়মান বাজারে একটি পুনরুত্থান ঘটাচ্ছে। তাদের মূল্য বিন্দু একটি সম্পূর্ণ নতুন শ্রোতাদের অনুমতি দেয়, যারা আগে এটি বহন করতে পারেনি, অনলাইনে আসতে এবং আধুনিক ওয়েব ব্যবহার করতে পারে৷ 2019 এর জন্য এটি অনুমান করা হয়েছে যে প্রায় 400 মিলিয়ন ফিচার ফোন শুধুমাত্র ভারতেই বিক্রি হবে , তাই ফিচার ফোনের ব্যবহারকারীরা আপনার দর্শকদের একটি উল্লেখযোগ্য অংশ হয়ে উঠতে পারে। তা ছাড়াও, 2G-এর মতো সংযোগের গতি উদীয়মান বাজারে আদর্শ। আমরা কীভাবে ফিচার ফোনের শর্তে PROXX কে ভালভাবে কাজ করতে পরিচালনা করেছি?
পারফরম্যান্স গুরুত্বপূর্ণ, এবং এতে লোডিং পারফরম্যান্স এবং রানটাইম পারফরম্যান্স উভয়ই অন্তর্ভুক্ত। এটি দেখানো হয়েছে যে ভাল পারফরম্যান্স বর্ধিত ব্যবহারকারীর ধারণ, উন্নত রূপান্তর এবং সবচেয়ে গুরুত্বপূর্ণভাবে-বর্ধিত অন্তর্ভুক্তির সাথে সম্পর্কযুক্ত। কেন পারফরম্যান্স গুরুত্বপূর্ণ সে সম্পর্কে জেরেমি ওয়াগনারের অনেক বেশি ডেটা এবং অন্তর্দৃষ্টি রয়েছে৷
এটি একটি দুই পর্বের সিরিজের পার্ট 1। পার্ট 1 লোডিং পারফরম্যান্সের উপর ফোকাস করে , এবং পার্ট 2 রানটাইম পারফরম্যান্সের উপর ফোকাস করবে।
স্থিতাবস্থা ক্যাপচার করা
একটি বাস্তব ডিভাইসে আপনার লোডিং কর্মক্ষমতা পরীক্ষা করা গুরুত্বপূর্ণ। যদি আপনার হাতে একটি বাস্তব ডিভাইস না থাকে, আমি সুপারিশ করি WebPageTest , বিশেষ করে "সহজ" সেটআপ । WPT একটি ইমুলেটেড 3G সংযোগ সহ একটি বাস্তব ডিভাইসে লোডিং পরীক্ষার একটি ব্যাটারি চালায়।
3G একটি ভাল গতি পরিমাপ. যদিও আপনি 4G, LTE বা শীঘ্রই এমনকি 5G-তে অভ্যস্ত হতে পারেন, মোবাইল ইন্টারনেটের বাস্তবতা বেশ ভিন্ন দেখায়। হতে পারে আপনি একটি ট্রেনে, একটি সম্মেলনে, একটি কনসার্টে, বা একটি ফ্লাইটে। আপনি সেখানে যা অনুভব করবেন তা সম্ভবত 3G এর কাছাকাছি এবং কখনও কখনও আরও খারাপ।
বলা হচ্ছে, আমরা এই নিবন্ধে 2G-এর উপর ফোকাস করতে যাচ্ছি কারণ PROXX স্পষ্টভাবে ফিচার ফোন এবং উদীয়মান বাজারগুলিকে তার লক্ষ্য দর্শকদের মধ্যে টার্গেট করছে। WebPageTest এর পরীক্ষা চালানো হয়ে গেলে, আপনি একটি জলপ্রপাত (আপনি DevTools-এ যা দেখেন তার অনুরূপ) পাশাপাশি শীর্ষে একটি ফিল্মস্ট্রিপ পাবেন। ফিল্ম স্ট্রিপ দেখায় যে আপনার অ্যাপ লোড হওয়ার সময় আপনার ব্যবহারকারী কী দেখেন। 2G-তে, PROXX-এর অপ্টিমাইজ করা সংস্করণের লোডিং অভিজ্ঞতা বেশ খারাপ:
3G এর উপর লোড করা হলে, ব্যবহারকারী 4 সেকেন্ডের সাদা শূন্যতা দেখতে পান। 2G-এর উপরে ব্যবহারকারী 8 সেকেন্ডের জন্য একেবারে কিছুই দেখতে পায় না। কর্মক্ষমতা কেন গুরুত্বপূর্ণ তা যদি আপনি পড়েন তবে আপনি জানেন যে আমরা এখন অধৈর্যতার কারণে আমাদের সম্ভাব্য ব্যবহারকারীদের একটি ভাল অংশ হারিয়ে ফেলেছি। স্ক্রিনে কিছু দেখাতে ব্যবহারকারীকে 62 KB জাভাস্ক্রিপ্টের সমস্ত ডাউনলোড করতে হবে। এই দৃশ্যের রূপালী আস্তরণ হল যে দ্বিতীয় কিছু পর্দায় প্রদর্শিত হয় এটিও ইন্টারেক্টিভ। নাকি এটা?

প্রায় 62 KB gzip'd JS ডাউনলোড হওয়ার পরে এবং DOM তৈরি হওয়ার পরে, ব্যবহারকারী আমাদের অ্যাপটি দেখতে পাবেন। অ্যাপটি প্রযুক্তিগতভাবে ইন্টারেক্টিভ। তবে ভিজ্যুয়াল দেখলে ভিন্ন বাস্তবতা দেখা যায়। ওয়েব ফন্টগুলি এখনও ব্যাকগ্রাউন্ডে লোড হচ্ছে এবং তারা প্রস্তুত না হওয়া পর্যন্ত ব্যবহারকারী কোনও পাঠ্য দেখতে পাবে না। যদিও এই স্টেটটি ফার্স্ট মিনিংফুল পেইন্ট (FMP) হিসাবে যোগ্যতা অর্জন করে, এটি অবশ্যই সঠিকভাবে ইন্টারেক্টিভ হিসাবে যোগ্যতা অর্জন করে না, কারণ ব্যবহারকারী বলতে পারে না যে কোন ইনপুটগুলি কী। অ্যাপটি চালু না হওয়া পর্যন্ত এটি 3G-তে আরও একটি সেকেন্ড এবং 2G-তে 3 সেকেন্ড সময় নেয়। সব মিলিয়ে, অ্যাপটি ইন্টারেক্টিভ হতে 3G-তে 6 সেকেন্ড এবং 2G-তে 11 সেকেন্ড সময় নেয়।
জলপ্রপাত বিশ্লেষণ
এখন যেহেতু আমরা জানি ব্যবহারকারী কী দেখে, আমাদের কেন তা খুঁজে বের করতে হবে। এর জন্য আমরা জলপ্রপাতটি দেখতে পারি এবং বিশ্লেষণ করতে পারি কেন সংস্থানগুলি খুব দেরিতে লোড হচ্ছে। PROXX-এর জন্য আমাদের 2G ট্রেসে আমরা দুটি প্রধান লাল পতাকা দেখতে পাচ্ছি:
- একাধিক, বহু রঙের পাতলা লাইন আছে।
- জাভাস্ক্রিপ্ট ফাইল একটি চেইন গঠন করে। উদাহরণস্বরূপ, প্রথম সংস্থানটি শেষ হওয়ার পরে দ্বিতীয় সংস্থানটি কেবলমাত্র লোড হওয়া শুরু করে এবং দ্বিতীয় সংস্থানটি শেষ হলেই তৃতীয় সংস্থানটি শুরু হয়।

সংযোগের সংখ্যা হ্রাস করা
প্রতিটি পাতলা লাইন ( dns
, connect
, ssl
) একটি নতুন HTTP সংযোগ তৈরির জন্য দাঁড়ায়। একটি নতুন সংযোগ সেট আপ করা ব্যয়বহুল কারণ এটি 3G তে প্রায় 1s এবং 2G তে প্রায় 2.5s লাগে৷ আমাদের জলপ্রপাতে আমরা এর জন্য একটি নতুন সংযোগ দেখতে পাচ্ছি:
- অনুরোধ #1: আমাদের
index.html
- অনুরোধ #5:
fonts.googleapis.com
থেকে ফন্ট শৈলী - অনুরোধ #8: Google Analytics
- অনুরোধ #9:
fonts.gstatic.com
থেকে একটি ফন্ট ফাইল - অনুরোধ #14: ওয়েব অ্যাপ ম্যানিফেস্ট
index.html
এর জন্য নতুন সংযোগ অনিবার্য। বিষয়বস্তু পেতে ব্রাউজারকে আমাদের সার্ভারের সাথে একটি সংযোগ তৈরি করতে হবে । Google Analytics-এর জন্য নতুন সংযোগটি Minimal Analytics-এর মতো কিছু ইনলাইন করে এড়ানো যেতে পারে, কিন্তু Google Analytics আমাদের অ্যাপকে রেন্ডারিং বা ইন্টারেক্টিভ হতে বাধা দিচ্ছে না, তাই এটি কত দ্রুত লোড হয় সে বিষয়ে আমরা সত্যিই চিন্তা করি না। আদর্শভাবে, Google Analytics অলস সময়ে লোড করা উচিত, যখন বাকি সবকিছু ইতিমধ্যে লোড হয়ে গেছে। এইভাবে এটি প্রাথমিক লোডের সময় ব্যান্ডউইথ বা প্রক্রিয়াকরণ শক্তি গ্রহণ করবে না। ওয়েব অ্যাপ ম্যানিফেস্টের জন্য নতুন সংযোগ ফেচ স্পেক দ্বারা নির্ধারিত হয়, কারণ ম্যানিফেস্টটিকে একটি অ-প্রমাণপত্রবিহীন সংযোগে লোড করতে হবে৷ আবার, ওয়েব অ্যাপ ম্যানিফেস্ট আমাদের অ্যাপকে রেন্ডারিং বা ইন্টারেক্টিভ হতে বাধা দেয় না, তাই আমাদের এতটা যত্ন নেওয়ার দরকার নেই।
দুটি ফন্ট এবং তাদের শৈলী, তবে, একটি সমস্যা কারণ তারা রেন্ডারিং এবং ইন্টারঅ্যাক্টিভিটি ব্লক করে। আমরা যদি fonts.googleapis.com
দ্বারা বিতরণ করা CSS-এর দিকে তাকাই, তবে এটি শুধুমাত্র দুটি @font-face
নিয়ম, প্রতিটি ফন্টের জন্য একটি। ফন্ট শৈলীগুলি আসলে এতই ছোট যে আমরা একটি অপ্রয়োজনীয় সংযোগ সরিয়ে এটিকে আমাদের HTML এ ইনলাইন করার সিদ্ধান্ত নিয়েছি। ফন্ট ফাইলগুলির জন্য সংযোগ সেটআপের খরচ এড়াতে, আমরা সেগুলিকে আমাদের নিজস্ব সার্ভারে অনুলিপি করতে পারি।
সমান্তরাল লোড
জলপ্রপাতের দিকে তাকিয়ে, আমরা দেখতে পাচ্ছি যে একবার প্রথম জাভাস্ক্রিপ্ট ফাইলটি লোড হওয়ার পরে, নতুন ফাইলগুলি অবিলম্বে লোড হতে শুরু করে। এটি মডিউল নির্ভরতার জন্য সাধারণ। আমাদের প্রধান মডিউলে সম্ভবত স্ট্যাটিক ইম্পোর্ট আছে, তাই সেই ইম্পোর্ট লোড না হওয়া পর্যন্ত JavaScript চলতে পারে না। এখানে উপলব্ধি করা গুরুত্বপূর্ণ বিষয় হল যে এই ধরনের নির্ভরতাগুলি নির্মাণের সময় পরিচিত হয়। আমরা আমাদের এইচটিএমএল পাওয়ার সাথে সাথে সমস্ত নির্ভরতা লোড হওয়া শুরু করে তা নিশ্চিত করতে আমরা <link rel="preload">
ট্যাগ ব্যবহার করতে পারি।
ফলাফল
আমাদের পরিবর্তনগুলি কী অর্জন করেছে তা একবার দেখে নেওয়া যাক। আমাদের পরীক্ষার সেটআপে অন্য কোনও ভেরিয়েবল পরিবর্তন না করা গুরুত্বপূর্ণ যা ফলাফলগুলিকে তির্যক করতে পারে, তাই আমরা এই নিবন্ধের বাকি অংশের জন্য WebPageTest এর সাধারণ সেটআপ ব্যবহার করব এবং ফিল্মস্ট্রিপটি দেখব:
এই পরিবর্তনগুলি আমাদের TTI 11 থেকে 8.5 এ কমিয়েছে , যা মোটামুটিভাবে সংযোগ সেটআপের 2.5 সেকেন্ড যা আমরা অপসারণের লক্ষ্য রেখেছি। ভাল হয়েছে আমাদের.
প্রি-রেন্ডারিং
যদিও আমরা সবেমাত্র আমাদের TTI কমিয়েছি, আমরা সত্যিই চিরকালের দীর্ঘ সাদা স্ক্রীনকে প্রভাবিত করিনি যা ব্যবহারকারীকে 8.5 সেকেন্ডের জন্য সহ্য করতে হয়। আপনার index.html
এ স্টাইল করা মার্কআপ পাঠিয়ে FMP-এর জন্য সবচেয়ে বড় উন্নতি করা যেতে পারে । এটি অর্জনের সাধারণ কৌশলগুলি হল প্রিরেন্ডারিং এবং সার্ভার-সাইড রেন্ডারিং, যা ঘনিষ্ঠভাবে সম্পর্কিত এবং ওয়েবে রেন্ডারিং -এ ব্যাখ্যা করা হয়েছে। উভয় কৌশলই নোডে ওয়েব অ্যাপ চালায় এবং ফলস্বরূপ DOM-কে HTML-এ সিরিয়ালাইজ করে। সার্ভার-সাইড রেন্ডারিং, ভাল, সার্ভার সাইডে অনুরোধ অনুসারে এটি করে, যখন প্রি-রেন্ডারিং বিল্ড টাইমে এটি করে এবং আউটপুটটিকে আপনার নতুন index.html
হিসাবে সংরক্ষণ করে। যেহেতু PROXX একটি JAMStack অ্যাপ এবং এর কোনো সার্ভার সাইড নেই, তাই আমরা প্রি-রেন্ডারিং বাস্তবায়ন করার সিদ্ধান্ত নিয়েছি।
প্রি-রেন্ডারার বাস্তবায়নের অনেক উপায় আছে। PROXX-এ আমরা Puppeteer ব্যবহার করা বেছে নিয়েছি, যা কোনো UI ছাড়াই ক্রোম শুরু করে এবং আপনাকে নোড API-এর সাহায্যে সেই উদাহরণটিকে রিমোট কন্ট্রোল করার অনুমতি দেয়। আমরা আমাদের মার্কআপ এবং আমাদের জাভাস্ক্রিপ্ট ইনজেক্ট করার জন্য এটি ব্যবহার করি এবং তারপর এইচটিএমএল এর একটি স্ট্রিং হিসাবে DOM কে আবার পড়ি। যেহেতু আমরা CSS মডিউল ব্যবহার করছি, আমরা বিনামূল্যের জন্য আমাদের প্রয়োজনীয় শৈলীগুলির CSS ইনলাইনিং পাই।
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(rawIndexHTML);
await page.evaluate(codeToRun);
const renderedHTML = await page.content();
browser.close();
await writeFile("index.html", renderedHTML);
এটির সাথে, আমরা আমাদের FMP-এর জন্য একটি উন্নতি আশা করতে পারি। আমাদের এখনও আগের মতো একই পরিমাণ জাভাস্ক্রিপ্ট লোড এবং এক্সিকিউট করতে হবে, তাই আমাদের টিটিআই খুব বেশি পরিবর্তনের আশা করা উচিত নয়। যদি কিছু হয়, আমাদের index.html
বড় হয়েছে এবং আমাদের TTI কে কিছুটা পিছিয়ে দিতে পারে। খুঁজে বের করার একমাত্র উপায় আছে: ওয়েবপেজটেস্ট চালানো।
আমাদের প্রথম অর্থপূর্ণ পেইন্ট 8.5 সেকেন্ড থেকে 4.9 সেকেন্ডে চলে গেছে, একটি ব্যাপক উন্নতি। আমাদের TTI এখনও প্রায় 8.5 সেকেন্ডে ঘটে তাই এটি এই পরিবর্তনের দ্বারা অনেকাংশে প্রভাবিত হয়নি। আমরা এখানে যা করেছি তা একটি উপলব্ধিগত পরিবর্তন। কেউ কেউ এটাকে হাতের তুচ্ছতাচ্ছিল্যও বলতে পারে। গেমের একটি মধ্যবর্তী ভিজ্যুয়াল রেন্ডার করার মাধ্যমে, আমরা অনুভূত লোডিং কর্মক্ষমতা আরও ভাল করার জন্য পরিবর্তন করছি।
ইনলাইনিং
আরেকটি মেট্রিক যা DevTools এবং WebPageTest উভয়ই আমাদের দেয় তা হল টাইম টু ফার্স্ট বাইট (TTFB) । রিকোয়েস্ট পাঠানোর প্রথম বাইট থেকে সাড়া পাওয়ার প্রথম বাইট পর্যন্ত এই সময় লাগে। এই সময়টিকে প্রায়ই রাউন্ড ট্রিপ টাইম (RTT) বলা হয়, যদিও প্রযুক্তিগতভাবে এই দুটি সংখ্যার মধ্যে পার্থক্য রয়েছে: RTT সার্ভারের দিকে অনুরোধের প্রক্রিয়াকরণের সময় অন্তর্ভুক্ত করে না। DevTools এবং WebPageTest অনুরোধ/প্রতিক্রিয়া ব্লকের মধ্যে হালকা রঙের সাথে TTFB কে কল্পনা করে।
আমাদের জলপ্রপাতের দিকে তাকিয়ে, আমরা দেখতে পাচ্ছি যে সমস্ত অনুরোধ তাদের বেশিরভাগ সময় ব্যয় করে প্রতিক্রিয়ার প্রথম বাইট আসার অপেক্ষায় ।
এই সমস্যাটি HTTP/2 পুশের জন্য মূলত ধারণা করা হয়েছিল। অ্যাপ ডেভেলপার জানেন যে নির্দিষ্ট সংস্থানগুলির প্রয়োজন এবং সেগুলিকে তারের নিচে ঠেলে দিতে পারে৷ ক্লায়েন্ট যখন বুঝতে পারে যে এটিকে অতিরিক্ত সংস্থান আনতে হবে, তারা ইতিমধ্যেই ব্রাউজারের ক্যাশে রয়েছে৷ এইচটিটিপি/2 পুশ সঠিক হওয়া খুব কঠিন বলে প্রমাণিত হয় এবং এটিকে নিরুৎসাহিত করা হয়। HTTP/3 এর প্রমিতকরণের সময় এই সমস্যা স্থানটি পুনরায় দেখা হবে। আপাতত, সবচেয়ে সহজ সমাধান হল ক্যাশিং দক্ষতার খরচে সমস্ত গুরুত্বপূর্ণ সংস্থান ইনলাইন করা ।
আমাদের সমালোচনামূলক CSS ইতিমধ্যেই ইনলাইন করা হয়েছে CSS মডিউল এবং আমাদের Puppeteer-ভিত্তিক প্রিরেন্ডারারকে ধন্যবাদ। জাভাস্ক্রিপ্টের জন্য আমাদের গুরুত্বপূর্ণ মডিউল এবং তাদের নির্ভরতা ইনলাইন করতে হবে। আপনি যে বান্ডলার ব্যবহার করছেন তার উপর ভিত্তি করে এই কাজটিতে বিভিন্ন অসুবিধা রয়েছে।
এটি আমাদের TTI বন্ধ 1 সেকেন্ড চাঁচা. আমরা এখন এমন পর্যায়ে পৌঁছেছি যেখানে আমাদের index.html
প্রাথমিক রেন্ডার এবং ইন্টারেক্টিভ হওয়ার জন্য প্রয়োজনীয় সবকিছু রয়েছে। এইচটিএমএল এখনও ডাউনলোড করার সময় রেন্ডার করতে পারে, আমাদের এফএমপি তৈরি করে। যে মুহূর্তে HTML পার্সিং এবং এক্সিকিউট করা হয়, অ্যাপটি ইন্টারেক্টিভ হয়।
আক্রমনাত্মক কোড বিভাজন
হ্যাঁ, আমাদের index.html
ইন্টারেক্টিভ হওয়ার জন্য প্রয়োজনীয় সবকিছু রয়েছে। কিন্তু ঘনিষ্ঠভাবে পরিদর্শন করলে দেখা যায় এতে অন্য সব কিছু রয়েছে। আমাদের index.html
প্রায় 43 KB. চলুন শুরুতে ব্যবহারকারীর সাথে কী ইন্টারঅ্যাক্ট করতে পারে তার সাথে সম্পর্কিত করা যাক: গেমটি কনফিগার করার জন্য আমাদের কাছে কয়েকটি উপাদান, একটি স্টার্ট বোতাম এবং ব্যবহারকারীর সেটিংস টিকে থাকার এবং লোড করার জন্য সম্ভবত কিছু কোড রয়েছে। যে বেশ এটা. 43 KB অনেকটা মনে হচ্ছে।

আমাদের বান্ডেলের আকার কোথা থেকে আসছে তা বোঝার জন্য আমরা একটি সোর্স ম্যাপ এক্সপ্লোরার বা অনুরূপ টুল ব্যবহার করতে পারি যা বান্ডিলটিতে কী আছে তা ভেঙে দিতে পারি। যেমন ভবিষ্যদ্বাণী করা হয়েছে, আমাদের বান্ডেলে রয়েছে গেম লজিক, রেন্ডারিং ইঞ্জিন, উইন স্ক্রিন, লস স্ক্রিন এবং একগুচ্ছ ইউটিলিটি। ল্যান্ডিং পৃষ্ঠার জন্য এই মডিউলগুলির শুধুমাত্র একটি ছোট উপসেট প্রয়োজন। অলসভাবে লোড করা মডিউলে ইন্টারঅ্যাক্টিভিটির জন্য কঠোরভাবে প্রয়োজনীয় নয় এমন সমস্ত কিছু স্থানান্তরিত করা TTI উল্লেখযোগ্যভাবে হ্রাস পাবে।
আমাদের যা করতে হবে তা হল কোড বিভক্ত । কোড স্প্লিটিং আপনার একচেটিয়া বান্ডিলকে ছোট ছোট অংশে বিভক্ত করে যা অলস-লোড-অন-ডিমান্ড হতে পারে। জনপ্রিয় বান্ডলার যেমন ওয়েবপ্যাক , রোলআপ , এবং পার্সেল সমর্থন কোড বিভাজন ডায়নামিক import()
ব্যবহার করে। বান্ডলার আপনার কোড বিশ্লেষণ করবে এবং স্ট্যাটিকভাবে আমদানি করা সমস্ত মডিউল ইনলাইন করবে । আপনি যা কিছু গতিশীলভাবে আমদানি করবেন তার নিজস্ব ফাইলে রাখা হবে এবং import()
কলটি কার্যকর হলেই কেবল নেটওয়ার্ক থেকে আনা হবে। অবশ্যই নেটওয়ার্কে আঘাত করার একটি খরচ আছে এবং আপনার হাতে সময় থাকলেই তা করা উচিত। এখানে মন্ত্রটি হল লোডের সময় সমালোচনামূলকভাবে প্রয়োজনীয় মডিউলগুলিকে স্ট্যাটিকভাবে আমদানি করা এবং অন্য সব কিছুকে গতিশীলভাবে লোড করা। তবে আপনার অলস-লোড মডিউলগুলির জন্য একেবারে শেষ মুহুর্ত পর্যন্ত অপেক্ষা করা উচিত নয় যা অবশ্যই ব্যবহার করা হবে। ফিল ওয়ালটনের Idle Until Urgent অলস লোডিং এবং আগ্রহী লোডিংয়ের মধ্যে একটি স্বাস্থ্যকর মধ্যম স্থলের জন্য একটি দুর্দান্ত প্যাটার্ন।
PROXX-এ আমরা একটি lazy.js
ফাইল তৈরি করেছি যা স্ট্যাটিকভাবে আমাদের প্রয়োজন নেই এমন সবকিছু আমদানি করে। আমাদের প্রধান ফাইলে, আমরা গতিশীলভাবে lazy.js
আমদানি করতে পারি। যাইহোক, আমাদের কিছু Preact কম্পোনেন্ট lazy.js
এ শেষ হয়েছে, যা কিছুটা জটিলতার মধ্যে পরিণত হয়েছে কারণ Preact বাক্সের বাইরে অলসভাবে লোড করা উপাদানগুলি পরিচালনা করতে পারে না। এই কারণে আমরা একটি সামান্য deferred
কম্পোনেন্ট র্যাপার লিখেছি যা প্রকৃত কম্পোনেন্ট লোড না হওয়া পর্যন্ত আমাদের একটি স্থানধারক রেন্ডার করতে দেয়।
export default function deferred(componentPromise) {
return class Deferred extends Component {
constructor(props) {
super(props);
this.state = {
LoadedComponent: undefined
};
componentPromise.then(component => {
this.setState({ LoadedComponent: component });
});
}
render({ loaded, loading }, { LoadedComponent }) {
if (LoadedComponent) {
return loaded(LoadedComponent);
}
return loading();
}
};
}
এটির সাথে, আমরা আমাদের render()
ফাংশনে একটি কম্পোনেন্টের প্রতিশ্রুতি ব্যবহার করতে পারি। উদাহরণস্বরূপ, <Nebula>
উপাদান, যা অ্যানিমেটেড ব্যাকগ্রাউন্ড ইমেজ রেন্ডার করে, কম্পোনেন্টটি লোড হওয়ার সময় একটি খালি <div>
দ্বারা প্রতিস্থাপিত হবে। কম্পোনেন্ট লোড হয়ে গেলে এবং ব্যবহারের জন্য প্রস্তুত হলে, <div>
আসল কম্পোনেন্ট দিয়ে প্রতিস্থাপিত হবে।
const NebulaDeferred = deferred(
import("/components/nebula").then(m => m.default)
);
return (
// ...
<NebulaDeferred
loading={() => <div />}
loaded={Nebula => <Nebula />}
/>
);
এই সব জায়গায় রেখে, আমরা আমাদের index.html
কে কমিয়েছি মাত্র 20 KB, আসল আকারের অর্ধেকেরও কম। এটি এফএমপি এবং টিটিআই-এর উপর কী প্রভাব ফেলে? WebPageTest বলে দেবে!
আমাদের এফএমপি এবং টিটিআই কেবল 100 মিমি দূরে, কারণ এটি কেবল ইনলাইন করা জাভাস্ক্রিপ্টটি পার্সিং এবং সম্পাদন করার বিষয়। 2 জি -তে মাত্র 5.4s এর পরে, অ্যাপটি সম্পূর্ণ ইন্টারেক্টিভ। অন্য সমস্ত, কম প্রয়োজনীয় মডিউলগুলি পটভূমিতে লোড করা হয়।
হাতের আরও নিদ্রা
আপনি যদি উপরের আমাদের সমালোচনামূলক মডিউলগুলির তালিকাটি দেখেন তবে আপনি দেখতে পাবেন যে রেন্ডারিং ইঞ্জিনটি সমালোচনামূলক মডিউলগুলির অংশ নয়। অবশ্যই, গেমটি রেন্ডার করার জন্য আমাদের রেন্ডারিং ইঞ্জিন না পাওয়া পর্যন্ত গেমটি শুরু হতে পারে না। আমাদের রেন্ডারিং ইঞ্জিনটি গেমটি শুরু করার জন্য প্রস্তুত না হওয়া পর্যন্ত আমরা "স্টার্ট" বোতামটি অক্ষম করতে পারি, তবে আমাদের অভিজ্ঞতায় ব্যবহারকারী সাধারণত তাদের গেমের সেটিংস কনফিগার করতে যথেষ্ট সময় নেয় যা এটি প্রয়োজনীয় নয়। বেশিরভাগ সময় রেন্ডারিং ইঞ্জিন এবং অন্যান্য অবশিষ্ট মডিউলগুলি ব্যবহারকারী "স্টার্ট" টিপানোর সময় পর্যন্ত লোডিং করা হয়। বিরল ক্ষেত্রে যে ব্যবহারকারী তাদের নেটওয়ার্ক সংযোগের চেয়ে দ্রুত, আমরা একটি সাধারণ লোডিং স্ক্রিন দেখাই যা অবশিষ্ট মডিউলগুলি শেষ হওয়ার জন্য অপেক্ষা করে।
উপসংহার
পরিমাপ গুরুত্বপূর্ণ। বাস্তব নয় এমন সমস্যাগুলিতে সময় ব্যয় করা এড়াতে, আমরা অপ্টিমাইজেশন বাস্তবায়নের আগে সর্বদা প্রথমে পরিমাপ করার পরামর্শ দিই। অতিরিক্তভাবে, কোনও বাস্তব ডিভাইস হাতে না থাকলে 3 জি সংযোগে বা ওয়েবপেজেস্টেস্টে রিয়েল ডিভাইসে পরিমাপ করা উচিত।
ফিল্মস্ট্রিপটি আপনার অ্যাপ্লিকেশনটিকে ব্যবহারকারীর জন্য কীভাবে লোড করা অনুভব করে তা অন্তর্দৃষ্টি দিতে পারে। জলপ্রপাতটি আপনাকে বলতে পারে যে সম্ভাব্য দীর্ঘ লোডিংয়ের জন্য কোন সংস্থানগুলি দায়ী। লোডিং পারফরম্যান্স উন্নত করতে আপনি করতে পারেন এমন জিনিসগুলির একটি চেকলিস্ট এখানে:
- একটি সংযোগের চেয়ে যতটা সম্ভব সম্পদ সরবরাহ করুন।
- প্রিলোড বা এমনকি ইনলাইন সংস্থানগুলি যা প্রথম রেন্ডার এবং ইন্টারেক্টিভিটির জন্য প্রয়োজনীয়।
- অনুভূত লোডিং পারফরম্যান্স উন্নত করতে আপনার অ্যাপ্লিকেশনটি প্রিরেন্ডার করুন।
- ইন্টারেক্টিভিটির জন্য প্রয়োজনীয় কোডের পরিমাণ হ্রাস করতে আক্রমণাত্মক কোড বিভাজন ব্যবহার করুন।
পার্ট 2 এর জন্য থাকুন যেখানে আমরা হাইপার-সীমাবদ্ধ ডিভাইসগুলিতে রানটাইম পারফরম্যান্সকে কীভাবে অনুকূল করতে পারি তা নিয়ে আলোচনা করি।
,আমরা প্রক্সেক্সে কোড বিভাজন, কোড ইনলাইনিং এবং সার্ভার-সাইড রেন্ডারিং কীভাবে ব্যবহার করি।
গুগল আই/ও 2019 এ মারিকো, জ্যাক এবং আমি ওয়েবের জন্য একটি আধুনিক মাইনসুইপার-ক্লোন প্রক্সেক্স প্রেরণ করেছি। প্রক্সেক্সকে আলাদা করে সেট করে এমন কিছু হ'ল অ্যাক্সেসযোগ্যতার উপর ফোকাস (আপনি এটি স্ক্রিন রিডারের সাথে খেলতে পারেন!) এবং একটি উচ্চ-শেষ ডেস্কটপ ডিভাইসে যেমন একটি বৈশিষ্ট্য ফোনে চালানোর ক্ষমতা। বৈশিষ্ট্য ফোনগুলি একাধিক উপায়ে সীমাবদ্ধ:
- দুর্বল সিপিইউ
- দুর্বল বা অস্তিত্বহীন জিপিইউ
- স্পর্শ ইনপুট ছাড়াই ছোট পর্দা
- স্মৃতি খুব সীমিত পরিমাণে
তবে তারা একটি আধুনিক ব্রাউজার চালায় এবং খুব সাশ্রয়ী মূল্যের। এই কারণে, বৈশিষ্ট্য ফোনগুলি উদীয়মান বাজারগুলিতে পুনরুত্থান করছে। তাদের মূল্য পয়েন্টটি সম্পূর্ণ নতুন শ্রোতাদের অনুমতি দেয়, যারা এর আগে এটি বহন করতে পারে না, অনলাইনে এসে আধুনিক ওয়েব ব্যবহার করতে পারে। 2019 এর জন্য এটি অনুমান করা হয়েছে যে প্রায় 400 মিলিয়ন বৈশিষ্ট্য ফোনগুলি কেবল ভারতে বিক্রি হবে , তাই বৈশিষ্ট্য ফোনে ব্যবহারকারীরা আপনার শ্রোতার একটি গুরুত্বপূর্ণ অংশে পরিণত হতে পারে। এগুলি ছাড়াও, 2 জি এর মতো সংযোগের গতি উদীয়মান বাজারগুলিতে আদর্শ। আমরা কীভাবে ফিচার ফোনের শর্তের অধীনে প্রক্সএক্সকে ভালভাবে কাজ করতে পরিচালনা করেছি?
পারফরম্যান্স গুরুত্বপূর্ণ, এবং এর মধ্যে লোডিং পারফরম্যান্স এবং রানটাইম পারফরম্যান্স উভয়ই অন্তর্ভুক্ত। এটি প্রদর্শিত হয়েছে যে ভাল পারফরম্যান্স বর্ধিত ব্যবহারকারীর ধরে রাখা, উন্নত রূপান্তর এবং - সর্বাধিক গুরুত্বপূর্ণভাবে - অন্তর্ভুক্তির সাথে সম্পর্কিত। জেরেমি ওয়াগনারের কেন পারফরম্যান্স গুরুত্বপূর্ণ তা সম্পর্কে আরও অনেক ডেটা এবং অন্তর্দৃষ্টি রয়েছে।
এটি একটি দুই পর্বের সিরিজের পার্ট 1। পার্ট 1 লোডিং পারফরম্যান্সের উপর দৃষ্টি নিবদ্ধ করে এবং পার্ট 2 রানটাইম পারফরম্যান্সে ফোকাস করবে।
স্থিতাবস্থা ক্যাপচার
একটি বাস্তব ডিভাইসে আপনার লোডিং পারফরম্যান্স পরীক্ষা করা গুরুত্বপূর্ণ। আপনার যদি হাতে সত্যিকারের ডিভাইস না থাকে তবে আমি ওয়েবপেজেস্টেস্টের পরামর্শ দিচ্ছি, বিশেষত "সাধারণ" সেটআপ । ডাব্লুপিটি একটি এমুলেটেড 3 জি সংযোগ সহ একটি বাস্তব ডিভাইসে লোডিং পরীক্ষার একটি ব্যাটারি চালায়।
3 জি পরিমাপের জন্য একটি ভাল গতি। আপনি 4 জি, এলটিই বা শীঘ্রই 5 জি ব্যবহার করতে পারেন, মোবাইল ইন্টারনেটের বাস্তবতাটি বেশ আলাদা দেখাচ্ছে। হতে পারে আপনি কোনও ট্রেনে, একটি সম্মেলনে, একটি কনসার্টে বা কোনও ফ্লাইটে রয়েছেন। আপনি সেখানে যা অনুভব করবেন তা সম্ভবত 3 জি এর কাছাকাছি এবং কখনও কখনও আরও খারাপ।
বলা হচ্ছে, আমরা এই নিবন্ধে 2 জি -তে ফোকাস করতে যাচ্ছি কারণ প্রক্সএক্স স্পষ্টভাবে তার লক্ষ্য দর্শকদের মধ্যে বৈশিষ্ট্য ফোন এবং উদীয়মান বাজারগুলিকে লক্ষ্য করছে। একবার ওয়েবপেজেস্টের পরীক্ষা চালানোর পরে, আপনি একটি জলপ্রপাত (আপনি ডেভটুলগুলিতে যা দেখেন তার অনুরূপ) পাশাপাশি শীর্ষে একটি ফিল্মস্ট্রিপ পাবেন। ফিল্ম স্ট্রিপটি দেখায় যে আপনার অ্যাপটি লোড হওয়ার সময় আপনার ব্যবহারকারী কী দেখেন। 2 জি -তে, প্রক্সেক্সের অপ্রচলিত সংস্করণের লোডিং অভিজ্ঞতাটি বেশ খারাপ:
3 জি এর বেশি লোড করা হলে, ব্যবহারকারী 4 সেকেন্ড সাদা কিছুই দেখেন। 2 জি এর বেশি ব্যবহারকারী 8 সেকেন্ডেরও বেশি সময় ধরে একেবারে কিছুই দেখতে পায় না। আপনি যদি পড়েন তবে পারফরম্যান্স কেন গুরুত্বপূর্ণ তা আপনি জানেন যে অধৈর্যতার কারণে আমরা এখন আমাদের সম্ভাব্য ব্যবহারকারীদের একটি ভাল অংশ হারিয়েছি। স্ক্রিনে উপস্থিত হওয়ার জন্য ব্যবহারকারীর 62 কেবি জাভাস্ক্রিপ্টের সমস্ত ডাউনলোড করতে হবে। এই দৃশ্যে রৌপ্য আস্তরণটি হ'ল দ্বিতীয় যে কোনও কিছুই স্ক্রিনে প্রদর্শিত হয় এটি ইন্টারেক্টিভও। নাকি এটা?

প্রায় 62 কেবি জিজিপ'ড জেএস ডাউনলোড করার পরে এবং ডিওএম উত্পন্ন হওয়ার পরে, ব্যবহারকারী আমাদের অ্যাপটি দেখতে পান। অ্যাপটি প্রযুক্তিগতভাবে ইন্টারেক্টিভ। ভিজ্যুয়ালটির দিকে তাকানো অবশ্য আলাদা বাস্তবতা দেখায়। ওয়েব ফন্টগুলি এখনও পটভূমিতে লোড হচ্ছে এবং তারা প্রস্তুত না হওয়া পর্যন্ত ব্যবহারকারী কোনও পাঠ্য দেখতে পাবেন না। যদিও এই রাজ্যটি প্রথম অর্থবহ পেইন্ট (এফএমপি) হিসাবে যোগ্যতা অর্জন করে, এটি অবশ্যই সঠিকভাবে ইন্টারেক্টিভ হিসাবে যোগ্যতা অর্জন করে না, কারণ ব্যবহারকারী কোনও ইনপুট সম্পর্কে কী তা বলতে পারে না। অ্যাপ্লিকেশনটি প্রস্তুত না হওয়া পর্যন্ত এটি 3 জি এবং 3 জি -তে আরও সেকেন্ডে আরও সেকেন্ড সময় নেয়। সব মিলিয়ে অ্যাপ্লিকেশনটি ইন্টারেক্টিভ হওয়ার জন্য 3 জি তে 6 সেকেন্ড এবং 2 জি তে 11 সেকেন্ড সময় নেয়।
জলপ্রপাত বিশ্লেষণ
এখন যেহেতু আমরা জানি যে ব্যবহারকারী কী দেখেন, আমাদের কেন তা বের করতে হবে। এর জন্য আমরা জলপ্রপাতটি দেখতে এবং বিশ্লেষণ করতে পারি কেন সংস্থানগুলি খুব দেরিতে লোড হচ্ছে। প্রক্সেক্সের জন্য আমাদের 2 জি ট্রেসে আমরা দুটি প্রধান লাল পতাকা দেখতে পাচ্ছি:
- একাধিক, বহু বর্ণের পাতলা রেখা রয়েছে।
- জাভাস্ক্রিপ্ট ফাইলগুলি একটি চেইন গঠন করে। উদাহরণস্বরূপ, দ্বিতীয় সংস্থানটি কেবল প্রথম সংস্থান শেষ হয়ে গেলে লোডিং শুরু করে এবং তৃতীয় সংস্থানটি কেবল তখনই শুরু হয় যখন দ্বিতীয় সংস্থানটি শেষ হয়।

সংযোগ গণনা হ্রাস
প্রতিটি পাতলা রেখা ( dns
, connect
, ssl
) একটি নতুন এইচটিটিপি সংযোগ তৈরি করার জন্য দাঁড়িয়েছে। একটি নতুন সংযোগ স্থাপন ব্যয়বহুল কারণ এটি 3 জি -তে প্রায় 1 এস এবং 2 জি তে প্রায় 2.5s লাগে। আমাদের জলপ্রপাতের জন্য আমরা এর জন্য একটি নতুন সংযোগ দেখতে পাচ্ছি:
- অনুরোধ #1: আমাদের
index.html
- অনুরোধ #5:
fonts.googleapis.com
থেকে ফন্ট স্টাইলগুলি - অনুরোধ #8: গুগল অ্যানালিটিক্স
- অনুরোধ #9:
fonts.gstatic.com
থেকে একটি ফন্ট ফাইল - অনুরোধ #14: ওয়েব অ্যাপ্লিকেশন ম্যানিফেস্ট
index.html
এর জন্য নতুন সংযোগটি অনিবার্য। বিষয়বস্তুগুলি পেতে ব্রাউজারটিকে আমাদের সার্ভারের সাথে একটি সংযোগ তৈরি করতে হবে । গুগল অ্যানালিটিক্সের জন্য নতুন সংযোগটি ন্যূনতম বিশ্লেষণের মতো কিছু ইনলাইন করে এড়ানো যেতে পারে, তবে গুগল অ্যানালিটিক্স আমাদের অ্যাপ্লিকেশনটিকে রেন্ডারিং বা ইন্টারেক্টিভ হয়ে যাওয়া থেকে অবরুদ্ধ করছে না, তাই এটি কতটা দ্রুত লোড হয় সে সম্পর্কে আমরা সত্যিই চিন্তা করি না। আদর্শভাবে, গুগল অ্যানালিটিক্স নিষ্ক্রিয় সময়ে লোড করা উচিত, যখন সমস্ত কিছু ইতিমধ্যে লোড হয়ে গেছে। এইভাবে এটি প্রাথমিক লোডের সময় ব্যান্ডউইথ বা প্রসেসিং শক্তি গ্রহণ করবে না। ওয়েব অ্যাপ্লিকেশন ম্যানিফেস্টের জন্য নতুন সংযোগটি আনতে স্পেক দ্বারা নির্ধারিত হয়, কারণ ম্যানিফেস্টটি একটি অ-ক্রেডেনশিয়াল সংযোগের মাধ্যমে লোড করতে হয়। আবার, ওয়েব অ্যাপ্লিকেশন ম্যানিফেস্টটি আমাদের অ্যাপ্লিকেশনটিকে রেন্ডারিং বা ইন্টারেক্টিভ হয়ে যাওয়া থেকে অবরুদ্ধ করে না, তাই আমাদের এত যত্ন নেওয়ার দরকার নেই।
দুটি ফন্ট এবং তাদের শৈলীগুলি অবশ্য একটি সমস্যা কারণ তারা রেন্ডারিং এবং ইন্টারেক্টিভিটি ব্লক করে। আমরা যদি fonts.googleapis.com
দ্বারা সরবরাহ করা সিএসএসের দিকে নজর রাখি তবে এটি প্রতিটি ফন্টের জন্য একটি মাত্র @font-face
বিধি। ফন্ট শৈলীগুলি আসলে এত ছোট, যে আমরা এটি আমাদের এইচটিএমএলে ইনলাইন করার সিদ্ধান্ত নিয়েছি, একটি অপ্রয়োজনীয় সংযোগ অপসারণ করে। ফন্ট ফাইলগুলির জন্য সংযোগ সেটআপের ব্যয় এড়াতে, আমরা সেগুলি আমাদের নিজস্ব সার্ভারে অনুলিপি করতে পারি।
সমান্তরাল বোঝা
জলপ্রপাতের দিকে তাকিয়ে আমরা দেখতে পাচ্ছি যে একবার প্রথম জাভাস্ক্রিপ্ট ফাইলটি লোড হয়ে গেলে নতুন ফাইলগুলি অবিলম্বে লোডিং শুরু করে। এটি মডিউল নির্ভরতার জন্য সাধারণ। আমাদের প্রধান মডিউলটিতে সম্ভবত স্থির আমদানি রয়েছে, সুতরাং সেই আমদানি লোড না হওয়া পর্যন্ত জাভাস্ক্রিপ্টটি চলতে পারে না। এখানে উপলব্ধি করা গুরুত্বপূর্ণ বিষয়টি হ'ল এই ধরণের নির্ভরতা বিল্ড সময়ে পরিচিত। সমস্ত নির্ভরতা আমাদের এইচটিএমএল প্রাপ্ত দ্বিতীয়টি লোড করা শুরু করে তা নিশ্চিত করার জন্য আমরা <link rel="preload">
ট্যাগগুলি ব্যবহার করতে পারি।
ফলাফল
আসুন আমাদের পরিবর্তনগুলি কী অর্জন করেছে তা একবার দেখে নেওয়া যাক। ফলাফলগুলি স্কিউ করতে পারে এমন আমাদের পরীক্ষার সেটআপে অন্য কোনও ভেরিয়েবল পরিবর্তন না করা গুরুত্বপূর্ণ, তাই আমরা এই নিবন্ধের বাকি অংশগুলির জন্য ওয়েবপেজেস্টেস্টের সাধারণ সেটআপটি ব্যবহার করব এবং ফিল্মস্ট্রিপটি দেখুন:
এই পরিবর্তনগুলি আমাদের টিটিআইকে 11 থেকে 8.5 এ হ্রাস করেছে , যা আমরা অপসারণের লক্ষ্য রেখেছিলাম সংযোগ সেটআপের সময় প্রায় 2.5s। ভাল আমাদের।
প্রিরেন্ডারিং
যদিও আমরা আমাদের টিটিআইকে সবেমাত্র হ্রাস করেছি, আমরা ব্যবহারকারীকে 8.5 সেকেন্ডের জন্য সহ্য করতে হবে এমন চিরন্তন দীর্ঘ সাদা স্ক্রিনটি সত্যই প্রভাবিত করতে পারি নি। যুক্তিযুক্তভাবে এফএমপির জন্য সবচেয়ে বড় উন্নতিগুলি আপনার index.html
এ স্টাইলযুক্ত মার্কআপ প্রেরণ করে অর্জন করা যেতে পারে । এটি অর্জনের জন্য সাধারণ কৌশলগুলি হ'ল প্রেরেন্ডারিং এবং সার্ভার-সাইড রেন্ডারিং, যা ঘনিষ্ঠভাবে সম্পর্কিত এবং ওয়েবে রেন্ডারিংয়ে ব্যাখ্যা করা হয়। উভয় কৌশলই নোডে ওয়েব অ্যাপ্লিকেশন চালায় এবং ফলাফলযুক্ত ডিওএমকে এইচটিএমএলে সিরিয়ালাইজ করে। সার্ভার-সাইড রেন্ডারিং এটি অনুরোধ অনুযায়ী, ভাল, সার্ভার সাইডে করে, যখন প্রেরেন্ডারিং এটি বিল্ড টাইমে করে এবং আউটপুটটিকে আপনার নতুন index.html
। যেহেতু প্রক্সএক্স একটি জামস্ট্যাক অ্যাপ্লিকেশন এবং কোনও সার্ভার সাইড নেই, তাই আমরা প্রেরেন্ডারিং বাস্তবায়ন করার সিদ্ধান্ত নিয়েছি।
একজন প্রেরেন্ডারার বাস্তবায়নের অনেকগুলি উপায় রয়েছে। প্রক্সেক্সে আমরা পুতুল ব্যবহার করতে বেছে নিয়েছি, যা কোনও ইউআই ছাড়াই ক্রোম শুরু করে এবং আপনাকে নোড এপিআই দিয়ে সেই উদাহরণটি নিয়ন্ত্রণ করতে দেয়। আমরা এটি আমাদের মার্কআপ এবং আমাদের জাভাস্ক্রিপ্ট ইনজেকশন করতে ব্যবহার করি এবং তারপরে এইচটিএমএল এর স্ট্রিং হিসাবে ডোমটি আবার পড়ি। যেহেতু আমরা সিএসএস মডিউলগুলি ব্যবহার করছি, আমরা আমাদের যে স্টাইলগুলি নিখরচায় প্রয়োজন তা সিএসএস ইনলাইনিং পাই।
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(rawIndexHTML);
await page.evaluate(codeToRun);
const renderedHTML = await page.content();
browser.close();
await writeFile("index.html", renderedHTML);
এটি জায়গায়, আমরা আমাদের এফএমপির জন্য একটি উন্নতি আশা করতে পারি। আমাদের এখনও আগের মতো একই পরিমাণ জাভাস্ক্রিপ্ট লোড এবং সম্পাদন করতে হবে, সুতরাং আমাদের টিটিআই বেশি পরিবর্তন হওয়ার আশা করা উচিত নয়। যদি কিছু হয় তবে আমাদের index.html
আরও বড় হয়েছে এবং আমাদের টিটিআইকে কিছুটা পিছনে ঠেলে দিতে পারে। খুঁজে বের করার একমাত্র উপায় আছে: ওয়েবপেজেস্টে চালানো।
আমাদের প্রথম অর্থবহ পেইন্ট 8.5 সেকেন্ড থেকে 4.9 সেকেন্ডে চলে গেছে, এটি একটি বিশাল উন্নতি। আমাদের টিটিআই এখনও প্রায় 8.5 সেকেন্ডে ঘটে তাই এটি এই পরিবর্তনের দ্বারা মূলত প্রভাবিত হয়নি। আমরা এখানে যা করেছি তা হ'ল একটি উপলব্ধি পরিবর্তন। কেউ কেউ এটিকে হাতের স্লাইটও বলতে পারে। গেমটির একটি মধ্যবর্তী ভিজ্যুয়াল রেন্ডার করে, আমরা আরও ভাল হিসাবে অনুভূত লোডিং পারফরম্যান্স পরিবর্তন করছি।
ইনলাইনিং
আর একটি মেট্রিক যা ডিভটুল এবং ওয়েবপেজেস্টেস্ট আমাদের দেয় তা হ'ল প্রথম বাইট (টিটিএফবি) এর সময় । এই সময়টি অনুরোধের প্রথম বাইট থেকে প্রাপ্ত প্রতিক্রিয়া প্রাপ্তির প্রথম বাইটে প্রেরণ করা হয়। এই সময়টিকে প্রায়শই একটি রাউন্ড ট্রিপ টাইম (আরটিটি) বলা হয়, যদিও প্রযুক্তিগতভাবে এই দুটি সংখ্যার মধ্যে পার্থক্য রয়েছে: আরটিটি সার্ভারের পক্ষের অনুরোধের প্রক্রিয়াকরণের সময়কে অন্তর্ভুক্ত করে না। ডিভটুলস এবং ওয়েবপেজেস্টেস্ট টিটিএফবিকে অনুরোধ/প্রতিক্রিয়া ব্লকের মধ্যে হালকা রঙের সাথে ভিজ্যুয়ালাইজ করুন।
আমাদের জলপ্রপাতের দিকে তাকিয়ে আমরা দেখতে পাচ্ছি যে সমস্ত অনুরোধ তাদের বেশিরভাগ সময় প্রতিক্রিয়াটির প্রথম বাইটের জন্য অপেক্ষা করতে ব্যয় করে ।
এই সমস্যাটি ছিল এইচটিটিপি/2 পুশটি মূলত কল্পনা করা হয়েছিল। অ্যাপ্লিকেশন বিকাশকারী জানেন যে নির্দিষ্ট সংস্থানগুলির প্রয়োজন এবং তাদেরকে তারের নীচে ঠেলে দিতে পারে। ক্লায়েন্ট যখন বুঝতে পারে যে এটি অতিরিক্ত সংস্থান আনতে হবে, তারা ইতিমধ্যে ব্রাউজারের ক্যাশে রয়েছে। HTTP/2 পুশটি ডান পেতে খুব শক্ত হয়ে উঠেছে এবং নিরুৎসাহিত হিসাবে বিবেচিত হয়। এই সমস্যার স্থানটি HTTP/3 এর মানীকরণের সময় পুনর্বিবেচনা করা হবে। আপাতত, সবচেয়ে সহজ সমাধানটি হ'ল ক্যাচিং দক্ষতার ব্যয়ে সমস্ত সমালোচনামূলক সংস্থানগুলিকে ইনলাইন করা ।
আমাদের সমালোচনামূলক সিএসএস ইতিমধ্যে সিএসএস মডিউল এবং আমাদের পুতুল-ভিত্তিক প্রেরেন্ডারারের জন্য ধন্যবাদ জানানো হয়েছে। জাভাস্ক্রিপ্টের জন্য আমাদের আমাদের সমালোচনামূলক মডিউল এবং তাদের নির্ভরতা ইনলাইন করা দরকার। আপনি যে বান্ডিলারটি ব্যবহার করছেন তার উপর ভিত্তি করে এই টাস্কের বিভিন্ন অসুবিধা রয়েছে।
এটি আমাদের টিটিআই থেকে 1 সেকেন্ড শেভ করেছে। আমরা এখন এমন পর্যায়ে পৌঁছেছি যেখানে আমাদের index.html
প্রাথমিক রেন্ডার এবং ইন্টারেক্টিভ হওয়ার জন্য প্রয়োজনীয় সমস্ত কিছু রয়েছে। এইচটিএমএল এখনও ডাউনলোড করার সময় রেন্ডার করতে পারে, আমাদের এফএমপি তৈরি করে। এইচটিএমএল পার্সিং এবং সম্পাদন করার মুহুর্তে অ্যাপটি ইন্টারেক্টিভ।
আক্রমণাত্মক কোড বিভাজন
হ্যাঁ, আমাদের index.html
ইন্টারেক্টিভ হওয়ার জন্য প্রয়োজনীয় সমস্ত কিছু রয়েছে। তবে কাছাকাছি পরিদর্শন করার সময় এটি দেখা যাচ্ছে এটিতে অন্য সমস্ত কিছু রয়েছে। আমাদের index.html
প্রায় 43 কেবি। আসুন এটি শুরুতে ব্যবহারকারী কী সাথে ইন্টারঅ্যাক্ট করতে পারে তার সাথে সম্পর্কিত: আমাদের কাছে কয়েকটি উপাদান, একটি স্টার্ট বোতাম এবং সম্ভবত ব্যবহারকারী সেটিংস ধরে রাখতে এবং লোড করার জন্য কিছু কোড কনফিগার করার জন্য একটি ফর্ম রয়েছে। যে বেশ এটা. 43 কেবি অনেকটা মনে হচ্ছে।

আমাদের বান্ডিলের আকারটি কোথা থেকে আসছে তা বোঝার জন্য আমরা বান্ডিলটি কী কী তা ভেঙে ফেলার জন্য একটি উত্স মানচিত্র এক্সপ্লোরার বা অনুরূপ সরঞ্জাম ব্যবহার করতে পারি। পূর্বাভাস অনুসারে, আমাদের বান্ডলে গেম লজিক, রেন্ডারিং ইঞ্জিন, দ্য উইন স্ক্রিন, হারানো স্ক্রিন এবং ইউটিলিটিগুলির একগুচ্ছ রয়েছে। অবতরণ পৃষ্ঠার জন্য এই মডিউলগুলির কেবলমাত্র একটি ছোট উপসেট প্রয়োজন। ইন্টারেক্টিভিটির জন্য কঠোরভাবে প্রয়োজনীয় নয় এমন সমস্ত কিছু সরানো একটি অলসভাবে বোঝা মডিউলটিতে টিটিআই উল্লেখযোগ্যভাবে হ্রাস পাবে।
আমাদের যা করা দরকার তা হ'ল কোড বিভক্ত । কোড বিভাজন আপনার মনোলিথিক বান্ডিলটিকে ছোট ছোট অংশগুলিতে আলাদা করে দেয় যা অলস-লোড অন-চাহিদাযুক্ত হতে পারে। গতিশীল import()
ব্যবহার করে ওয়েবপ্যাক , রোলআপ এবং পার্সেল সমর্থন কোড বিভাজনের মতো জনপ্রিয় বান্ডলারগুলি। বান্ডলারটি আপনার কোডটি বিশ্লেষণ করবে এবং স্থিতিশীলভাবে আমদানি করা সমস্ত মডিউল ইনলাইন করবে । আপনি গতিশীলভাবে আমদানি করে এমন সমস্ত কিছু তার নিজস্ব ফাইলে রাখা হবে এবং import()
কলটি কার্যকর হওয়ার পরে কেবল নেটওয়ার্ক থেকে আনা হবে। অবশ্যই নেটওয়ার্কে আঘাত করার জন্য একটি ব্যয় রয়েছে এবং আপনার যদি বাঁচানোর সময় থাকে তবে কেবল তা করা উচিত। এখানকার মন্ত্রটি হ'ল মডিউলগুলি স্থিতিশীলভাবে আমদানি করা যা লোড টাইমে সমালোচনামূলকভাবে প্রয়োজন এবং গতিশীলভাবে সমস্ত কিছু লোড করা। তবে আপনার অলস-লোড মডিউলগুলিতে অবশ্যই শেষ মুহুর্তে অপেক্ষা করা উচিত নয় যা অবশ্যই ব্যবহৃত হতে চলেছে। ফিল ওয়ালটনের অলস হওয়া অবধি অলস লোডিং এবং আগ্রহী লোডিংয়ের মধ্যে একটি স্বাস্থ্যকর মধ্যম জমির জন্য জরুরী একটি দুর্দান্ত প্যাটার্ন।
প্রক্সেক্সে আমরা একটি lazy.js
ফাইল তৈরি করেছি যা আমাদের প্রয়োজন হয় না এমন সমস্ত কিছু স্ট্যাটিকভাবে আমদানি করে। আমাদের প্রধান ফাইলে, আমরা তারপরে গতিশীলভাবে lazy.js
আমদানি করতে পারি। যাইহোক, আমাদের কিছু পূর্বের উপাদানগুলি lazy.js
শেষ হয়েছিল, যা কিছুটা জটিলতা হিসাবে প্রমাণিত হয়েছিল কারণ প্রি্যাক্ট বাক্সের বাইরে অলসভাবে বোঝা উপাদানগুলি পরিচালনা করতে পারে না। এই কারণে আমরা একটি সামান্য deferred
উপাদান র্যাপার লিখেছিলাম যা প্রকৃত উপাদানটি লোড না হওয়া পর্যন্ত আমাদের কোনও স্থানধারককে রেন্ডার করতে দেয়।
export default function deferred(componentPromise) {
return class Deferred extends Component {
constructor(props) {
super(props);
this.state = {
LoadedComponent: undefined
};
componentPromise.then(component => {
this.setState({ LoadedComponent: component });
});
}
render({ loaded, loading }, { LoadedComponent }) {
if (LoadedComponent) {
return loaded(LoadedComponent);
}
return loading();
}
};
}
এটি স্থানে, আমরা আমাদের render()
ফাংশনগুলিতে একটি উপাদানগুলির একটি প্রতিশ্রুতি ব্যবহার করতে পারি। উদাহরণস্বরূপ, <Nebula>
উপাদান, যা অ্যানিমেটেড ব্যাকগ্রাউন্ড চিত্রকে রেন্ডার করে, উপাদানটি লোড হওয়ার সময় একটি খালি <div>
দ্বারা প্রতিস্থাপন করা হবে। একবার উপাদানটি লোড হয়ে গেলে এবং ব্যবহারের জন্য প্রস্তুত হয়ে গেলে <div>
প্রকৃত উপাদানটির সাথে প্রতিস্থাপন করা হবে।
const NebulaDeferred = deferred(
import("/components/nebula").then(m => m.default)
);
return (
// ...
<NebulaDeferred
loading={() => <div />}
loaded={Nebula => <Nebula />}
/>
);
এই সমস্ত জায়গায়, আমরা আমাদের index.html
হ্রাস করেছি মাত্র 20 কেবি, মূল আকারের অর্ধেকেরও কম। এফএমপি এবং টিটিআই -তে এর কী প্রভাব রয়েছে? ওয়েবপেজেস্টেস্ট বলবে!
আমাদের এফএমপি এবং টিটিআই কেবল 100 মিমি দূরে, কারণ এটি কেবল ইনলাইন করা জাভাস্ক্রিপ্টটি পার্সিং এবং সম্পাদন করার বিষয়। 2 জি -তে মাত্র 5.4s এর পরে, অ্যাপটি সম্পূর্ণ ইন্টারেক্টিভ। অন্য সমস্ত, কম প্রয়োজনীয় মডিউলগুলি পটভূমিতে লোড করা হয়।
হাতের আরও নিদ্রা
আপনি যদি উপরের আমাদের সমালোচনামূলক মডিউলগুলির তালিকাটি দেখেন তবে আপনি দেখতে পাবেন যে রেন্ডারিং ইঞ্জিনটি সমালোচনামূলক মডিউলগুলির অংশ নয়। অবশ্যই, গেমটি রেন্ডার করার জন্য আমাদের রেন্ডারিং ইঞ্জিন না পাওয়া পর্যন্ত গেমটি শুরু হতে পারে না। আমাদের রেন্ডারিং ইঞ্জিনটি গেমটি শুরু করার জন্য প্রস্তুত না হওয়া পর্যন্ত আমরা "স্টার্ট" বোতামটি অক্ষম করতে পারি, তবে আমাদের অভিজ্ঞতায় ব্যবহারকারী সাধারণত তাদের গেমের সেটিংস কনফিগার করতে যথেষ্ট সময় নেয় যা এটি প্রয়োজনীয় নয়। বেশিরভাগ সময় রেন্ডারিং ইঞ্জিন এবং অন্যান্য অবশিষ্ট মডিউলগুলি ব্যবহারকারী "স্টার্ট" টিপানোর সময় পর্যন্ত লোডিং করা হয়। বিরল ক্ষেত্রে যে ব্যবহারকারী তাদের নেটওয়ার্ক সংযোগের চেয়ে দ্রুত, আমরা একটি সাধারণ লোডিং স্ক্রিন দেখাই যা অবশিষ্ট মডিউলগুলি শেষ হওয়ার জন্য অপেক্ষা করে।
উপসংহার
পরিমাপ গুরুত্বপূর্ণ। বাস্তব নয় এমন সমস্যাগুলিতে সময় ব্যয় করা এড়াতে, আমরা অপ্টিমাইজেশন বাস্তবায়নের আগে সর্বদা প্রথমে পরিমাপ করার পরামর্শ দিই। অতিরিক্তভাবে, কোনও বাস্তব ডিভাইস হাতে না থাকলে 3 জি সংযোগে বা ওয়েবপেজেস্টেস্টে রিয়েল ডিভাইসে পরিমাপ করা উচিত।
ফিল্মস্ট্রিপটি আপনার অ্যাপ্লিকেশনটিকে ব্যবহারকারীর জন্য কীভাবে লোড করা অনুভব করে তা অন্তর্দৃষ্টি দিতে পারে। জলপ্রপাতটি আপনাকে বলতে পারে যে সম্ভাব্য দীর্ঘ লোডিংয়ের জন্য কোন সংস্থানগুলি দায়ী। লোডিং পারফরম্যান্স উন্নত করতে আপনি করতে পারেন এমন জিনিসগুলির একটি চেকলিস্ট এখানে:
- একটি সংযোগের চেয়ে যতটা সম্ভব সম্পদ সরবরাহ করুন।
- প্রিলোড বা এমনকি ইনলাইন সংস্থানগুলি যা প্রথম রেন্ডার এবং ইন্টারেক্টিভিটির জন্য প্রয়োজনীয়।
- অনুভূত লোডিং পারফরম্যান্স উন্নত করতে আপনার অ্যাপ্লিকেশনটি প্রিরেন্ডার করুন।
- ইন্টারেক্টিভিটির জন্য প্রয়োজনীয় কোডের পরিমাণ হ্রাস করতে আক্রমণাত্মক কোড বিভাজন ব্যবহার করুন।
পার্ট 2 এর জন্য থাকুন যেখানে আমরা হাইপার-সীমাবদ্ধ ডিভাইসগুলিতে রানটাইম পারফরম্যান্সকে কীভাবে অনুকূল করতে পারি তা নিয়ে আলোচনা করি।