কৌণিক SSR এর মাধ্যমে নিরাপদে DOM অ্যাক্সেস করা

জেরাল্ড মোনাকো
Gerald Monaco

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

দুর্ভাগ্যবশত, একটি প্যাটার্ন রয়েছে যা আপনার অ্যাপ্লিকেশন বা লাইব্রেরিকে এই সমস্ত নতুন এবং আসন্ন বৈশিষ্ট্যগুলির সম্পূর্ণ সুবিধা নেওয়া থেকে বাধা দিতে পারে: অন্তর্নিহিত DOM কাঠামোর ম্যানুয়াল ম্যানিপুলেশন। কৌণিকের জন্য প্রয়োজন যে DOM-এর গঠন সার্ভারের দ্বারা ক্রমিককরণের সময় থেকে ব্রাউজারে হাইড্রেটেড না হওয়া পর্যন্ত সামঞ্জস্যপূর্ণ থাকে। ElementRef , Renderer2 , বা DOM APIs ব্যবহার করে ম্যানুয়ালি DOM থেকে নোডগুলি যোগ করা, সরানো বা অপসারণ করার আগে হাইড্রেশন এই বৈশিষ্ট্যগুলিকে কাজ করা থেকে বাধা দেয় এমন অসঙ্গতিগুলি প্রবর্তন করতে পারে৷

যাইহোক, সমস্ত ম্যানুয়াল DOM ম্যানিপুলেশন এবং অ্যাক্সেস সমস্যাযুক্ত নয় এবং কখনও কখনও এটি প্রয়োজনীয়। নিরাপদে DOM ব্যবহার করার মূল চাবিকাঠি হল এটির জন্য আপনার প্রয়োজনীয়তা যতটা সম্ভব কমিয়ে আনা এবং তারপর যতটা সম্ভব আপনার ব্যবহার পিছিয়ে দেওয়া। নিম্নলিখিত নির্দেশিকাগুলি ব্যাখ্যা করে যে আপনি কীভাবে এটি সম্পন্ন করতে পারেন এবং সত্যিকারের সর্বজনীন এবং ভবিষ্যত-প্রমাণ কৌণিক উপাদানগুলি তৈরি করতে পারেন যা অ্যাঙ্গুলারের সমস্ত নতুন এবং আসন্ন বৈশিষ্ট্যগুলির সম্পূর্ণ সুবিধা নিতে পারে।

ম্যানুয়াল DOM ম্যানিপুলেশন এড়িয়ে চলুন

ম্যানুয়াল DOM ম্যানিপুলেশন যে সমস্যাগুলি সৃষ্টি করে তা এড়ানোর সর্বোত্তম উপায় হল, আশ্চর্যজনকভাবে, যেখানেই সম্ভব এটিকে সম্পূর্ণভাবে এড়ানো। Angular-এর অন্তর্নির্মিত API এবং প্যাটার্ন রয়েছে যা DOM-এর বেশিরভাগ দিকগুলিকে কাজে লাগাতে পারে: আপনার সরাসরি DOM অ্যাক্সেস করার পরিবর্তে সেগুলি ব্যবহার করা পছন্দ করা উচিত।

একটি উপাদানের নিজস্ব DOM উপাদান পরিবর্তন করুন

একটি উপাদান বা নির্দেশনা লেখার সময়, আপনাকে হোস্ট উপাদান (অর্থাৎ, DOM উপাদান যা উপাদান বা নির্দেশের নির্বাচকের সাথে মেলে) পরিবর্তন করতে হতে পারে, উদাহরণস্বরূপ, লক্ষ্য বা প্রবর্তনের পরিবর্তে একটি শ্রেণী, শৈলী বা বৈশিষ্ট্য যোগ করতে মোড়ক উপাদান। এটি অন্তর্নিহিত DOM উপাদানকে পরিবর্তন করতে ElementRef এর কাছে পৌঁছানো লোভনীয়। পরিবর্তে, মানগুলিকে একটি অভিব্যক্তিতে ঘোষণামূলকভাবে আবদ্ধ করতে আপনার হোস্ট বাইন্ডিং ব্যবহার করা উচিত:

@Component({
  selector: 'my-component',
  template: `...`,
  host: {
    '[class.foo]': 'true'
  },
})
export class MyComponent {
  /* ... */
}

ঠিক যেমন HTML-এ ডেটা বাইন্ডিং এর সাথে, আপনিও, উদাহরণস্বরূপ, বৈশিষ্ট্য এবং শৈলীর সাথে আবদ্ধ করতে পারেন এবং 'true' একটি ভিন্ন অভিব্যক্তিতে পরিবর্তন করতে পারেন যা কৌণিক স্বয়ংক্রিয়ভাবে প্রয়োজন অনুসারে মান যোগ করতে বা সরাতে ব্যবহার করবে।

কিছু ক্ষেত্রে, কীটি গতিশীলভাবে গণনা করা প্রয়োজন। আপনি একটি সংকেত বা ফাংশনে আবদ্ধ করতে পারেন যা মানগুলির একটি সেট বা মানচিত্র প্রদান করে:

@Component({
  selector: 'my-component',
  template: `...`,
  host: {
    '[class.foo]': 'true',
    '[class]': 'classes()'
  },
})
export class MyComponent {
  size = signal('large');
  classes = computed(() => {
    return [`size-${this.size()}`];
  });
}

আরও জটিল অ্যাপ্লিকেশনে, ExpressionChangedAfterItHasBeenCheckedError এড়াতে ম্যানুয়াল DOM ম্যানিপুলেশনের জন্য পৌঁছাতে প্রলুব্ধ হতে পারে। পরিবর্তে, আপনি আগের উদাহরণের মতো একটি সংকেতের সাথে মানটিকে আবদ্ধ করতে পারেন। এটি প্রয়োজন অনুসারে করা যেতে পারে এবং আপনার পুরো কোডবেস জুড়ে সংকেত গ্রহণের প্রয়োজন নেই।

একটি টেমপ্লেটের বাইরে DOM উপাদানগুলি পরিবর্তন করুন৷

সাধারণভাবে অ্যাক্সেসযোগ্য নয় এমন উপাদানগুলিকে অ্যাক্সেস করতে DOM ব্যবহার করার চেষ্টা করা লোভনীয়, যেমন অন্যান্য পিতামাতা বা শিশু উপাদানগুলির অন্তর্ভুক্ত৷ যাইহোক, এটি ত্রুটি প্রবণ, এনক্যাপসুলেশন লঙ্ঘন করে এবং ভবিষ্যতে এই উপাদানগুলি পরিবর্তন বা আপগ্রেড করা কঠিন করে তোলে।

পরিবর্তে, আপনার উপাদানটি অন্য প্রতিটি উপাদানকে একটি কালো বাক্স হিসাবে বিবেচনা করা উচিত। কখন এবং কোথায় অন্যান্য উপাদানগুলি (এমনকি একই অ্যাপ্লিকেশন বা লাইব্রেরির মধ্যেও) আপনার উপাদানের আচরণ বা চেহারার সাথে ইন্টারঅ্যাক্ট বা কাস্টমাইজ করার প্রয়োজন হতে পারে তা বিবেচনা করার জন্য সময় নিন এবং তারপরে এটি করার জন্য একটি নিরাপদ এবং নথিভুক্ত উপায় প্রকাশ করুন৷ সাধারণ @Input এবং @Output বৈশিষ্ট্যগুলি পর্যাপ্ত না হলে একটি সাবট্রিতে একটি API উপলব্ধ করতে শ্রেণীবিন্যাস নির্ভরতা ইনজেকশনের মতো বৈশিষ্ট্যগুলি ব্যবহার করুন৷

ঐতিহাসিকভাবে, <body> বা অন্য কোনো হোস্ট এলিমেন্টের শেষে একটি উপাদান যোগ করে এবং তারপর সেখানে বিষয়বস্তু সরানো বা প্রজেক্ট করার মাধ্যমে মডেল ডায়ালগ বা টুলটিপের মতো বৈশিষ্ট্য বাস্তবায়ন করা সাধারণ ছিল। যাইহোক, আজকাল আপনি সম্ভবত আপনার টেমপ্লেটে একটি সাধারণ <dialog> উপাদান রেন্ডার করতে পারেন:

