2026 ਵਿੱਚ ਜ਼ੀਰੋ ਤੋਂ ਇੱਕ ਕਸਟਮ ਬਲੌਗ ਬਣਾਉਣਾ ਇੱਕ ਸੋਚਿਆ-ਸਮਝਿਆ ਫੈਸਲਾ ਹੈ। ਜ਼ਿਆਦਾਤਰ ਲੇਖਕ ਸਿਰਫ਼ ਇੱਕ ਹੋਸਟਡ ਪਲੇਟਫਾਰਮ ਚੁਣਦੇ ਹਨ ਅਤੇ ਅੱਗੇ ਵਧਦੇ ਹਨ। ਮੈਂ ਆਪਣੇ ਟੈਕ ਬਲੌਗ ਨੂੰ Astro ਨਾਲ ਮੁੜ ਬਣਾਉਣ ਦਾ ਫੈਸਲਾ ਕੀਤਾ ਕਿਉਂਕਿ ਮੈਂ ਸਟੈਕ ਦੇ ਹਰ ਪੱਧਰ 'ਤੇ ਆਪਣਾ ਕੰਟਰੋਲ ਚਾਹੁੰਦਾ ਸੀ ਅਤੇ ਉਹਨਾਂ ਪੈਟਰਨਾਂ ਨੂੰ ਸਿੱਖਣਾ ਚਾਹੁੰਦਾ ਸੀ ਜੋ ਇੱਕ ਸਟੈਟਿਕ ਸਾਈਟ ਨੂੰ ਸਿਰਫ਼ ਵੱਖਰਾ ਹੀ ਨਹੀਂ, ਸਗੋਂ ਤੇਜ਼ ਵੀ ਬਣਾਉਂਦੇ ਹਨ। ਇਸ ਦਾ ਨਤੀਜਾ ਇੱਕ ਦੋ-ਭਾਸ਼ਾਈ ਸਾਈਟ ਹੈ ਜੋ ਜਾਪਾਨੀ ਅਤੇ ਅੰਗਰੇਜ਼ੀ ਸਮੱਗਰੀ ਪ੍ਰਦਾਨ ਕਰਦੀ ਹੈ, ਡਿਫੌਲਟ ਰੂਪ ਵਿੱਚ ਜ਼ੀਰੋ JavaScript ਭੇਜਦੀ ਹੈ, ਅਤੇ ਹਰ ਤਰ੍ਹਾਂ ਦੀ ਗੁੰਝਲਦਾਰੀ ਨੂੰ ਵਿਜ਼ਿਟਰ ਦੇ ਬ੍ਰਾਊਜ਼ਰ ਦੀ ਬਜਾਏ ਮੇਰੀ ਮਸ਼ੀਨ 'ਤੇ ਰੱਖਦੀ ਹੈ।

ਇੱਥੇ ਉਹ ਪੰਜ ਪੈਟਰਨ ਹਨ ਜਿਨ੍ਹਾਂ ਨੇ ਇਸ ਨੂੰ ਕਾਮਯਾਬ ਬਣਾਇਆ।

Zod ਦੇ ਨਾਲ Content Collections

Astro ਦੇ Content Collections ਸਿਰਫ਼ Markdown ਫਾਈਲਾਂ ਨੂੰ ਫੋਲਡਰਾਂ ਵਿੱਚ ਸੰਗਠਿਤ ਕਰਨ ਤੋਂ ਕਿਤੇ ਵੱਧ ਕਰਦੇ ਹਨ। ਉਹ ਤੁਹਾਡੀ ਸਮੱਗਰੀ ਅਤੇ ਤੁਹਾਡੇ ਕੋਡ ਦੇ ਵਿਚਕਾਰ ਇੱਕ ਸਮਝੌਤਾ (contract) ਲਾਗੂ ਕਰਦੇ ਹਨ। ਮੈਂ ਹਰ ਆਰਟੀਕਲ ਕਲੈਕਸ਼ਨ ਨਾਲ ਇੱਕ Zod schema ਲਗਾਇਆ ਹੈ, ਜਿਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਬਿਲਡ ਸਟੈਪ ਇੱਕ ਵੀ ਪੇਜ ਰੈਂਡਰ ਹੋਣ ਤੋਂ ਪਹਿਲਾਂ frontmatter ਦੀ ਜਾਂਚ ਕਰਦਾ ਹੈ।

