Next.js _document.js: Custom HTML, Global Scripts & SEO | Sinhala Guide

Next.js _document.js: Custom HTML, Global Scripts & SEO | Sinhala Guide

කට්ටියට කොහොමද? Next.js එක්ක වැඩ කරනකොට අපිට පුළුවන් නේද ලස්සනට UI එකක් හදන්න, SSR (Server-Side Rendering) වගේ දේවල් පාවිච්චි කරලා performance එක වැඩි කරන්න. ඒත් සමහර වෙලාවට, අපිට අවශ්‍ය වෙනවා අපේ App එකේ මුලික HTML Structure එකටම (<html>, <body> tags වලට) වෙනස්කම් කරන්න. සාමාන්‍යයෙන් අපි <head> tag එකට දේවල් දාන්න next/head පාවිච්චි කරනවනේ. ඒත් <html> හෝ <body> tag වලට custom attributes එකතු කරන්න, නැත්නම් Next.js වලින් manage නොකරන third-party scripts වගේ දේවල් global විදිහට මුලින්ම load කරන්න ඕන වුණොත් මොකද කරන්නේ? මෙන්න මේ වගේ අවස්ථා වලදී තමයි අපේ ගැලවුම්කරුවා, _document.js කියන file එක අපිට උදව්වට එන්නේ.

මේ guide එකෙන් අපි _document.js කියන්නේ මොකක්ද, ඒක කොහොමද වැඩ කරන්නේ, ඒකෙන් අපිට මොනවද කරන්න පුළුවන්, සහ ඒක පාවිච්චි කරනකොට සැලකිලිමත් වෙන්න ඕන දේවල් මොනවද කියලා සවිස්තරාත්මකව බලමු. ඔයා Next.js developer කෙනෙක් නම්, මේ concept එක දැනගෙන ඉන්න එක ඔයාගේ project වලට ලොකු වටිනාකමක් ගෙනෙයි.

1. _document.js කියන්නේ මොකක්ද? (What is _document.js?)

සරලව කිව්වොත්, _document.js කියන්නේ Next.js App එකක් server-side render වෙනකොට Generate වෙන මුලික HTML පිටුව (document) එක customize කරන්න අපිට අවස්ථාව දෙන file එකක්. මේකෙන් අපිට පුළුවන් <html>, <body> tags වලට custom attributes එකතු කරන්න, <head> tag එකට Next.js manage නොකරන global meta tags, custom fonts, CSS, හෝ JavaScript files වගේ දේවල් inject කරන්න.

_app.js සහ next/head වලින් _document.js වෙනස් වෙන්නේ කොහොමද?

  • _app.js: මේක Client-Side App එක Initialize කරන තැන. ඔයාගේ හැම page එකකටම පොදු UI logic, global styles, හෝ state management provider set up කරන්න මේක පාවිච්චි කරනවා. _app.js එක Client-Side එකේදීත් run වෙනවා, ඒත් _document.js එහෙම නැහැ.
  • next/head: මේකෙන් අපිට පුළුවන් page එකෙන් page එකට <head> tag එක ඇතුළත titles, meta descriptions, canonical URLs වගේ දේවල් වෙනස් කරන්න. මේක page-specific වෙනස්කම් වලට.
  • _document.js: මේක server-side එකේදී විතරයි run වෙන්නේ. Client-side එකේදී මේකේ logic run වෙන්නේ නැහැ. මේකේ ප්‍රධානම කාර්යය තමයි <html>, <body> වගේ මුලික HTML elements වලට වෙනස්කම් කරන්න, සහ global විදිහට හැම page එකකටම බලපාන scripts හෝ styles මුලින්ම load කරන්න. ඒ වගේම, මේකේ React state, hooks වගේ client-side specific දේවල් පාවිච්චි කරන්න බැහැ.

ඉතින්, _document.js කියන්නේ ඔයාගේ Next.js App එකේ fundamental HTML structure එකටම අත තියන්න පුළුවන් tool එකක්. ඒක පාවිච්චි කරනකොට පොඩි සැලකිල්ලක් දක්වන්න ඕනේ, මොකද ඒක කරන වෙනස්කම් ඔයාගේ මුළු App එකටම බලපානවා.

