การใช้ Tailwind CSS กับ Server-Side Rendering (SSR)
Server-Side Rendering (SSR) เป็นเทคนิคที่ช่วยให้เว็บไซต์สามารถแสดงผลเนื้อหาบนเซิร์ฟเวอร์ก่อนที่จะส่งไปยังเบราว์เซอร์ของผู้ใช้ ทำให้เว็บไซต์โหลดเร็วขึ้น, ปรับปรุง SEO, และให้ประสบการณ์การใช้งานที่ดีขึ้น ในบทความนี้ เราจะมาดูวิธีการใช้งาน Tailwind CSS ร่วมกับ SSR อย่างมีประสิทธิภาพ โดยเน้นที่การ extract CSS, การ inject CSS, และการจัดการ critical CSS
เหตุผลที่ต้องพิจารณาการใช้งาน Tailwind CSS กับ SSR
เมื่อใช้ Tailwind CSS ในสภาพแวดล้อม SSR มีประเด็นสำคัญที่ต้องพิจารณา:
- การจัดการ CSS: Tailwind CSS สร้างไฟล์ CSS ขนาดใหญ่ การส่งไฟล์ CSS ทั้งหมดไปยังเบราว์เซอร์ในทุก request อาจทำให้เว็บไซต์โหลดช้า
- Flash of Unstyled Content (FOUC): หาก CSS ยังไม่พร้อมใช้งานเมื่อเบราว์เซอร์แสดงผล HTML ผู้ใช้อาจเห็นเนื้อหาที่ไม่มีสไตล์ (FOUC) ก่อนที่ CSS จะโหลดเสร็จ
- Performance: การ optimize CSS สำหรับ SSR เป็นสิ่งสำคัญเพื่อให้แน่ใจว่าเว็บไซต์โหลดเร็วและมีประสิทธิภาพ
การ Extract CSS
ขั้นตอนแรกในการใช้งาน Tailwind CSS กับ SSR คือการ extract CSS ออกจาก JavaScript Bundles เพื่อให้ CSS สามารถนำไปใช้ในการ render หน้าเว็บฝั่งเซิร์ฟเวอร์ได้ วิธีนี้จะช่วยลดปัญหา FOUC และปรับปรุง performance โดยรวมของเว็บไซต์
แนวทางที่ 1: ใช้ Plugins ที่รองรับการ Extract CSS
เครื่องมือสร้าง Bundles อย่าง Webpack และ Parcel มักมี Plugins ที่ช่วยในการ Extract CSS โดยอัตโนมัติ ตัวอย่างเช่น:
- Webpack: ใช้
mini-css-extract-plugin - Parcel: Parcel รองรับการ Extract CSS โดยไม่ต้องติดตั้ง Plugin เพิ่มเติม
ตัวอย่างการใช้งาน mini-css-extract-plugin ใน Webpack:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: 'styles.css',
}),
],
};
ในตัวอย่างนี้ mini-css-extract-plugin จะ Extract CSS ที่ถูก import ใน JavaScript files และสร้างไฟล์ styles.css แยกออกมา
แนวทางที่ 2: ใช้ Tailwind CLI
Tailwind CLI สามารถใช้เพื่อ compile CSS โดยตรง โดยไม่ต้องพึ่ง Bundler วิธีนี้เหมาะสำหรับโปรเจ็กต์ที่ต้องการควบคุมกระบวนการ compile CSS อย่างละเอียด
npx tailwindcss -i ./src/input.css -o ./public/styles.css
คำสั่งนี้จะอ่าน CSS จาก ./src/input.css, process ด้วย Tailwind CSS, และเขียนผลลัพธ์ไปยัง ./public/styles.css
การ Inject CSS
เมื่อ Extract CSS เรียบร้อยแล้ว ขั้นตอนต่อไปคือการ Inject CSS เข้าไปใน HTML ที่ถูก render ฝั่งเซิร์ฟเวอร์ มีหลายวิธีในการทำเช่นนี้:
แนวทางที่ 1: Inject CSS ใน <head> Tag
วิธีที่ง่ายที่สุดคือการอ่านไฟล์ CSS ที่ Extract ไว้ แล้ว inject CSS เข้าไปใน <head> tag ของ HTML ก่อนที่จะส่งไปยังเบราว์เซอร์
ตัวอย่าง (Node.js):
const fs = require('fs');
const path = require('path');
function renderPage() {
const cssPath = path.resolve(__dirname, 'public', 'styles.css');
const css = fs.readFileSync(cssPath, 'utf8');
const html = `
<!DOCTYPE html>
<html>
<head>
<style>${css}</style>
</head>
<body>
<div class="container">
<h1 class="text-3xl font-bold">Hello, Tailwind CSS!</h1>
</div>
</body>
</html>
`;
return html;
}
ในตัวอย่างนี้ เราอ่านไฟล์ styles.css และ inject เนื้อหาของมันเข้าไปใน <style> tag ใน <head> tag
แนวทางที่ 2: ใช้ Template Engines
Template Engines อย่าง EJS, Handlebars, หรือ Pug สามารถใช้เพื่อ inject CSS ได้อย่างง่ายดาย
ตัวอย่าง (EJS):
<!DOCTYPE html>
<html>
<head>
<style><%- css %></style>
</head>
<body>
<div class="container">
<h1 class="text-3xl font-bold">Hello, Tailwind CSS!</h1>
</div>
</body>
</html>
ใน Node.js:
const ejs = require('ejs');
const fs = require('fs');
const path = require('path');
function renderPage() {
const cssPath = path.resolve(__dirname, 'public', 'styles.css');
const css = fs.readFileSync(cssPath, 'utf8');
const templatePath = path.resolve(__dirname, 'views', 'index.ejs');
const template = fs.readFileSync(templatePath, 'utf8');
const html = ejs.render(template, { css: css });
return html;
}
การจัดการ Critical CSS
Critical CSS คือ CSS ที่จำเป็นสำหรับการแสดงผลส่วนบนของหน้าเว็บ (above-the-fold content) การ inject Critical CSS ก่อน จะช่วยให้ผู้ใช้เห็นเนื้อหาที่สำคัญได้เร็วขึ้น และลดปัญหา FOUC
แนวทางที่ 1: ใช้ Libraries สำหรับ Critical CSS
มี Libraries ที่ช่วยในการ Extract Critical CSS โดยอัตโนมัติ ตัวอย่างเช่น:
critical: Library ที่ Extract Critical CSS จาก HTMLpenthouse: Library ที่ Extract Critical CSS จาก URL
ตัวอย่างการใช้งาน critical:
const critical = require('critical');
const fs = require('fs');
const path = require('path');
async function renderPage() {
const htmlPath = path.resolve(__dirname, 'public', 'index.html'); // สมมติว่ามีไฟล์ HTML ที่ยังไม่ได้ใส่ CSS
const html = fs.readFileSync(htmlPath, 'utf8');
const criticalCSSResult = await critical.generate({
html: html,
inline: false, // ไม่ inline CSS, ต้องการแยกไฟล์
css: [path.resolve(__dirname, 'public', 'styles.css')],
target: {
css: path.resolve(__dirname, 'public', 'critical.css'), // ไฟล์ CSS ที่จะเก็บ critical css
html: path.resolve(__dirname, 'public', 'index_critical.html'), // ไฟล์ HTML ที่ใส่ critical css แล้ว
}
});
const criticalCSS = fs.readFileSync(path.resolve(__dirname, 'public', 'critical.css'), 'utf8'); // อ่านไฟล์ critical css
const modifiedHTML = html.replace('<head>', `<head><style>${criticalCSS}</style>`); // แทรก critical css เข้าไปใน HTML
return modifiedHTML;
}
แนวทางที่ 2: Manual Critical CSS Extraction
หากต้องการควบคุมกระบวนการ Extract Critical CSS อย่างละเอียด สามารถทำได้โดยการระบุ classes ที่ใช้ในส่วนบนของหน้าเว็บ และ generate CSS สำหรับ classes เหล่านั้นโดยเฉพาะ
ข้อควรระวังและแนวปฏิบัติที่ดี
- Purge Unused CSS: ใช้ PurgeCSS เพื่อลบ CSS ที่ไม่ได้ใช้งานออกจากไฟล์ CSS ก่อนที่จะ Inject เข้าไปใน HTML
- Cache CSS: Cache ไฟล์ CSS เพื่อลดเวลาในการโหลดใน request ถัดไป
- ใช้ Content Delivery Network (CDN): ใช้ CDN เพื่อกระจายไฟล์ CSS ไปยังเซิร์ฟเวอร์ที่อยู่ใกล้ผู้ใช้มากที่สุด
- Monitor Performance: ติดตาม performance ของเว็บไซต์อย่างสม่ำเสมอ และปรับปรุงการตั้งค่า SSR ตามความเหมาะสม
การใช้งาน Tailwind CSS กับ SSR อาจมีความซับซ้อน แต่ด้วยการ Extract CSS, การ Inject CSS, และการจัดการ Critical CSS อย่างเหมาะสม จะช่วยให้เว็บไซต์โหลดเร็วขึ้น, ปรับปรุง SEO, และให้ประสบการณ์การใช้งานที่ดีขึ้น