ਇਸ schema ਲਈ ਇੱਕ language ਫੀਲਡ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ ਜੋ ਸਿਰਫ਼ ਦੋ ਮੁੱਲ ਸਵੀਕਾਰ ਕਰਦੀ ਹੈ: ja ਜਾਂ en। ਇਸ ਵਿੱਚ ਕੋਈ ਅਸਪਸ਼ਟਤਾ ਨਹੀਂ ਹੈ ਕਿ ਪਾਠਕ ਨੂੰ ਕਿਹੜੀ ਭਾਸ਼ਾ ਮਿਲੇਗੀ। ਮੈਂ ਇੱਕ pair ਫੀਲਡ ਵੀ ਜੋੜੀ ਹੈ ਜੋ ਅਨੁਵਾਦਾਂ ਨੂੰ ਆਪਸ ਵਿੱਚ ਜੋੜਦੀ ਹੈ। ਜੇਕਰ ਮੈਂ ਜਾਪਾਨੀ ਵਿੱਚ Astro ਬਾਰੇ ਇੱਕ ਪੋਸਟ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰਦਾ ਹਾਂ ਅਤੇ ਬਾਅਦ ਵਿੱਚ ਇਸਦਾ ਅੰਗਰੇਜ਼ੀ ਵਿੱਚ ਅਨੁਵਾਦ ਕਰਦਾ ਹਾਂ, ਤਾਂ ਦੋਵੇਂ ਫਾਈਲਾਂ ਇੱਕੋ ਹੀ pair ID ਸਾਂਝੀ ਕਰਦੀਆਂ ਹਨ। ਇਸ ਨਾਲ ਲੈਂਗੂਏਜ ਸਵਿਚਰ ਬਣਾਉਣਾ ਬਹੁਤ ਸੌਖਾ ਹੋ ਜਾਂਦਾ ਹੈ ਕਿਉਂਕਿ ਰਿਸ਼ਤਾ ਡੇਟਾ ਵਿੱਚ ਸਪਸ਼ਟ ਹੁੰਦਾ ਹੈ, ਨਾ ਕਿ ਫਾਈਲ ਦੇ ਨਾਮਾਂ ਤੋਂ ਅੰਦਾਜ਼ਾ ਲਗਾਇਆ ਜਾਂਦਾ ਹੈ।

ਮਿਤੀਆਂ (Dates) Markdown frontmatter ਤੋਂ ਸਟ੍ਰਿੰਗਸ ਵਜੋਂ ਆਉਂਦੀਆਂ ਹਨ, ਇਸ ਲਈ schema ਉਹਨਾਂ ਨੂੰ ਆਪਣੇ ਆਪ ਅਸਲੀ Date ਆਬਜੈਕਟਾਂ ਵਿੱਚ ਬਦਲ ਦਿੰਦਾ ਹੈ। ਇਹ ਮੇਰੇ ਪੇਜ ਟੈਂਪਲੇਟਾਂ ਦੇ ਅੰਦਰ ਸਟ੍ਰਿੰਗ-ਮੈਂਗਲਿੰਗ ਲੌਜਿਕ ਨੂੰ ਖਤਮ ਕਰ ਦਿੰਦਾ ਹੈ। ਹਾਲਾਂਕਿ, ਸਭ ਤੋਂ ਮਹੱਤਵਪੂਰਨ ਫਾਇਦਾ ਇਸਦਾ ਫੇਲ੍ਹ ਹੋਣ ਦਾ ਤਰੀਕਾ (failure mode) ਹੈ। ਜੇਕਰ ਕਿਸੇ ਫਾਈਲ ਵਿੱਚ ਕੋਈ ਲੋੜੀਂਦੀ ਫੀਲਡ ਗੁੰਮ ਹੈ ਜਾਂ ਗਲਤ ਭਾਸ਼ਾ ਕੋਡ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਗਈ ਹੈ, ਤਾਂ ਬਿਲਡ ਤੁਰੰਤ ਇੱਕ ਸਪਸ਼ਟ ਗਲਤੀ (error) ਦੇ ਨਾਲ ਕ੍ਰੈਸ਼ ਹੋ ਜਾਂਦਾ ਹੈ। ਮੈਂ ਇਸਨੂੰ ਡਿਪਲਾਈਮੈਂਟ ਤੋਂ ਬਾਅਦ ਟੁੱਟੇ ਹੋਏ ਲੇਆਉਟ ਜਾਂ ਚੁੱਪਚਾਪ 404 ਹੋਣ ਦੀ ਖੋਜ ਕਰਨ ਦੀ ਬਜਾਏ ਆਪਣੇ ਟਰਮੀਨਲ ਵਿੱਚ ਹੀ ਠੀਕ ਕਰ ਲੈਂਦਾ ਹਾਂ।