2. Practical Implementation: _document.js වෙනස් කරමු (Let's Modify _document.js)

_document.js එකක් හදන්න ඉතාම ලේසියි. ඔයාගේ project එකේ pages folder එක ඇතුළේ _document.js කියලා file එකක් හදන්න විතරයි තියෙන්නේ. (ඔයා app directory එක පාවිච්චි කරනවා නම්, මේ concept එක ටිකක් වෙනස්. මේ tutorial එක pages directory එක focus කරලා හදලා තියෙන්නේ.)

මුලික _document.js Structure එක

මුලින්ම, මේක තමයි සාමාන්‍ය _document.js file එකක structure එක:

import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html lang="en"> {/* මෙතන තමයි අපේ custom HTML tags එන්නේ */}
      <Head>
        {/* මෙතනට ඔයාට global meta tags, font links වගේ දේවල් දාන්න පුළුවන් */}
      </Head>
      <body>
        <Main /> {/* මේකෙන් තමයි Next.js ඔයාගේ pages render කරන්නේ */}
        <NextScript /> {/* මේකෙන් තමයි Next.js විසින් අවශ්‍ය කරන JavaScript bundles load කරන්නේ */}
      </body>
    </Html>
  );
}

මේ file එක Next.js server එකෙන් generate කරලා client-side එකට යවන්නේ එක වතාවක් විතරයි, App එක load වෙනකොට. ඒක නිසා මේක ඇතුළේ ඔයා කරන ඕනෑම වෙනසක් App එකේ හැම page එකකටම බලපානවා.

ප්‍රායෝගික උදාහරණ:

උදාහරණය 1: <html> tag එකට custom lang attribute එකක් දාමු

Search Engine Optimization (SEO) සහ Accessibility වලට <html> tag එකේ lang attribute එක හරියට දාලා තියෙන එක ගොඩක් වැදගත්. Next.js App එකක default විදිහට lang="en" තියෙන්නේ. අපිට ඒක "si" (සිංහල), "ta" (දෙමළ) හෝ වෙනත් භාෂාවකට වෙනස් කරන්න පුළුවන්.

import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html lang="si"> {/* <html> tag එකට lang="si" කියලා දානවා */}
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

මේ වෙනසත් එක්ක, ඔයාගේ App එක browser එකේ render වෙනකොට, HTML document එකේ root element එක මේ වගේ පෙනෙයි:

<html lang="si">
  <head>...
  </head>
  <body>...
  </body>
</html>

මේක ගොඩක් සරල වෙනසක් වුණත්, Accessibility tools වලට සහ Search Engines වලට ඔයාගේ content එකේ භාෂාව තේරුම් ගන්න මේක ලොකු උදව්වක්.

උදාහරණය 2: Third-party scripts (e.g., Google Analytics, Custom Fonts) එකතු කිරීම

ඔයාට Google Analytics වගේ tracking scripts, හෝ Google Fonts වගේ custom font loaders App එකේ හැම page එකකටම load කරන්න ඕන වුණොත්, _document.js එක තමයි හොඳම තැන. මොකද මේවා global scripts, සහ මේවා page-specific නොවී මුලින්ම load වෙන්න ඕනේ.

import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html lang="si">
      <Head>
        {/* Google Fonts Link - preload කරන්න අවශ්‍ය නම් මෙතනට දාන්න */}
        <link
          href="https://fonts.googleapis.com/css2?family=Noto+Sans+Sinhala:wght@400;700&display=swap"
          rel="stylesheet"
        />
        {/* Google Analytics Script - head එකේ උඩින්ම දාන්න ඕන scripts මෙතනට දාන්න */}
        {process.env.NODE_ENV === 'production' && (
          <>
            <script
              async
              src="https://www.googletagmanager.com/gtag/js?id=YOUR_GA_TRACKING_ID"
            />
            <script
              dangerouslySetInnerHTML={{
                __html: `
                  window.dataLayer = window.dataLayer || [];
                  function gtag(){dataLayer.push(arguments);}
                  gtag('js', new Date());
                  gtag('config', 'YOUR_GA_TRACKING_ID');
                `,
              }}
            />
          </>
        )}
      </Head>
      <body>
        <Main />
        {/* සමහර third-party scripts body එකේ අන්තිමට load කරන්න ඕන වෙනවා */}
        {/* උදා: Intercom Messenger, Stripe widgets වගේ දේවල් */}
        {/* <script src="https://example.com/some-other-script.js" /> */}
        <NextScript />
      </body>
    </Html>
  );
}

