Langkah Mudah Mengonversi Markdown ke JSON di Hexo

Cara mengubah Markdown ke JSON
Image: generated with AI

Seperti yang sering saya sebutkan, Static Site Generator (SSG) seperti Hexo tidak memiliki database seperti web pada umumnya. Walau database tidak selalu diperlukan oleh sebuah web, akan tetapi ketiadaannya dapat menyulitkan.

Sebagai contoh, untuk menambahkan fitur pencarian di SSG kita memerlukan semacam database. Kalau datanya tidak ada, bagaimana melakukannya? Oleh sebab itu, diperlukan cara agar kita dapat membuat “database” sederhana yang berfungsi untuk menyimpan sekumpulan data dan mengelolanya.

Cara paling sederhana adalah dengan menggunakan format JSON, XML, CSV, YAML, atau TOML. Di artikel ini saya hanya akan membahas untuk format JSON.


Penjelasan Singkat tentang JSON

JSON, akronim dari JavaScript Son, eh, JavaScript Object Notation, bukanlah bahasa pemrograman. JSON adalah sebuah format untuk menyimpan dan mendistribusikan data. Nama file-nya ditulis dengan ekstensi .json. Contoh: nama-pegawai.json.

Data di dalam JSON kemudian bisa dikonsumsi oleh bahasa pemrograman lain untuk ditampilkan, dimodifikasi, atau digunakan dalam berbagai aplikasi. JSON sangat populer karena mudah dibaca dan ditulis oleh manusia, serta mudah diurai dan dihasilkan oleh mesin. JSON sering digunakan dalam aplikasi web untuk mengirim data antara server dan klien.

Format JSON pertama kali diperkenalkan pada April 2001 oleh programmer bernama Douglas Crockford dan masih jadi format transportasi data yang cukup tangguh hingga sekarang.

// Contoh data JSON
[
  {
    "nama": "Andi Prasetya",
    "jabatan": "Manajer",
    "departemen": "Pemasaran"
  },
  {
    "nama": "Siti Aisyah",
    "jabatan": "Staf Keuangan",
    "departemen": "Keuangan"
  },
  {
    "nama": "Budi Santoso",
    "jabatan": "Supervisor Produksi",
    "departemen": "Produksi"
  }
]

Dalam contoh di atas, kita memiliki array yang berisi tiga objek, masing-masing dengan properti nama, jabatan, dan departemen. JSON sangat fleksibel dan dapat digunakan untuk menyimpan berbagai jenis data, termasuk string, angka, array, dan objek.


Mengonversi Markdown ke JSON di Hexo: Tanpa Plugin

Kembali ke Markdown dan Hexo, kita bisa mengonversi Markdown ke format JSON agar data bisa diolah oleh JavaScript, EJS sebagai template engine, atau API Hexo. Ada dua cara melakukannya: tanpa plugin dan dengan plugin. Saya hanya akan membahas yang tanpa plugin.

Tujuannya adalah mengonversi semua post Markdown menjadi satu file JSON yang berisi daftar semua artikel blog Hexo kita.

Kita akan memanfaatkan kesaktian modul Node.js dan Generator API dari Hexo. Data sumber akan diambil dari API locals variable yang sudah disediakan Hexo, tanpa mengubah file Markdown itu sendiri.

Langkah 1: Instal Cheerio

Tidak seperti Hugo yang memiliki metode .Plain untuk mengambil konten tanpa tag HTML dari halaman, Hexo tidak memiliki itu. Jadi, kita akan menggunakan Cheerio untuk menghasilkan plain text di JSON.

Buka CLI atau terminal dan jalankan perintah npm install cheerio --save-dev untuk menginstal Cheerio sebagai dev dependency.

Mengapa kita perlu mengubahnya menjadi plain text segala?

Ada dua alasan. Pertama, bila tidak diubah maka semua tag HTML akan di-parsing ke file JSON. Sesuatu yang sebenarnya tidak perlu. Kedua, untuk mengurangi ukuran file JSON itu sendiri. Lumayan, sih, ukuran file bisa berkurang sebanyak 50%.

Langkah 2: Buat File Generator

Buat file generate-post-data.js di folder themes/theme-anda/scripts. Generator ini akan menghasilkan file .json yang berisi daftar artikel blog beserta metadata-nya. Berikut script yang perlu dimasukkan:

const fs = require('hexo-fs');
const path = require('path');
const cheerio = require('cheerio');

// Function to clean HTML using cheerio
const cleanHTML = html => {
  const $ = cheerio.load(html);
  
  // Handle <code> tags specifically, keeping the content formatted with backticks
  $('code').each(function() {
    const codeContent = $(this).text();
    $(this).replaceWith(`\`${codeContent}\``); // Wrap code content with backticks for better formatting
  });

  // Return the clean text, removing all HTML tags
  return $.text().trim();
};

hexo.extend.generator.register('langit_generate_post_data', function(locals) {
  // Generate data for each post
  const data = locals.posts.map(post => ({
    title: post.title || '',
    permalink: post.permalink || '',
    path: post.path || '',
    date: post.date.format('YYYY-MM-DD'),
    author: post.author || '',
    image: post.image || '',
    tags: post.tags ? post.tags.map(tag => tag.name) : [],
    categories: post.categories ? post.categories.map(category => category.name) : [],
    excerpt: cleanHTML(post.excerpt) || '',
    content: cleanHTML(post.content) || ''
  }));

  // Return route and save the data to the public folder
  return {
    path: 'data/post-data.json',
    data: JSON.stringify(data, null, 2)
  };
});

Perhatikan bahwa saya menggunakan langit_generate_post_data, ini adalah name atau identifier. Tidak ada keterangan khusus di Hexo tentang cara penulisan generator name, tapi saya mengikuti cara penulisan tag plugin Hexo dan identifier JavaScript pada umumnya. Tentu saja Anda dapat menggantinya dengan nama Anda sendiri.

Sebetulnya, generator API dirancang untuk membuat route, yang berfungsi sebagai endpoint untuk mengakses data tertentu. Namun, penggunaannya untuk membuat file JSON seperti post-data.json sebenarnya masih valid dan merupakan praktik yang sering dilakukan dalam skenario seperti ini.

Langkah 3: Build Ulang

Jalankan perintah hexo clean && hexo generate di terminal agar web dibangun ulang dan perubahan yang kita lakukan pada generator akan diterapkan.

Maka Hexo akan membuatkan file post-data.json di folder ./public/data. Data yang berada di sini dapat diakses melalui root URL baik di server lokal maupun di live server. Karena di folder public, itu artinya di client side. Dengan begini, kita dapat menggunakan JavaScript atau library pihak ketika untuk membuat berbagai fitur. Misalnya, fitur pencarian.

Coba akses http://localhost:4000/data/post-data.json di browser. Maka akan ada data artikel-artikel kita.

post-data.json
post-data.json
Notes:
  • Perhatikan bahwa path-nya adalah ./data/post-data.json, tanpa tanda / di akhir. Server akan me-render file ini sebagai file. Jika menggunakan tanda / di akhir seperti ./data/post-data.json/, server akan memperlakukannya sebagai route yang artinya harus ada file index.html. Bukan itu yang kita inginkan.

Langkah 4: Minify JSON (Opsional)

File JSON memang tidak berat-berat amat. Namun, seiring berjalannya waktu artikel kita pasti akan bertambah dan akan semakin besar pula file JSON-nya. Oleh karena itu, disarankan agar minify file JSON sebelum diunggah ke live server. Selain untuk mengurangi ukuran file, juga dapat mempercepat loading website.

Anda dapat melakukan itu dengan NodeJS atau berbagai toolkit, saya sendiri menggunakan Gulp.


Membuat Database di Folder Source

Selain database di client-side, kita juga perlu database di server-side. Database di server side inilah yang yang dapat dikonsumsi oleh API Hexo lainnya. Misalnya tag plugin, helper, atau renderer. Saya sendiri menggunakannya untuk keperluan membuat fitur “baca juga” dan mungkin beberapa fitur lainnya di masa depan. Anda dapat melewati langkah ini bila tidak memerlukannya.

“Kenapa tag plugin tidak langsung ambil data dari folder public saja?”

Secara teori, kita tidak punya akses langsung terhadap data di folder public selama proses render atau sebelum web di-build. Yang punya kekuasaan itu hanya JavaScript yang ada di client-side.