ਆਰਟੀਕਲ ਕਨਵਰਸ਼ਨ ਪਾਈਪਲਾਈਨ

ਮੈਂ ਪਹਿਲੇ ਦਿਨ ਤੋਂ ਹੀ ਹਰ ਪੋਸਟ ਇਸ ਨਵੇਂ ਫਾਰਮੈਟ ਵਿੱਚ ਨਹੀਂ ਲਿਖੀ ਸੀ। ਸਾਲਾਂ ਦੀ ਸਮੱਗਰੀ Zenn ਅਤੇ Dev.to 'ਤੇ ਸੀ, ਜਿੱਥੇ ਹਰੇਕ ਪਲੇਟਫਾਰਮ ਦੇ ਆਪਣੇ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਅਤੇ ਪ੍ਰੋਪਰਾਈਟਰੀ ਸਿੰਟੈਕਸ ਹਨ। ਕਾਪੀ-ਪੇਸਟ ਕਰਨ ਅਤੇ ਹੱਥ ਨਾਲ ਠੀਕ ਕਰਨ ਦੀ ਬਜਾਏ, ਮੈਂ ਇੱਕ TypeScript ਸਕ੍ਰਿਪਟ ਲਿਖੀ ਜੋ ਪੂਰੇ ਆਰਟੀਕਲ ਦੇ ਬੈਚ ਨੂੰ ਮਿਆਰੀ Markdown ਵਿੱਚ ਬਦਲ ਦਿੰਦੀ ਹੈ।

Zenn ਟਿਪਸ ਅਤੇ ਚੇਤਾਵਨੀਆਂ ਲਈ ਕਸਟਮ ਕਾਲਆਊਟ ਸਿੰਟੈਕਸ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਮੇਰੀ ਸਕ੍ਰਿਪਟ ਉਹਨਾਂ ਨੂੰ ਸੈਮੈਂਟਿਕ HTML aside ਟੈਗਸ ਵਿੱਚ ਬਦਲ ਦਿੰਦੀ ਹੈ ਤਾਂ ਜੋ ਉਹ ਸਾਈਟ 'ਤੇ ਇੱਕੋ ਜਿਹੇ ਦਿਖਾਈ ਦੇਣ। Dev.to ਐਂਬੈਡਸ ਅਤੇ ਵਿਸ਼ੇਸ਼ ਬਲਾਕਾਂ ਲਈ Liquid ਟੈਗਸ 'ਤੇ ਨਿਰਭਰ ਕਰਦਾ ਹੈ। ਪਾਈਪਲਾਈਨ ਉਹਨਾਂ ਨੂੰ ਸਾਧਾਰਨ Markdown ਲਿੰਕਾਂ ਵਿੱਚ ਬਦਲ ਦਿੰਦੀ ਹੈ ਜੋ ਕਿ ਕਿਤੇ ਵੀ ਕੰਮ ਕਰਦੇ ਹਨ।