සැලකිය යුතුයි: YOUR_GA_TRACKING_ID කියන තැනට ඔයාගේ Google Analytics ID එක දාන්න. ඒ වගේම, process.env.NODE_ENV === 'production' කියන condition එකෙන් අපි sure කරනවා Google Analytics script එක production environment එකේදී විතරක් load වෙනවා කියලා.

මේ විදිහට scripts දානකොට dangerouslySetInnerHTML කියන prop එක පාවිච්චි කරන්න වෙනවා. මේක පාවිච්චි කරනකොට පොඩි ආරක්ෂක අවදානමක් තියෙනවා (XSS attacks), ඒත් Google Analytics වගේ trusted scripts වලට මේක සාමාන්‍ය දෙයක්. හැබැයි, unknown sources වලින් scripts දානකොට ගොඩක් පරිස්සම් වෙන්න ඕනේ.

3. _document.js Lifecycle සහ කාර්යසාධනය (Lifecycle and Performance of _document.js)

_document.js ගොඩක් powerful වුණත්, ඒක පාවිච්චි කරනකොට මතක තියාගන්න ඕන වැදගත් කරුණු කිහිපයක් තියෙනවා:

  • Server-Side Only: මේක Client-side එකේ run වෙන්නේ නැහැ. ඒකෙන් කියවෙන්නේ ඔයාට මේක ඇතුළේ useState, useEffect වගේ React Hooks හෝ event handlers වගේ client-side JavaScript logic දාන්න බැහැ. එහෙම දැම්මොත් error එන්න පුළුවන්, නැත්නම් App එකේ hydration එක අවුල් වෙන්න පුළුවන්.
  • No Data Fetching: මේක ඇතුළේ page-specific data fetch කරන්න එපා. getInitialProps වගේ methods පාවිච්චි කරන්න පුළුවන් වුණත්, ඒක සාමාන්‍යයෙන් Page components වලට හෝ _app.js වලට සීමා කරන එක තමයි හොඳම පුරුද්ද. _document.js එකේදී data fetch කළොත්, ඒක App එකේ Initial Page Load එකට බලපාලා performance එක අඩු කරන්න පුළුවන්.
  • Performance Regressions: _document.js එකට අනවශ්‍ය scripts හෝ styles ගොඩක් දැම්මොත්, First Contentful Paint (FCP) සහ Largest Contentful Paint (LCP) වගේ Core Web Vitals වලට අහිතකර විදිහට බලපාන්න පුළුවන්. හැම වෙලාවෙම හිතන්න මේ script එක ඇත්තටම global විදිහට load වෙන්න ඕනෙද, නැත්නම් ඒක specific page එකකට විතරක් Load කරන්න බැරිද කියලා.

getInitialProps (Advanced)

_document.js එකට getInitialProps කියන static async method එක add කරන්න පුළුවන්. මේකෙන් අපිට පුළුවන් server-side එකේදී document එක render කරන්න කලින් server-side data fetch කරලා, ඒ data එක document එකේ props විදිහට ලබාගන්න. උදාහරණයක් විදිහට, server එකේ තිබෙන request headers වලින් භාෂාව detect කරලා <html> tag එකේ lang attribute එක dynamic විදිහට set කරන්න පුළුවන්.

