วิธีการทำงานของ Markdown
การทำความเข้าใจวิธีการทำงานของ Markdown จะช่วยให้คุณใช้เครื่องมือที่มีประสิทธิภาพนี้ได้ดียิ่งขึ้น บทนี้จะอธิบายอย่างละเอียดว่า Markdown แปลงจากข้อความธรรมดาเป็นเอกสารที่มีการจัดรูปแบบที่สวยงามได้อย่างไร
เวิร์กโฟลว์พื้นฐาน
เวิร์กโฟลว์ของ Markdown สามารถสรุปเป็นขั้นตอนต่อไปนี้:
ไฟล์ต้นฉบับ Markdown (.md) → ตัวแยกวิเคราะห์ Markdown → เอกสาร HTML → การแสดงผลในเบราว์เซอร์1. เขียนไฟล์ต้นฉบับ Markdown
คุณใช้โปรแกรมแก้ไขข้อความใดๆ ในการสร้างไฟล์ .md และใช้ไวยากรณ์ Markdown ในการเขียนเนื้อหา:
# เอกสารของฉัน
นี่คือย่อหน้าที่**สำคัญ**
## ตัวอย่างรายการ
- รายการ 1
- รายการ 2
- รายการ 32. การประมวลผลตัวแยกวิเคราะห์ Markdown
ตัวแยกวิเคราะห์อ่านไฟล์ Markdown ระบุองค์ประกอบไวยากรณ์และแปลงเป็น HTML ที่เกี่ยวข้อง:
<h1>เอกสารของฉัน</h1>
<p>นี่คือย่อหน้าที่<strong>สำคัญ</strong></p>
<h2>ตัวอย่างรายการ</h2>
<ul>
<li>รายการ 1</li>
<li>รายการ 2</li>
<li>รายการ 3</li>
</ul>3. การแสดงผลในเบราว์เซอร์
HTML ที่สร้างขึ้นจะแสดงเป็นเอกสารที่มีการจัดรูปแบบในเบราว์เซอร์
กลไกการทำงานของตัวแยกวิเคราะห์
การวิเคราะห์คำศัพท์
ตัวแยกวิเคราะห์ดำเนินการวิเคราะห์คำศัพท์ก่อน โดยแยกข้อความ Markdown ออกเป็นโทเค็น (tokens):
#ระบุเป็นโทเค็นหัวข้อ**text**ระบุเป็นโทเค็นข้อความหนา- itemระบุเป็นโทเค็นรายการ
การแยกวิเคราะห์ไวยากรณ์
จากนั้นดำเนินการแยกวิเคราะห์ไวยากรณ์ สร้างแผนผังโครงสร้างไวยากรณ์แบบนามธรรม (AST):
เอกสาร
├── หัวข้อ(ระดับ1): "เอกสารของฉัน"
├── ย่อหน้า
│ ├── ข้อความ: "นี่คือย่อหน้าที่"
│ ├── ข้อความหนา: "สำคัญ"
│ └── ข้อความ: ""
├── หัวข้อ(ระดับ2): "ตัวอย่างรายการ"
└── รายการแบบไม่มีลำดับ
├── รายการ: "รายการ 1"
├── รายการ: "รายการ 2"
└── รายการ: "รายการ 3"การสร้าง HTML
สุดท้ายข้ามแผนผังไวยากรณ์ สร้าง HTML เอาต์พุตที่เกี่ยวข้อง
ตัวแยกวิเคราะห์หลัก
CommonMark
- มาตรฐาน - ให้มาตรฐานการแยกวิเคราะห์ Markdown ที่เป็นมาตรฐาน
- คำจำกัดความที่เข้มงวด - กำจัดความคลุมเครือระหว่างการใช้งานต่างๆ
- การรองรับอย่างกว้างขวาง - ถูกนำมาใช้โดยตัวแยกวิเคราะห์หลายตัว
GitHub Flavored Markdown (GFM)
อิงตาม CommonMark เพิ่ม:
- การรองรับตาราง
- ขีดฆ่า
- รายการงาน
- การระบุลิงก์อัตโนมัติ
- บล็อกโค้ดที่มีการเน้นไวยากรณ์
ตัวแยกวิเคราะห์อื่นๆ
| ตัวแยกวิเคราะห์ | ภาษา | คุณสมบัติ |
|---|---|---|
| marked | JavaScript | เร็ว น้ำหนักเบา |
| markdown-it | JavaScript | สามารถเสียบได้ รองรับส่วนขยาย |
| Python-Markdown | Python | ฟีเจอร์ครบถ้วน ระบบปลั๊กอิน |
| kramdown | Ruby | รองรับรูปแบบเอาต์พุตหลายแบบ |
| Pandoc | Haskell | ตัวแปลงเอกสารสากล |
เอ็นจินการแสดงผล
การแสดงผลฝั่งไคลเอนต์
แยกวิเคราะห์ Markdown ในเบราว์เซอร์แบบเรียลไทม์:
// ใช้ marked.js
const html = marked.parse('# Hello World');
document.body.innerHTML = html;ข้อดี:
- ไม่จำเป็นต้องประมวลผลฝั่งเซิร์ฟเวอร์
- ผลการแสดงตัวอย่างแบบเรียลไทม์
- ลดภาระของเซิร์ฟเวอร์
ข้อเสีย:
- ขึ้นกับ JavaScript
- ไม่เป็นมิตรกับ SEO
- โหลดครั้งแรกช้า
การแสดงผลฝั่งเซิร์ฟเวอร์
สร้าง HTML ไว้ล่วงหน้าบนเซิร์ฟเวอร์:
// ตัวอย่าง Node.js
const fs = require('fs');
const marked = require('marked');
const markdown = fs.readFileSync('document.md', 'utf8');
const html = marked.parse(markdown);ข้อดี:
- เป็นมิตรกับ SEO
- โหลดเร็ว
- ไม่ขึ้นกับ JavaScript ฝั่งไคลเอนต์
ข้อเสีย:
- ภาระการประมวลผลของเซิร์ฟเวอร์
- การจัดการแคชซับซ้อน
การสร้างไซต์แบบคงที่
สร้างหน้าทั้งหมดล่วงหน้าในตอน build:
# ใช้ VitePress
npm run buildข้อดี:
- โหลดเร็วที่สุด
- SEO ดีที่สุด
- ความปลอดภัยสูง
- ติดตั้งง่าย
ข้อเสีย:
- การรองรับเนื้อหาแบบไดนามิกมีจำกัด
- เวลาสร้างนาน
กลไกการขยาย
ระบบปลั๊กอิน
ตัวแยกวิเคราะห์หลายตัวรองรับการขยายด้วยปลั๊กอิน:
// ตัวอย่างปลั๊กอิน markdown-it
const md = require('markdown-it')()
.use(require('markdown-it-footnote'))
.use(require('markdown-it-deflist'))
.use(require('markdown-it-abbr'));ตัวแสดงผลแบบกำหนดเอง
// การแสดงผลลิงก์แบบกำหนดเอง
const renderer = new marked.Renderer();
renderer.link = function(href, title, text) {
return `<a href="${href}" target="_blank">${text}</a>`;
};การปรับปรุงประสิทธิภาพ
กลยุทธ์แคช
const cache = new Map();
function parseMarkdown(content) {
const hash = generateHash(content);
if (cache.has(hash)) {
return cache.get(hash);
}
const result = marked.parse(content);
cache.set(hash, result);
return result;
}โหลดขี้เกียจ
// แยกวิเคราะห์เฉพาะเนื้อหาในพื้นที่ที่มองเห็นได้
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
parseAndRender(entry.target);
}
});
});การประมวลผลแบบสตรีม
// แยกวิเคราะห์ไฟล์ขนาดใหญ่แบบสตรีม
const fs = require('fs');
const { Transform } = require('stream');
const markdownTransform = new Transform({
transform(chunk, encoding, callback) {
const html = marked.parse(chunk.toString());
callback(null, html);
}
});
fs.createReadStream('large-document.md')
.pipe(markdownTransform)
.pipe(fs.createWriteStream('output.html'));ปัญหาที่พบบ่อย
1. ปัญหาการขึ้นบรรทัดใหม่
ตัวแยกวิเคราะห์ต่างๆ อาจจัดการกับการขึ้นบรรทัดใหม่ต่างกัน:
บรรทัด 1
บรรทัด 2 ← ที่นี่อาจถูกแยกเป็นย่อหน้าเดียวกัน
บรรทัด 1
บรรทัด 2 ← เว้นวรรคสองช่องที่ท้ายบรรทัดบังคับขึ้นบรรทัดใหม่
บรรทัด 1
บรรทัด 2 ← บรรทัดว่างแยกย่อหน้า2. การใช้ HTML ผสม
นี่คือ **Markdown** และ <em>HTML</em> ที่ผสมกันควรระวังการปิดและซ้อนแท็ก HTML ที่ถูกต้อง
3. การหนีอักขระพิเศษ
ที่นี่ต้องหนี \* และ \_ อักขระสถานการณ์การใช้งานจริง
1. ระบบบล็อก
บทความ Markdown → ตัวสร้างไซต์แบบคงที่ → เว็บไซต์ HTML2. เว็บไซต์เอกสาร
เอกสาร .md → VitePress/Docusaurus → เอกสารออนไลน์3. ไฟล์ README
README.md → GitHub/GitLab → หน้าแรกโปรเจ็กต์4. แอปพลิเคชันบันทึก
บันทึก Markdown → การแสดงผลแบบเรียลไทม์ → การแสดงข้อความที่อุดมไปด้วยขั้นตอนต่อไป
ตอนนี้คุณเข้าใจวิธีการทำงานของ Markdown แล้ว คุณสามารถ: