Hydration mismatch terjadi ketika representasi Virtual DOM dari server tidak identik dengan struktur DOM yang dievaluasi pertama kali oleh client. Salah satu penyebab yang sulit dilacak adalah serialisasi string berbasis sistem berkas (file system path) langsung ke dalam komponen UI.

Root Cause: Evaluasi path.sep Antara Node.js dan Browser

Di lingkungan Node.js, modul standar path menyesuaikan perilakunya dengan sistem operasi host tempat proses berjalan:

  • Pada sistem operasi POSIX (Linux, macOS modern), path.sep bernilai slash tunggal (/).
  • Pada Windows, path.sep bernilai backslash (\).

Ketika aplikasi dieksekusi di server berbasis Windows (misalnya saat proses development lokal) atau memproses path tanpa normalisasi, server menghasilkan string HTML dengan separator \. Sebaliknya, saat di-bundle untuk client browser, pustaka polyfill atau bundler seperti Webpack/Vite menyetel modul path ke format POSIX standar, atau komponen menerima string yang tidak konsisten saat hydration berlangsung.

// Contoh output berbeda antar runtime
// Node.js di Windows Server:
const filePath = path.join('static', 'images', 'banner.png');
// Output server: "static\\images\\banner.png"

// Browser DOM Client mengharapkan:
// "static/images/banner.png"

Contoh Kasus Komponen Bermasalah

Kode berikut memperlihatkan komponen SSR (seperti Next.js, Nuxt, atau SvelteKit) yang memproses metadata file path di level modul atau langsung di dalam render loop.

import path from 'path';

export async function getServerSideProps() {
  const relativePath = path.join('uploads', 'documents', 'invoice.pdf');
  return {
    props: {
      filePath: relativePath,
    },
  };
}

export default function FileViewer({ filePath }) {
  return (
    <div>
      <p>File Path: <span className="path-text">{filePath}</span></p>
    </div>
  );
}

Jika server berjalan di platform Windows, server mengirimkan markup <span class="path-text">uploads\documents\invoice.pdf</span>. Jika client hydration mencoba memvalidasi atau memformat ulang path menggunakan API platform berbasis web, console akan menampilkan warning:

Warning: Text content did not match. Server: "uploads\documents\invoice.pdf" Client: "uploads/documents/invoice.pdf"

Solusi 1: Normalisasi ke Format POSIX Menggunakan path/posix

Metode paling efisien adalah memaksa penggunaan implementasi POSIX pada proses serialisasi data di server sebelum dikirimkan ke props komponen UI.

import path from 'path/posix';

export async function getServerSideProps() {
  // Mengabaikan OS host, selalu menghasilkan format POSIX kanonikal
  const relativePath = path.join('uploads', 'documents', 'invoice.pdf');
  return {
    props: {
      filePath: relativePath, // Selalu "uploads/documents/invoice.pdf"
    },
  };
}

Alternatif tanpa mengubah import module adalah dengan melakukan regex replace secara eksplisit sebelum data di-render:

function toPosixPath(inputPath) {
  return inputPath.replace(/\\+/g, '/');
}

Solusi 2: Menunda Rendering Path ke Client Lifecycle

Jika aplikasi memang perlu menampilkan path absolut lokal sistem operasi pengguna (misalnya pada aplikasi desktop berbasis Electron yang menggunakan SSR/hydration), jangan render nilai tersebut ke SSR HTML. Tunda rendering hingga fase mounting client selesai.

import { useState, useEffect } from 'react';

export default function NativePathViewer({ nativePath }) {
  const [displayPath, setDisplayPath] = useState(null);

  useEffect(() => {
    // Hanya dievaluasi setelah hydration selesai pada client
    setDisplayPath(nativePath);
  }, [nativePath]);

  return (
    <div>
      <p>Platform Path: {displayPath ? displayPath : 'Memuat path...'}</p>
    </div>
  );
}

Panduan Praktik Terbaik

  • Terapkan Batas Serialisasi: Semua metadata sistem berkas yang dikirim dari lapisan backend/server runtime ke client harus berupa representasi URL-friendly (URI kanonikal dengan forward-slash).
  • Gunakan URL Objek untuk Resource Web: Jangan gunakan path.join() untuk membentuk path gambar atau file statis; gunakan pustaka url atau konstruktor standar new URL().
  • Tetapkan Lint Rule: Larang pemanggilan modul path langsung pada kode komponen isomorphic (komponen yang dieksekusi di server dan client).