একটি ওয়েব অ্যাপ দ্রুত লোড করার কৌশল, এমনকি একটি ফিচার ফোনেও

কিভাবে আমরা PROXX এ কোড স্প্লিটিং, কোড ইনলাইনিং এবং সার্ভার-সাইড রেন্ডারিং ব্যবহার করেছি।

Google I/O 2019 এ Mariko, Jake, এবং আমি PROXX পাঠিয়েছি, ওয়েবের জন্য একটি আধুনিক মাইনসুইপার-ক্লোন। এমন কিছু যা PROXX কে আলাদা করে তা হল অ্যাক্সেসিবিলিটির উপর ফোকাস (আপনি এটি একটি স্ক্রিনরিডার দিয়ে চালাতে পারেন!) এবং হাই-এন্ড ডেস্কটপ ডিভাইসের মতো ফিচার ফোনেও চালানোর ক্ষমতা। ফিচার ফোন একাধিক উপায়ে সীমাবদ্ধ:

  • দুর্বল সিপিইউ
  • দুর্বল বা অস্তিত্বহীন জিপিইউ
  • স্পর্শ ইনপুট ছাড়া ছোট পর্দা
  • মেমরি খুব সীমিত পরিমাণ

কিন্তু তারা একটি আধুনিক ব্রাউজার চালায় এবং খুব সাশ্রয়ী মূল্যের। এই কারণে, ফিচার ফোনগুলি উদীয়মান বাজারে একটি পুনরুত্থান ঘটাচ্ছে। তাদের মূল্য বিন্দু একটি সম্পূর্ণ নতুন শ্রোতাদের অনুমতি দেয়, যারা আগে এটি বহন করতে পারেনি, অনলাইনে আসতে এবং আধুনিক ওয়েব ব্যবহার করতে পারে৷ 2019 এর জন্য এটি অনুমান করা হয়েছে যে প্রায় 400 মিলিয়ন ফিচার ফোন শুধুমাত্র ভারতেই বিক্রি হবে , তাই ফিচার ফোনের ব্যবহারকারীরা আপনার দর্শকদের একটি উল্লেখযোগ্য অংশ হয়ে উঠতে পারে। তা ছাড়াও, 2G-এর মতো সংযোগের গতি উদীয়মান বাজারে আদর্শ। আমরা কীভাবে ফিচার ফোনের শর্তে PROXX কে ভালভাবে কাজ করতে পরিচালনা করেছি?

PROXX গেমপ্লে।

পারফরম্যান্স গুরুত্বপূর্ণ, এবং এতে লোডিং পারফরম্যান্স এবং রানটাইম পারফরম্যান্স উভয়ই অন্তর্ভুক্ত। এটি দেখানো হয়েছে যে ভাল পারফরম্যান্স বর্ধিত ব্যবহারকারীর ধারণ, উন্নত রূপান্তর এবং সবচেয়ে গুরুত্বপূর্ণভাবে-বর্ধিত অন্তর্ভুক্তির সাথে সম্পর্কযুক্ত। কেন পারফরম্যান্স গুরুত্বপূর্ণ সে সম্পর্কে জেরেমি ওয়াগনারের অনেক বেশি ডেটা এবং অন্তর্দৃষ্টি রয়েছে৷

এটি একটি দুই পর্বের সিরিজের পার্ট 1। পার্ট 1 লোডিং পারফরম্যান্সের উপর ফোকাস করে , এবং পার্ট 2 রানটাইম পারফরম্যান্সের উপর ফোকাস করবে।

স্থিতাবস্থা ক্যাপচার করা

একটি বাস্তব ডিভাইসে আপনার লোডিং কর্মক্ষমতা পরীক্ষা করা গুরুত্বপূর্ণ। যদি আপনার হাতে একটি বাস্তব ডিভাইস না থাকে, আমি সুপারিশ করি WebPageTest , বিশেষ করে "সহজ" সেটআপWPT একটি ইমুলেটেড 3G সংযোগ সহ একটি বাস্তব ডিভাইসে লোডিং পরীক্ষার একটি ব্যাটারি চালায়।