ਕੁਝ ਪੋਸਟਾਂ ਵਿੱਚ ਅਜਿਹੇ asides ਹੁੰਦੇ ਹਨ ਜੋ ਸਿਰਫ਼ ਅਸਲ ਪਲੇਟਫਾਰਮ ਲਈ ਹੁੰਦੇ ਹਨ, ਜਿਵੇਂ ਕਿ Medium paywalls ਬਾਰੇ ਇੱਕ ਡਿਸਕਲੇਮਰ ਜਾਂ Zenn-ਵਿਸ਼ੇਸ਼ ਇਮੇਜ ਪਾਥ। ਮੈਂ ਉਹਨਾਂ ਨੂੰ HTML ਕਮੈਂਟਸ ਵਿੱਚ ਲਪੇਟ ਦਿੰਦਾ ਹਾਂ ਤਾਂ ਜੋ ਕਨਵਰਟਰ ਮਾਈਗ੍ਰੇਸ਼ਨ ਦੌਰਾਨ ਉਹਨਾਂ ਨੂੰ ਹਟਾ ਸਕੇ। ਸਕ੍ਰਿਪਟ ਫਾਈਲਾਂ ਨੂੰ ਲਾਈਨ-ਦਰ-ਲਾਈਨ ਪ੍ਰੋਸੈਸ ਕਰਦੀ ਹੈ, ਪਰ ਇਹ ਕੋਡ ਦੀਆਂ ਸੀਮਾਵਾਂ ਦਾ ਸਤਿਕਾਰ ਕਰਦੀ ਹੈ। ਜਦੋਂ ਇਹ ਇੱਕ fenced code block ਦਾ ਪਤਾ ਲਗਾਉਂਦੀ ਹੈ, ਤਾਂ ਇਹ ਪਰਿਵਰਤਨ ਨਿਯਮਾਂ ਨੂੰ ਪੂਰੀ ਤਰ੍ਹਾਂ ਛੱਡ ਦਿੰਦੀ ਹੈ। ਇੱਕ ਟੈਕ ਬਲੌਗ ਦੇ ਪੂਰੇ ਉਦੇਸ਼ ਨੂੰ ਖਰਾਬ ਕਰਨ ਲਈ ਸਿੰਟੈਕਸ ਸੈਂਪਲ ਨੂੰ ਵਿਗਾੜਨਾ ਸਹੀ ਨਹੀਂ ਹੋਵੇਗਾ, ਇਸ ਲਈ ਲਾਈਨ-ਦਰ-ਲਾਈਨ ਪਾਰਸਰ ਕੋਡ ਬਲਾਕਾਂ ਨੂੰ ਅਣਛੇੜੇ ਜਾਣ ਵਾਲੇ ਜ਼ੋਨ ਵਜੋਂ ਮੰਨਦਾ ਹੈ।

ਹੁਣ ਇੱਕ ਕਮਾਂਡ ਚਲਾਉਣ ਨਾਲ ਸਾਲਾਂ ਦੀ ਲਿਖਤ ਇੱਕ ਵੀ ਲਿੰਕ ਜਾਂ ਕਾਲਆਊਟ ਨੂੰ ਤੋੜੇ ਬਿਨਾਂ ਮੁੜ ਪ੍ਰਕਾਸ਼ਿਤ ਹੋ ਜਾਂਦੀ ਹੈ।

ਬਿਲਡ-ਟਾਈਮ OGP ਇਮੇਜ ਜਨਰੇਸ਼ਨ