import Document, { Html, Head, Main, NextScript } from 'next/document';

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    // ඔයාට අවශ්‍ය data මෙතනින් fetch කරන්න පුළුවන්
    const language = ctx.req?.headers['accept-language']?.split(',')[0] || 'en';
    return { ...initialProps, language };
  }

  render() {
    return (
      <Html lang={this.props.language}> {/* dynamic lang attribute */}
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

මේ උදාහරණයේදී, අපි request header එකේ 'accept-language' වලින් browser එකේ preferred language එක අරගෙන, lang attribute එකට දානවා. මේක dynamic Language support එකකට හොඳ approach එකක්.

4. හොඳම පුරුදු සහ පොදු ගැටළු (Best Practices and Common Issues)

  • Use Sparingly: _document.js පාවිච්චි කරන්න ඕන වෙන්නේ next/head හෝ _app.js වලින් ඔයාගේ අවශ්‍යතාවය සපුරාගන්න බැරි නම් විතරයි. මේක තමයි ප්‍රධානම Best Practice එක.
  • Server-Side Concerns Only: මේක ප්‍රධාන වශයෙන් server-rendered HTML adjustments වලට විතරක් පාවිච්චි කරන්න. Global Analytics, Web Fonts, Critical CSS වගේ දේවල් වලට මේක සුදුසුයි.
  • Avoid Client-Side Logic: React state, hooks, event listeners, හෝ client-side data fetching මේක ඇතුළේ කරන්න එපා. ඒ වගේ දේවල් _app.js, page components, හෝ custom hooks වලට සීමා කරන්න.
  • Maintain Readability: _document.js file එක clean සහ කියවීමට පහසු විදිහට තියාගන්න. අනවශ්‍ය code blocks හෝ comments වලින් පුරවන්න එපා.
  • Third-Party Scripts: Third-party scripts දානකොට ඒවායේ load order එක සහ performance impact එක ගැන හිතන්න. සමහර scripts <head> එකේ මුලින්ම load වෙන්න ඕනේ, තවත් සමහර ඒවා <body> එකේ අන්තිමට load වෙන එක performance එකට හොඳයි.
  • NextScript සහ Main: <Main /> සහ <NextScript /> components අයින් කරන්න එපා, නැත්නම් Next.js App එක හරියට render වෙන්නේ නැහැ. මේවා Next.js ecosystem එකේ වැදගත් කොටස්.

අවසාන වශයෙන් (Conclusion)

_document.js කියන්නේ Next.js App එකක මුලික HTML structure එක customized කරගන්න පුළුවන් ඉතාම powerful tool එකක්. <html> tag එකේ lang attribute එක වෙනස් කිරීමේ සිට, global third-party scripts සහ custom fonts එකතු කිරීම දක්වා බොහෝ දේ මේකෙන් කරන්න පුළුවන්. ඒත් මේක server-side එකේදී විතරයි run වෙන්නේ කියන එකත්, client-side logic මේක ඇතුළේ පාවිච්චි කරන්න බැහැ කියන එකත් හැම වෙලාවෙම මතක තියාගන්න ඕනේ.

මේක පරිස්සමෙන් පාවිච්චි කළොත්, ඔයාගේ Next.js App එකේ SEO, Accessibility, සහ global script management වලට ලොකු වටිනාකමක් එකතු කරන්න පුළුවන්. හැම වෙලාවෙම Best Practices අනුගමනය කරන්න, අනවශ්‍ය විදිහට මේක customize නොකර ඉන්න, සහ ඔයා කරන වෙනස්කම් App එකේ performance එකට බලපාන්නේ කොහොමද කියලා නිතරම බලන්න.

ඉතින්, මේ tutorial එක ඔයාට _document.js ගැන පැහැදිලි අවබෝධයක් ලබාදෙන්න ඇති කියලා හිතනවා. ඔයාගේ Next.js project වල මේ දැනුම පාවිච්චි කරලා අලුත් දේවල් try කරලා බලන්න. ඔයාට මේ ගැන තියෙන ප්‍රශ්න, අදහස්, හෝ ඔයාගේ අත්දැකීම් පහළින් comment section එකේ අපිත් එක්ක බෙදාගන්න පුළුවන්!

Happy Coding!