3G একটি ভাল গতি পরিমাপ. যদিও আপনি 4G, LTE বা শীঘ্রই এমনকি 5G-তে অভ্যস্ত হতে পারেন, মোবাইল ইন্টারনেটের বাস্তবতা বেশ ভিন্ন দেখায়। হতে পারে আপনি একটি ট্রেনে, একটি সম্মেলনে, একটি কনসার্টে, বা একটি ফ্লাইটে। আপনি সেখানে যা অনুভব করবেন তা সম্ভবত 3G এর কাছাকাছি এবং কখনও কখনও আরও খারাপ।

বলা হচ্ছে, আমরা এই নিবন্ধে 2G-এর উপর ফোকাস করতে যাচ্ছি কারণ PROXX স্পষ্টভাবে ফিচার ফোন এবং উদীয়মান বাজারগুলিকে তার লক্ষ্য দর্শকদের মধ্যে টার্গেট করছে। WebPageTest এর পরীক্ষা চালানো হয়ে গেলে, আপনি একটি জলপ্রপাত (আপনি DevTools-এ যা দেখেন তার অনুরূপ) পাশাপাশি শীর্ষে একটি ফিল্মস্ট্রিপ পাবেন। ফিল্ম স্ট্রিপ দেখায় যে আপনার অ্যাপ লোড হওয়ার সময় আপনার ব্যবহারকারী কী দেখেন। 2G-তে, PROXX-এর অপ্টিমাইজ করা সংস্করণের লোডিং অভিজ্ঞতা বেশ খারাপ:

ফিল্মস্ট্রিপ ভিডিওটি দেখায় যে ব্যবহারকারী যখন PROXX একটি বাস্তব, লো-এন্ড ডিভাইসে একটি অনুকরণ করা 2G সংযোগে লোড হচ্ছে তখন কী দেখেন৷

3G এর উপর লোড করা হলে, ব্যবহারকারী 4 সেকেন্ডের সাদা শূন্যতা দেখতে পান। 2G-এর উপরে ব্যবহারকারী 8 সেকেন্ডের জন্য একেবারে কিছুই দেখতে পায় না। কর্মক্ষমতা কেন গুরুত্বপূর্ণ তা যদি আপনি পড়েন তবে আপনি জানেন যে আমরা এখন অধৈর্যতার কারণে আমাদের সম্ভাব্য ব্যবহারকারীদের একটি ভাল অংশ হারিয়ে ফেলেছি। স্ক্রিনে কিছু দেখাতে ব্যবহারকারীকে 62 KB জাভাস্ক্রিপ্টের সমস্ত ডাউনলোড করতে হবে। এই দৃশ্যের রূপালী আস্তরণ হল যে দ্বিতীয় কিছু পর্দায় প্রদর্শিত হয় এটিও ইন্টারেক্টিভ। অথবা এটা?

PROXX-এর অপ্টিমাইজ করা সংস্করণে [প্রথম অর্থপূর্ণ পেইন্ট][FMP] হল _টেকনিক্যালি_ [ইন্টারেক্টিভ][TTI] কিন্তু ব্যবহারকারীর কাছে অকেজো।

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

জলপ্রপাত বিশ্লেষণ

এখন যেহেতু আমরা জানি ব্যবহারকারী কী দেখে, আমাদের কেন তা খুঁজে বের করতে হবে। এর জন্য আমরা জলপ্রপাতটি দেখতে পারি এবং বিশ্লেষণ করতে পারি কেন সংস্থানগুলি খুব দেরিতে লোড হচ্ছে। PROXX-এর জন্য আমাদের 2G ট্রেসে আমরা দুটি প্রধান লাল পতাকা দেখতে পাচ্ছি:

  1. একাধিক, বহু রঙের পাতলা লাইন আছে।
  2. জাভাস্ক্রিপ্ট ফাইল একটি চেইন গঠন করে। উদাহরণস্বরূপ, প্রথম সংস্থানটি শেষ হওয়ার পরে দ্বিতীয় সংস্থানটি কেবলমাত্র লোড হওয়া শুরু করে এবং দ্বিতীয় সংস্থানটি শেষ হলেই তৃতীয় সংস্থানটি শুরু হয়।
জলপ্রপাত কোন সম্পদ লোড হচ্ছে কখন এবং কত সময় নেয় তা অন্তর্দৃষ্টি দেয়।

সংযোগের সংখ্যা হ্রাস করা