ਸੋਸ਼ਲ ਸ਼ੇਅਰਿੰਗ ਇਮੇਜਾਂ ਨੂੰ ਆਮ ਤੌਰ 'ਤੇ ਬਾਅਦ ਵਿੱਚ ਸੋਚਿਆ ਜਾਣ ਵਾਲਾ ਮਾਮਲਾ ਮੰਨਿਆ ਜਾਂਦਾ ਹੈ। ਜਾਂ ਤਾਂ ਤੁਸੀਂ ਉਹਨਾਂ ਨੂੰ ਮੈਨੁਅਲੀ ਡਿਜ਼ਾਈਨ ਕਰਦੇ ਹੋ ਜਾਂ ਇੱਕ ਭਾਰੀ ਰਨਟਾਈਮ ਸਰਵਿਸ ਇੰਸਟਾਲ ਕਰਦੇ ਹੋ ਜੋ ਮੰਗ 'ਤੇ ਕਾਰਡ ਬਣਾਉਂਦੀ ਹੈ। ਮੈਂ ਦੋਵਾਂ ਵਿੱਚੋਂ ਕੁਝ ਵੀ ਨਹੀਂ ਚਾਹੁੰਦਾ ਸੀ। ਇਸ ਸਾਈਟ 'ਤੇ ਹਰ Open Graph ਇਮੇਜ ਬਿਲਡ ਦੌਰਾਨ ਤਿਆਰ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਤਾਂ ਜੋ ਵਿਜ਼ਿਟਰਾਂ ਨੂੰ ਇੱਕ ਸਟੈਟਿਕ PNG ਵੱਲ ਇਸ਼ਾਰਾ ਕਰਨ ਵਾਲੇ ਹਲਕੇ img ਟੈਗ ਤੋਂ ਵੱਧ ਕੁਝ ਨਾ ਮਿਲੇ।

ਮੈਂ Satori ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹਾਂ, ਜੋ JSX ਮਾਰਕਅੱਪ ਲੈਂਦਾ ਹੈ ਅਤੇ ਇਸਨੂੰ SVG ਵਿੱਚ ਰੈਂਡਰ ਕਰਦਾ ਹੈ। ਆਉਟਪੁੱਟ ਸਾਫ਼, ਭਰੋਸੇਮੰਦ ਅਤੇ ਟੈਂਪਲੇਟ ਬਣਾਉਣ ਵਿੱਚ ਆਸਾਨ ਹੈ। ਅਸਲ ਆਪਟੀਮਾਈਜ਼ੇਸ਼ਨ ਫੌਂਟ ਹੈਂਡਲਿੰਗ ਤੋਂ ਆਈ। ਇੱਕ ਪੂਰਾ ਜਾਪਾਨੀ ਵੈੱਬ ਫੌਂਟ ਆਸਾਨੀ ਨਾਲ ਪੰਜ ਮੈਗਾਬਾਈਟ ਤੋਂ ਵੱਧ ਹੋ ਸਕਦਾ ਹੈ। ਬਿਲਡ ਦੌਰਾਨ ਇਸਨੂੰ ਲੋਡ ਕਰਨਾ, ਜਾਂ ਬ੍ਰਾਊਜ਼ਰ ਨੂੰ ਇਸਨੂੰ ਫੈਚ ਕਰਨ ਲਈ ਕਹਿਣਾ, ਬੇਤੁਕਾ ਹੋਵੇਗਾ।

ਇਸ ਦੀ ਬਜਾਏ, ਮੈਂ Google Fonts subsetting ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹਾਂ। ਸਕ੍ਰਿਪਟ ਕਿਸੇ ਦਿੱਤੀ ਗਈ ਪੋਸਟ ਲਈ ਟਾਈਟਲ ਟੈਕਸਟ ਦੀ ਜਾਂਚ ਕਰਦੀ ਹੈ ਅਤੇ ਸਿਰਫ਼ ਉਸੇ ਸਹੀ ਗਲਾਈਫ ਸੈੱਟ (glyph set) ਦੀ ਬੇਨਤੀ ਕਰਦੀ ਹੈ ਜਿਸਦੀ ਉਸ ਸਟ੍ਰਿੰਗ ਨੂੰ ਰੈਂਡਰ ਕਰਨ ਲਈ ਲੋੜ ਹੈ। ਜੇਕਰ ਕੋਈ ਹੈਡਲਾਈਨ ਚਾਲੀ ਵਿਲੱਖਣ ਜਾਪਾਨੀ ਅੱਖਰਾਂ ਦੀ ਵਰਤੋਂ ਕਰਦੀ ਹੈ, ਤਾਂ ਸਿਰਫ਼ ਉਹ ਚਾਲੀ ਅੱਖਰ ਹੀ ਡਾਟਾ ਰਾਹੀਂ ਆਉਣਗੇ। ਬਿਲਡ ਤੇਜ਼ ਰਹਿੰਦਾ ਹੈ, ਅਤੇ ਰੈਂਡਰ ਕੀਤੀ ਗਈ ਇਮੇਜ ਵਿੱਚ ਕਦੇ ਵੀ ਟੁੱਟੇ ਹੋਏ ਟੋਫੂ ਬਲਾਕਸ (broken tofu blocks) ਨਹੀਂ ਦਿਖਾਈ ਦਿੰਦੇ ਕਿਉਂਕਿ subset ਸਹੀ ਹੁੰਦਾ ਹੈ। ਕੁਝ ਵੀ ਰਨਟਾਈਮ ਸੰਭਾਵਨਾ 'ਤੇ ਨਹੀਂ ਛੱਡਿਆ ਗਿਆ ਹੈ।