@Component({
  selector: 'my-component',
  template: `<dialog #dialog>Hello World</dialog>`,
})
export class MyComponent {
  @ViewChild('dialog') dialogRef!: ElementRef;

  constructor() {
    afterNextRender(() => {
      this.dialogRef.nativeElement.showModal();
    });
  }
}

ম্যানুয়াল DOM ম্যানিপুলেশন স্থগিত করুন

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

ব্রাউজার-শুধু জাভাস্ক্রিপ্ট চালান

কিছু ক্ষেত্রে আপনার একটি লাইব্রেরি বা API থাকবে যা শুধুমাত্র ব্রাউজারে কাজ করে (উদাহরণস্বরূপ, একটি চার্ট লাইব্রেরি, কিছু IntersectionObserver ব্যবহার, ইত্যাদি)। শর্তসাপেক্ষে আপনি ব্রাউজারে চলছেন কিনা তা পরীক্ষা করার পরিবর্তে, বা সার্ভারে আচরণ বন্ধ করে দেওয়ার পরিবর্তে, আপনি কেবল afterNextRender ব্যবহার করতে পারেন:

@Component({
  /* ... */
})
export class MyComponent {
  @ViewChild('chart') chartRef: ElementRef;
  myChart: MyChart|null = null;
  
  constructor() {
    afterNextRender(() => {
      this.myChart = new MyChart(this.chartRef.nativeElement);
    });
  }
}

কাস্টম লেআউট সঞ্চালন

কখনও কখনও আপনাকে এমন কিছু লেআউট সম্পাদন করতে DOM-এ পড়তে বা লিখতে হতে পারে যা আপনার টার্গেট ব্রাউজার এখনও সমর্থন করে না, যেমন একটি টুলটিপ অবস্থান করা। afterRender এটির জন্য একটি দুর্দান্ত পছন্দ, কারণ আপনি নিশ্চিত হতে পারেন যে DOM একটি সামঞ্জস্যপূর্ণ অবস্থায় রয়েছে। afterRender এবং afterNextRender EarlyRead , Read বা Write এর একটি phase মান গ্রহণ করে। DOM লেআউটটি লেখার পরে পড়া ব্রাউজারকে লেআউটটি সিঙ্ক্রোনাসভাবে পুনরায় গণনা করতে বাধ্য করে, যা কার্যকারিতাকে গুরুতরভাবে প্রভাবিত করতে পারে (দেখুন: লেআউট থ্র্যাশিং )। তাই আপনার যুক্তিকে সঠিক পর্যায়গুলিতে সাবধানে বিভক্ত করা গুরুত্বপূর্ণ।

উদাহরণস্বরূপ, একটি টুলটিপ উপাদান যা পৃষ্ঠার অন্য উপাদানের সাথে সম্পর্কিত একটি টুলটিপ প্রদর্শন করতে চায় সম্ভবত দুটি পর্যায় ব্যবহার করবে। EarlyRead পর্বটি প্রথমে উপাদানগুলির আকার এবং অবস্থান অর্জন করতে ব্যবহৃত হবে:

afterRender(() => {
    targetRect = targetEl.getBoundingClientRect();
    tooltipRect = tooltipEl.getBoundingClientRect();
  }, { phase: AfterRenderPhase.EarlyRead },
);

তারপরে, Write পর্বটি টুলটিপটিকে প্রকৃতপক্ষে পুনঃস্থাপন করতে পূর্বে পড়া মান ব্যবহার করবে:

afterRender(() => {
    tooltipEl.style.setProperty('left', `${targetRect.left + targetRect.width / 2 - tooltipRect.width / 2}px`);
    tooltipEl.style.setProperty('top', `${targetRect.bottom - 4}px`);
  }, { phase: AfterRenderPhase.Write },
);

আমাদের যুক্তিগুলিকে সঠিক পর্যায়গুলিতে বিভক্ত করে, অ্যাঙ্গুলার কার্যকরভাবে প্রয়োগের অন্য প্রতিটি উপাদান জুড়ে DOM ম্যানিপুলেশন ব্যাচ করতে সক্ষম, একটি ন্যূনতম কর্মক্ষমতা প্রভাব নিশ্চিত করে।

উপসংহার

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