21 Oct 2019

Membuat static site dengan Nuxt.js

javascript vue

Selamat tinggal website yang dulu...

warning: this site not using this method anymore, since I cant figure it out how to do dynamic SEO in Nuxt.js, more on this information I'll explain in here but you can still use this guide to create Nuxt.js simple blog :)

Hai! 😃 dan selamat datang di blog baru ini sebelumnya maaf jika ini memakan waktu lama hanya untuk website dengan fitur tak banyak ini. JAMStack sendiri sudah cukup lama berkembang sejak saya mengenalnya 2017 lalu melalui sebuah perusahaan bernama netlify yang berhasil me-rework sebuah website yang suka saya kunjungi saat sedang belajar programming sampai sekarang berkarir di dunia ini.

Cukup simple #

KISS dengan adanya banyak bantuan dari module di NPM... Cukup simple dan bahkan sebenarnya kita dapat menyelesaikannya satu hari.

Markdown Parsing #

Bagian markdown-parsing saya menggunakan markdown-it module ofisial dari nuxtjs. Saya agak mendapatakan sedikit trouble menggunakan mdx padahal menurut saya ini lebih powerfull daripada sekedar parsing. Karena saya menganut filosofi dadi sik update sesuk maka saya memilih markdown-it

modules: ['@nuxtjs/markdownit'],
markdownit: {
html: true,
preset: 'default',
linkify: true,
breaks: true
}

dan kita bisa menggunakannya dengan

<template>
<div v-html="postContent"/>
</template>

<script>
export default {
computed: {
postContent() {
const post = this.$store.state.post
// path to filename
return require(`../../content/post/${post.filename}.md`)
}
}
}
</script>

Content Title and Blogpost Meta #

Untuk hal ini saya manfaatkan YAML front matter pada markdown. Sayangnya markdown-it mendeteksi YAML front matter ini sebagai h2 dan di parse ke html 😄 jadi ya saya nemu workaround yang paling tidak bekerja di website saya.

// remove yaml from blogpost 😁
mounted() {
const h2 = document.getElementsByTagName('h2')
h2[0].outerHTML = ''
}

Kembali ke topik meta tadi untuk parser YAML saya memakai gray-matter sebenarnya ini terlalu powerfull-sih tapi saya tidak bisa menemukan yang lebih simple lagi di NPM. Lalu kita buat simple script untuk men-generate meta kita.

// create-post-list.js

const fs = require("fs");
const matter = require("gray-matter");
// eslint-disable-next-line no-path-concat
const files = fs.readdirSync(__dirname + "/content/post");

console.time("⏲");

const posts = [];

for (const i in files) {
// eslint-disable-next-line no-path-concat
const str = fs.readFileSync(__dirname + `/content/post/${files[i]}`, "utf8");
const post = matter(str).data;
posts.push(post);
}

// to JSON
const data = JSON.stringify(posts);
fs.writeFileSync("blogposts.json", data);

console.timeEnd("⏲");

Bang! dengan ini kita punya single source of truth yang gampang kita gunakan, adanya blogposts.json ini bisa digunakan juga untuk mempermudah proses generate route di nuxt.config.js

// nuxt.config.js

const blogJSON = require("./blogposts.json");

function generateStaticRoute() {
const route = [];
for (let i = 0; i < blogJSON.length; i++) {
// add /blog in frot of string
const blog = blogJSON[i].slug.replace(/^/, "/blog/");
route.push(blog);
}
return route;
}

// pages routes automaticaly generated with nuxt 🚄
module.exports = {
generate: {
routes: generateStaticRoute(),
},
};

dengan tambahan script di package.json untuk run ini selesai sudah.

Kita juga gunakan blogpost.json tadi pada vuex store untuk fetch data artikel ini.

import dataJson from "../blogposts.json";

export const state = () => ({
posts: [],
post: {},
});

export const mutations = {
updatePosts(state, postsJSON) {
state.posts = postsJSON;
},
updatePost(state, { post }) {
state.post = post;
},
};

export const actions = {
getPost({ commit, state }, slug) {
const post = state.posts.find((post) => {
return post.slug === slug;
});
commit("updatePost", { post: post });
},
getListOfPost({ commit, state }) {
if (state.posts.length === 0) commit("updatePosts", dataJson);
},
};

naaah dengan ini kita fetch meta data blogpost kita yg ada pada markdown di vue-template

fetch({ store, params }) {
// in case user reload the page
store.dispatch('getListOfPost')
// fetch post
store.dispatch('getPost', params.slug)
},

Code highlighting #

Saya pilih yang paling ringan Prism.js penggunaannya cukup simple.

// _slug.vue
mounted() {
const block = document.querySelectorAll('code')
for (let i = 0; i < block.length; ++i) {
block[i].classList.add('language-javascript')
}
// remove yaml title
const h2 = document.getElementsByTagName('h2')
h2[0].outerHTML = ''
// hightlight code
Prism.highlightAll()
}

Enaknya memakai prism sendiri ini style dapat kita kustomisasi dengan mudah 😍.

Still on progress #

Jika anda membaca sampai sini ini isinya hanya curhatan saja. Saya ada juga mengalami blocker lain selain kesusahan saat mengapliaksikan mdx di project ini. Salah-satunya adalah purgecss, project ini menggunakan TailwindCSS dimana jika tidak di kompress atau dikurangi class yang tidak digunakan maka size CSS-nya cukup besar yaitu 38.6kb.

Saat saya memutuskan menggukan purgecss, CSS custom saya banyak kena trim 😄 walaupun sudah saya include beberapa class yang tidak boleh di trim. Saya selalu strich soal size, saya sering curi soure code-nya lodash kalau hanya dipakai 4/6 fungsi saja pada proyek saya daripada harus meng-install-nya.

Commenting on blog sebenarnya saya mau menyematkan fitur komen pada blog ini, menggunakan utteranc.es darapida discus ... tapi kok style-nya kurang cocok jadi saya harus menyesuaikannya sedikit dengan website ini.

Karena saya tidak begitu paham paham benar soal CSS. Kadang masih bingung ini kenapa height: 100% kok tidak bisa bisa 😂. Dengan ini saya nyatakan itu fitur berikutnya saja hehe.

I'm backend dev

Okay semoga anda menikmati first-post saya ini dan mendapat setidaknya sedikit ilmu 😁 oh yah untuk meninggalkan komen anda dapat mengunjungi github issue ini sambil saya coba coba integrasi untterances tadi.

Tidak lupa source code untuk website ini ada di sini