Tailwind Tokens ਰਾਹੀਂ ਡਾਰਕ ਮੋਡ

ਮੈਂ ਹਰ ਐਲੀਮੈਂਟ ਨੂੰ dark: ਯੂਟੀਲਿਟੀ ਕਲਾਸਾਂ ਨਾਲ ਸਜਾਉਣ ਤੋਂ ਇਨਕਾਰ ਕਰ ਦਿੱਤਾ। ਉਹ ਤਰੀਕਾ ਮਾੜੇ ਤਰੀਕੇ ਨਾਲ ਸਕੇਲ ਹੁੰਦਾ ਹੈ ਅਤੇ ਤੁਹਾਡੇ ਮਾਰਕਅੱਪ ਨੂੰ ਫਾਲਤੂ ਚੀਜ਼ਾਂ ਨਾਲ ਭਰ ਦਿੰਦਾ ਹੈ। ਮੈਂ ਖੁਦ ਕਲਰ ਟੋਕਨਸ ਨੂੰ ਮੁੜ ਪਰਿਭਾਸ਼ਿਤ ਕੀਤਾ ਤਾਂ ਜੋ ਸਰਗਰਮ ਥੀਮ ਦੇ ਅਧਾਰ 'ਤੇ ਇੱਕੋ ਜਿਹੀ ਕਲਾਸ ਦਾ ਨਾਮ ਵੱਖ-ਵੱਖ ਮੁੱਲਾਂ ਨੂੰ ਦਰਸਾ ਸਕੇ।

I use CSS custom properties for every surface and text color. In light mode, --color-white maps to #ffffff. In dark mode, the identical variable name points to a near-black value. My HTML stays completely agnostic. A card can use bg-ui-surface and text-ui-primary without caring about the time of day. The theme switch changes the variable definitions at the root, and the entire interface responds instantly.

The one risk with this approach is the flash of light content before stylesheets load. I solved it with a tiny inline script in the document head. It runs before the first paint, checks localStorage and the system preference, and sets the correct data attribute immediately. Because the script blocks the render for only a few milliseconds, the visitor never sees a jarring white burst before dark mode kicks in.

Island Architecture and Zero-JS

Astro’s core premise is that a page should start as static HTML. JavaScript enters only when an interaction genuinely requires it. I took that seriously.

I avoided React for the global menu and the theme toggle. Both are handled with a small amount of vanilla JavaScript that lives in a single module. There is no hydration overhead, no virtual DOM diffing, and no framework runtime to download.

The only heavy library I use is Mermaid.js for rendering diagrams from text. Instead of importing it globally, I wrapped it inside an Intersection Observer. The observer watches for diagram containers. When a user scrolls within a few hundred pixels of one, the script dynamically injects the Mermaid module and renders the diagram. If a post contains no diagrams, that library never touches the network. The initial page load stays light, and the browser only pays for what the reader actually sees.

The Build-First Mindset

The thread running through every pattern is straightforward: if you can do the work during the build, do it there. Validate your data with Zod before the site deploys. Convert proprietary platform syntax ahead of time rather than at request time. Render social images into static files instead of spinning up a server. Resolve theme colors through tokens instead of shipping logic to every client. Defer heavy JavaScript until the user actually needs it.

Pushing complexity leftward into the build step keeps the runtime predictable, the payload small, and the maintenance burden manageable. The site remains fast not because of any single trick, but because there is simply less happening inside the visitor’s browser. That is the real payoff of choosing a static architecture in 2026.