প্রতিটি পাতলা লাইন ( 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 এর সাধারণ সেটআপ ব্যবহার করব এবং ফিল্মস্ট্রিপটি দেখব:

আমাদের পরিবর্তনগুলি কী অর্জন করেছে তা দেখতে আমরা 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 কে কিছুটা পিছিয়ে দিতে পারে। খুঁজে বের করার একমাত্র উপায় আছে: ওয়েবপেজটেস্ট চালানো।

ফিল্মস্ট্রিপ আমাদের FMP মেট্রিকের জন্য একটি স্পষ্ট উন্নতি দেখায়। টিটিআই বেশিরভাগই প্রভাবিত নয়।

আমাদের প্রথম অর্থপূর্ণ পেইন্ট 8.5 সেকেন্ড থেকে 4.9 সেকেন্ডে চলে গেছে, একটি ব্যাপক উন্নতি। আমাদের TTI এখনও প্রায় 8.5 সেকেন্ডে ঘটে তাই এটি এই পরিবর্তনের দ্বারা অনেকাংশে প্রভাবিত হয়নি। আমরা এখানে যা করেছি তা একটি উপলব্ধিগত পরিবর্তন। কেউ কেউ এটাকে হাতের তুচ্ছতাচ্ছিল্যও বলতে পারে। গেমের একটি মধ্যবর্তী ভিজ্যুয়াল রেন্ডার করার মাধ্যমে, আমরা অনুভূত লোডিং কর্মক্ষমতা আরও ভাল করার জন্য পরিবর্তন করছি।

ইনলাইনিং

আরেকটি মেট্রিক যা DevTools এবং WebPageTest উভয়ই আমাদের দেয় তা হল টাইম টু ফার্স্ট বাইট (TTFB) । রিকোয়েস্ট পাঠানোর প্রথম বাইট থেকে সাড়া পাওয়ার প্রথম বাইট পর্যন্ত এই সময় লাগে। এই সময়টিকে প্রায়ই রাউন্ড ট্রিপ টাইম (RTT) বলা হয়, যদিও প্রযুক্তিগতভাবে এই দুটি সংখ্যার মধ্যে পার্থক্য রয়েছে: RTT সার্ভারের দিকে অনুরোধের প্রক্রিয়াকরণের সময় অন্তর্ভুক্ত করে না। DevTools এবং WebPageTest অনুরোধ/প্রতিক্রিয়া ব্লকের মধ্যে হালকা রঙের সাথে TTFB কে কল্পনা করে।

একটি অনুরোধের হালকা বিভাগটি নির্দেশ করে যে অনুরোধটি প্রতিক্রিয়ার প্রথম বাইট পাওয়ার জন্য অপেক্ষা করছে।

আমাদের জলপ্রপাতের দিকে তাকিয়ে, আমরা দেখতে পাচ্ছি যে সমস্ত অনুরোধ তাদের বেশিরভাগ সময় ব্যয় করে প্রতিক্রিয়ার প্রথম বাইট আসার অপেক্ষায়

এই সমস্যাটি HTTP/2 পুশের জন্য মূলত ধারণা করা হয়েছিল। অ্যাপ ডেভেলপার জানেন যে নির্দিষ্ট সংস্থানগুলির প্রয়োজন এবং সেগুলিকে তারের নিচে ঠেলে দিতে পারে৷ ক্লায়েন্ট যখন বুঝতে পারে যে এটিকে অতিরিক্ত সংস্থান আনতে হবে, তারা ইতিমধ্যেই ব্রাউজারের ক্যাশে রয়েছে৷ এইচটিটিপি/2 পুশ সঠিক হওয়া খুব কঠিন বলে প্রমাণিত হয় এবং এটিকে নিরুৎসাহিত করা হয়। HTTP/3 এর প্রমিতকরণের সময় এই সমস্যা স্থানটি পুনরায় দেখা হবে। আপাতত, সবচেয়ে সহজ সমাধান হল ক্যাশিং দক্ষতার খরচে সমস্ত গুরুত্বপূর্ণ সংস্থান ইনলাইন করা

আমাদের সমালোচনামূলক CSS ইতিমধ্যেই ইনলাইন করা হয়েছে CSS মডিউল এবং আমাদের Puppeteer-ভিত্তিক প্রিরেন্ডারারকে ধন্যবাদ। জাভাস্ক্রিপ্টের জন্য আমাদের গুরুত্বপূর্ণ মডিউল এবং তাদের নির্ভরতা ইনলাইন করতে হবে। আপনি যে বান্ডলার ব্যবহার করছেন তার উপর ভিত্তি করে এই কাজটিতে বিভিন্ন অসুবিধা রয়েছে।

আমাদের জাভাস্ক্রিপ্টের ইনলাইনিংয়ের সাথে আমরা আমাদের TTI 8.5s থেকে কমিয়ে 7.2s করেছি।

এটি আমাদের TTI বন্ধ 1 সেকেন্ড চাঁচা. আমরা এখন এমন পর্যায়ে পৌঁছেছি যেখানে আমাদের index.html প্রাথমিক রেন্ডার এবং ইন্টারেক্টিভ হওয়ার জন্য প্রয়োজনীয় সবকিছু রয়েছে। এইচটিএমএল এখনও ডাউনলোড করার সময় রেন্ডার করতে পারে, আমাদের এফএমপি তৈরি করে। যে মুহূর্তে HTML পার্সিং এবং এক্সিকিউট করা হয়, অ্যাপটি ইন্টারেক্টিভ হয়।

আক্রমনাত্মক কোড বিভাজন

হ্যাঁ, আমাদের index.html ইন্টারেক্টিভ হওয়ার জন্য প্রয়োজনীয় সবকিছু রয়েছে। কিন্তু ঘনিষ্ঠভাবে পরিদর্শন করলে দেখা যায় এতে অন্য সব কিছু রয়েছে। আমাদের index.html প্রায় 43 KB. চলুন শুরুতে ব্যবহারকারীর সাথে কী ইন্টারঅ্যাক্ট করতে পারে তার সাথে সম্পর্কিত করা যাক: গেমটি কনফিগার করার জন্য আমাদের কাছে কয়েকটি উপাদান, একটি স্টার্ট বোতাম এবং ব্যবহারকারীর সেটিংস টিকে থাকার এবং লোড করার জন্য সম্ভবত কিছু কোড রয়েছে। যে প্রায় কাছাকাছি এটা. 43 KB অনেকটা মনে হচ্ছে।

PROXX এর ল্যান্ডিং পৃষ্ঠা। এখানে শুধুমাত্র গুরুত্বপূর্ণ উপাদান ব্যবহার করা হয়.

আমাদের বান্ডেলের আকার কোথা থেকে আসছে তা বোঝার জন্য আমরা একটি সোর্স ম্যাপ এক্সপ্লোরার বা অনুরূপ টুল ব্যবহার করতে পারি যা বান্ডিলটিতে কী আছে তা ভেঙে দিতে পারি। যেমন ভবিষ্যদ্বাণী করা হয়েছে, আমাদের বান্ডেলে রয়েছে গেম লজিক, রেন্ডারিং ইঞ্জিন, উইন স্ক্রিন, লস স্ক্রিন এবং একগুচ্ছ ইউটিলিটি। ল্যান্ডিং পৃষ্ঠার জন্য এই মডিউলগুলির শুধুমাত্র একটি ছোট উপসেট প্রয়োজন। অলসভাবে লোড করা মডিউলে ইন্টারঅ্যাক্টিভিটির জন্য কঠোরভাবে প্রয়োজনীয় নয় এমন সমস্ত কিছু স্থানান্তরিত করা TTI উল্লেখযোগ্যভাবে হ্রাস পাবে।

PROXX এর `index.html` এর বিষয়বস্তু বিশ্লেষণ করলে প্রচুর অপ্রয়োজনীয় সম্পদ দেখা যায়। সমালোচনামূলক সম্পদ হাইলাইট করা হয়.

আমাদের যা করতে হবে তা হল কোড বিভক্ত । কোড স্প্লিটিং আপনার একশিলা বান্ডিলকে ছোট ছোট অংশে বিভক্ত করে যা অলস-লোড-অন-ডিমান্ড হতে পারে। জনপ্রিয় বান্ডলার যেমন ওয়েবপ্যাক , রোলআপ , এবং পার্সেল সমর্থন কোড বিভাজন ডায়নামিক 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 বলে দেবে!

ফিল্মস্ট্রিপ নিশ্চিত করে: আমাদের TTI এখন 5.4s এ। আমাদের মূল 11s থেকে একটি কঠোর উন্নতি।

আমাদের FMP এবং TTI শুধুমাত্র 100ms দূরে, কারণ এটি শুধুমাত্র ইনলাইন করা জাভাস্ক্রিপ্ট পার্সিং এবং এক্সিকিউট করার বিষয়। 2G-তে মাত্র 5.4s পরে, অ্যাপটি সম্পূর্ণ ইন্টারেক্টিভ। অন্য সব, কম প্রয়োজনীয় মডিউল পটভূমিতে লোড করা হয়।

হাতের আরও স্লাইট

আপনি যদি উপরে আমাদের সমালোচনামূলক মডিউলগুলির তালিকাটি দেখেন তবে আপনি দেখতে পাবেন যে রেন্ডারিং ইঞ্জিনটি সমালোচনামূলক মডিউলগুলির অংশ নয়৷ অবশ্যই, গেমটি রেন্ডার করার জন্য আমাদের রেন্ডারিং ইঞ্জিন না হওয়া পর্যন্ত গেমটি শুরু করা যাবে না। আমাদের রেন্ডারিং ইঞ্জিন গেমটি শুরু করার জন্য প্রস্তুত না হওয়া পর্যন্ত আমরা "স্টার্ট" বোতামটি অক্ষম করতে পারি, তবে আমাদের অভিজ্ঞতায় ব্যবহারকারী সাধারণত তাদের গেম সেটিংস কনফিগার করতে যথেষ্ট সময় নেয় যে এটি প্রয়োজনীয় নয়। বেশিরভাগ সময় রেন্ডারিং ইঞ্জিন এবং অন্যান্য অবশিষ্ট মডিউলগুলি লোড করা হয় যখন ব্যবহারকারী "স্টার্ট" চাপেন। বিরল ক্ষেত্রে যে ব্যবহারকারী তাদের নেটওয়ার্ক সংযোগের চেয়ে দ্রুত, আমরা একটি সাধারণ লোডিং স্ক্রিন দেখাই যা অবশিষ্ট মডিউলগুলি শেষ হওয়ার জন্য অপেক্ষা করে।

উপসংহার

পরিমাপ গুরুত্বপূর্ণ। বাস্তব নয় এমন সমস্যায় সময় ব্যয় এড়াতে, আমরা সর্বদা অপ্টিমাইজেশান প্রয়োগ করার আগে প্রথমে পরিমাপ করার পরামর্শ দিই। অতিরিক্তভাবে, পরিমাপ করা উচিত বাস্তব ডিভাইসে 3G সংযোগে বা WebPageTest- এ যদি কোনো বাস্তব ডিভাইস হাতে না থাকে।

ফিল্মস্ট্রিপ আপনার অ্যাপ লোড করা ব্যবহারকারীর জন্য কেমন অনুভব করে তার অন্তর্দৃষ্টি দিতে পারে। জলপ্রপাতটি আপনাকে বলতে পারে যে সম্ভাব্য দীর্ঘ লোডিং সময়ের জন্য কোন সংস্থানগুলি দায়ী। লোডিং কর্মক্ষমতা উন্নত করতে আপনি যা করতে পারেন তার একটি চেকলিস্ট এখানে রয়েছে:

  • একটি সংযোগে যতটা সম্ভব সম্পদ সরবরাহ করুন।
  • প্রিলোড বা এমনকি ইনলাইন সংস্থান যা প্রথম রেন্ডার এবং ইন্টারঅ্যাক্টিভিটির জন্য প্রয়োজনীয়।
  • অনুভূত লোডিং কর্মক্ষমতা উন্নত করতে আপনার অ্যাপ প্রি-রেন্ডার করুন।
  • ইন্টারঅ্যাক্টিভিটির জন্য প্রয়োজনীয় কোডের পরিমাণ কমাতে আক্রমণাত্মক কোড বিভাজন ব্যবহার করুন।

পার্ট 2 এর জন্য সাথে থাকুন যেখানে আমরা হাইপার-সংবদ্ধ ডিভাইসগুলিতে রানটাইম পারফরম্যান্সকে কীভাবে অপ্টিমাইজ করতে হয় তা নিয়ে আলোচনা করব।