FYI, saat menjalankan perintah hexo generate, semua perintah yang ada di folder scripts akan dieksekusi. Generator API dijalankan paling terakhir. Jadi, kalau misalnya kita membuat tag plugin yang mengharuskan mengakses data, datanya tidak akan tersedia karena tag plugin sudah terlebih dahulu dijalankan sebelum generator.

Langkah 1: Copy File

File post-data.json yang telah dibuat sebelumnya akan kita copy ke folder ./source/_data. Saya menggunakan metode ini karena kita memang tidak berniat untuk membuat route. Kita hanya perlu file JSON-nya.

Sebab kalau kita menggunakan generator API untuk membuat file JSON dan disimpan di folder source langsung seperti cara membuat database sebelumnya, itu akan menyebabkan eror Unhandled rejection TypeError: data is required!

Buat file copy-data.js di root folder. Kemudian masukkan script berikut:

const fs = require('fs');
const path = require('path');
const hexoFs = require('hexo-fs');

// Direktori sumber dan tujuan
const srcDir = path.join(__dirname, 'public', 'data'); // Folder sumber di public/data
const destDir = path.join(__dirname, 'source', '_data'); // Folder tujuan di source/_data

// Fungsi untuk menyalin file/folder
async function copyFiles(srcDir, destDir) {
  try {
    // Cek jika folder tujuan ada, jika tidak, buat folder tersebut
    if (!fs.existsSync(destDir)) {
      fs.mkdirSync(destDir, { recursive: true });
    }

    const items = await hexoFs.readdir(srcDir); // Menggunakan hexo-fs untuk membaca direktori
    for (const item of items) {
      const srcPath = path.join(srcDir, item);
      const destPath = path.join(destDir, item);

      const stats = await hexoFs.stat(srcPath); // Cek apakah item adalah file atau direktori
      if (stats.isDirectory()) {
        // Rekursif untuk folder
        await copyFiles(srcPath, destPath);
      } else {
        // Salin file
        await hexoFs.copyFile(srcPath, destPath);
        console.log(`Copied: ${srcPath} -> ${destPath}`);
      }
    }
  } catch (err) {
    console.error('Error copying files:', err);
  }
}

// Jalankan proses salin file
(async () => {
  if (fs.existsSync(srcDir)) {
    await copyFiles(srcDir, destDir);
  } else {
    console.warn(`Source directory does not exist: ${srcDir}.`);
  }
})();

Langkah 2: Jalankan NodeJS

Setelah hexo clean && hexo generate dijalankan, jalankan perintah node copy-data.js di CLI. Maka NodeJS akan menyalin file ./public/data/post-data.json ke ./source/_data/post-daja.json.

Anda bisa memasukkan file copy-data.js ke dalam .gitignore karena kita hanya memerlukannya di local server.

Notes:
  • File copy-data.js sengaja dibuat di root folder agar keluar dari life cycle Hexo. Juga untuk memastikan bahwa file sumber (di folder public) telah tersedia sebelum disalin.
  • File tujuan sengaja ditempatkan di folder ./source/_data karena file di folder ini sepenuhnya diabaikan dan tidak dirender kembali ke folder public.
  • File post-data.json di mana pun, baik di folder source maupun di folder public, tentu saja tidak update secara live. Database hanya akan update ketika hexo generate dijalankan.
  • Bila kita menggunakan data dari file ini dengan tag plugin, misalnya, tidak perlu khawatir datanya hilang setelah proses render karena pada dasarnya, yang di-render hanyalah file HTML.

Selain ngoding sendiri, Anda juga dapat mengubah Markdown ke JSON menggunakan plugin pihak ketiga. Pilihlah metode mana saja yang menurut Anda nyaman.

Namun, saya tidak menemukan dokumentasi atau artikel lain tentang membuat database di folder source, menggunakan NodeJS adalah metode terbaik yang bisa saya temukan. (eL)

TAGS: Hexo
Langit Amaravati

Langit Amaravati

Web developer, graphic designer, techno blogger.

Suka dengan artikel-artikel di blog ini dan merasa mendapatkan manfaatnya? Dukung saya dengan mentraktir kopi. Dengan dukungan Anda, saya dapat terus menulis dan berkarya.

Hatur nuhun!

Traktir Kopi