ข้ามไปยังเนื้อหา

เครื่องมือตรวจสอบ

คอร์สนี้ไม่มี playground ในเบราว์เซอร์สำหรับ compiler จริงของ Astro 7 แบบที่ sandbox ที่รันได้จริงจะให้ได้ — วิธีเดียวที่จะพิสูจน์ข้ออ้างเกี่ยวกับโค้ด Astro ที่ generate มาคือโปรเจกต์จริง, การรัน astro check/astro build จริง, หรือ test จริง ผลลัพธ์ทุกอันด้านล่างเป็นของจริง เก็บมาจาก [email protected] ที่ติดตั้งใน probe ของคอร์สนี้เอง ไม่มีเครื่องมือไหนซ้อนทับกันสมบูรณ์ และไม่มีตัวไหนใกล้เคียงครบถ้วนด้วยตัวมันเอง — บรรทัด “จับได้ด้วย” ของแต่ละ 22 entry ใน AI Bug Catalog ระบุเป๊ะ ๆ ว่าเครื่องมือไหนด้านล่าง (ถ้ามี) ที่จะจับมันได้ และ 18 จาก 22 นั้นไม่มีตัวไหนเลย

astro check type-check ไฟล์ .astro/.ts/.tsx ด้วย diagnostic จริงที่สามระดับ — error, warning, hint — และพิมพ์บรรทัดสรุป พิสูจน์แล้วกับ 7.3.5 ที่ติดตั้ง โปรเจกต์ที่สะอาด exit 0; โปรเจกต์ที่มี error อย่างน้อยหนึ่งอัน exit 1:

Terminal window
npx astro check; echo "exit: $?"
Result (100+ files):
- 0 errors
- 0 warnings
- 11 hints
exit: 0

flag สองตัวที่แยกกันควบคุมคนละเรื่อง — ตรวจตรงจาก astro check --help:

--minimumFailingSeverity Minimum error severity needed to exit with an
error code. [choices: "error", "warning", "hint"] [default: "error"]
--minimumSeverity Minimum diagnostic severity to show. Choosing
`warning` will, for example, show both errors
and warnings, but not hints. [choices: "error", "warning", "hint"] [default: "hint"]

--minimumSeverity ควบคุมสิ่งที่ แสดง; --minimumFailingSeverity ควบคุมสิ่งที่ทำให้ exit code ไม่เป็นศูนย์ โดยปริยายมีแค่ diagnostic ระดับ error เท่านั้นที่ทำให้คำสั่งล้มเหลว — นี่คือเหตุผลเป๊ะ ๆ ที่ entry 21 ใน AI Bug Catalog (key markdown.remarkPlugins ระดับบนสุดที่เลิกใช้แล้ว) พิมพ์ warning ts(6385) จริงและยัง exit 0 พลาดง่ายใน CI เว้นแต่ --minimumFailingSeverity จะถูกตั้งให้เข้มขึ้นเป็น "warning"

การ type-check อย่างเดียวจับ catalog ของคอร์สนี้ได้น้อยอย่างน่าประหลาดใจโดยการออกแบบ — 18 จาก 22 entry ผ่าน astro check สะอาด เพราะความล้มเหลวส่วนใหญ่ของ Astro เอง (adapter ที่ขาด, transition:persist ที่ไม่ตรงกันแบบเงียบ, secret ที่หลุดใน prop ของ island) เป็นเรื่อง runtime/พฤติกรรมที่ type checker ไม่มีทางมองเห็น สิ่งที่มัน จับได้ จริงคือ: การเรียก Astro.glob() ที่ถูกเอาออก, function prop เข้า island ที่ type เข้มงวด, method entry.render() เก่า, และ import <ViewTransitions /> ที่เปลี่ยนชื่อแล้ว — entry 9, 6, 12, และ 19 ตามลำดับ

log ของ astro build เองบอกมากกว่าผ่าน/ไม่ผ่าน — มันระบุเป๊ะ ๆ ว่า route ไหนถูก prerender เป็นไฟล์ static:

Terminal window
npx astro build --outDir dist
prerendering static routes
├─ /mixed/static-about/index.html (+13ms)
├─ /index.html (+1ms)
✓ Completed in 27ms.
[build] Rearranging server assets...
[build] Server built in 467ms
[build] Complete!

อะไรก็ตามที่ ไม่ อยู่ใน list “prerendering static routes” ในโปรเจกต์ที่เปิดใช้ server ถูก compile เข้า server entry แทน — build log เองคือหลักฐานว่า route หนึ่งได้ rendering mode ไหนจริง ๆ ไม่ใช่แค่สิ่งที่ source file ประกาศไว้ (นี่คือวิธีเป๊ะ ๆ ที่บทเรียน Rendering & Output Modes พิสูจน์ prerender ต่อ route) build จริงยังเป็นวิธีเดียวที่คอร์สนี้ reproduce error ที่มีชื่อส่วนใหญ่ของ AI Bug Catalog ได้ — NoAdapterInstalled, GetStaticPathsRequired, MISSING_EXPORT, InvalidContentEntryDataError — ซึ่งไม่มีตัวไหนที่ astro check เจอเลย

astro sync (ที่ astro dev/build/check ทั้งหมดรันให้อัตโนมัติก่อน) เรียก load() ของทุก collection จริง ๆ และเขียน .astro/content.d.ts:

Terminal window
npx astro sync
[content] Syncing content
[content] Synced content
[types] Generated 1.16s

เพราะมันรัน loader จริง astro sync จึงเป็นจุดที่ frontmatter ไม่ตรงกับ schema ปรากฏก่อนใคร — InvalidContentEntryDataError (entry 11 ของ AI Bug Catalog) เป็น error ตอน sync ไม่ใช่ตอน check เพราะ fence content.config.ts ของบทเรียนเอง type-check เป็น module ธรรมดาภายใต้โหมด check เริ่มต้นของคอร์สนี้ และไม่เคยรันกับ content จริงเลย

โครงร่างการทดสอบด้วย Container API — test ที่รันจริงและผ่านจริง

หัวข้อที่มีชื่อว่า “โครงร่างการทดสอบด้วย Container API — test ที่รันจริงและผ่านจริง”

Astro Container API (experimental_AstroContainer) render component เป็น HTML string โดยไม่ต้องใช้ browser — เครื่องมือเดียวกับที่บทเรียน Testing & Tooling ครอบคลุมแบบเต็ม โครงร่างขั้นต่ำ จริง สำหรับบทเรียนนี้เป๊ะ ๆ:

src/components/Greeting.astro
---
interface Props {
name: string;
}
const { name } = Astro.props as Props;
---
<p class="greeting">Hello, {name}!</p>
src/__tests__/greeting-render.test.ts
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import { expect, test } from 'vitest';
import Greeting from '../components/Greeting.astro';
test('Greeting renders the given name into real HTML', async () => {
const container = await AstroContainer.create();
const result = await container.renderToString(Greeting, {
props: { name: 'Ava' },
});
expect(result).toContain('Hello, Ava!');
});

รันด้วย harness ของคอร์สนี้เอง เจาะจงเฉพาะบทเรียนนี้:

Terminal window
node tools/verify-snippets.mjs --test reading-astro/verification-tools
reading-astro/verification-tools: 1/1 passed
1/1 test(s) passed across 1 file(s).

test ด้วย Container API เหมาะกับคำถามเดียวเท่านั้น — “component นี้ render HTML ที่คาดไว้สำหรับ prop/slot เหล่านี้หรือไม่” — ไม่เคยเหมาะกับอะไรที่ต้องใช้ browser (พฤติกรรม hydrate ของ island, การนำทางฝั่ง client) หรือ request จริง (การตรวจ auth ของ Action, error ที่เกิดแค่ตอน build)

eslint-plugin-astro lint ไฟล์ .astro — frontmatter, template, directive, และ (พร้อม eslint-plugin-jsx-a11y ที่ติดตั้งคู่กัน) กฎ accessibility ตรวจตรงจาก registry ไม่ใช่จากความจำ:

Terminal window
npm view eslint-plugin-astro version
3.2.1

มันเป็น flat-config เท่านั้น รูปร่างจริง ตรงจากเอกสารของมันเอง:

eslint.config.js
import eslintPluginAstro from 'eslint-plugin-astro';
export default [
...eslintPluginAstro.configs.recommended,
];

configs.recommended เป็น array ที่ spread เข้าไป (flat-config object หลายตัว) ไม่ใช่ object เดียว — snippet ที่ generate มาที่เขียน rules: eslintPluginAstro.configs.recommended โดยไม่มี ... spread จะได้ config array ที่พังไม่ใช่ ruleset ที่ทำงานได้

dev server ของ Astro 7 มี flag สองตัวที่ harness ของคอร์สนี้พึ่งพาสำหรับ automation ตรวจตรงจาก CLI ที่ติดตั้ง:

Terminal window
npx astro dev --help
Commands
stop Stop a running background dev server.
status Check if a dev server is running.
logs [--follow] View logs from a background dev server.
Flags
--background Start the dev server as a background process.
Terminal window
npx astro --help
Global Flags
--json Enables JSON logging.

--background ให้ script (หรือ AI coding agent) เริ่ม dev server ทำงานต่อ แล้วมาตรวจดูทีหลังด้วย astro dev status/astro dev logs แทนที่จะบล็อกอยู่กับ process ที่ทำงานอยู่หน้าจอ --json เปลี่ยนทุกบรรทัด log เป็น JSON ที่มีโครงสร้างแทนที่จะเป็นข้อความสีบน terminal — การรวมกันนี้คือสิ่งที่เครื่องมืออัตโนมัติ (หรือ agent ที่ขับ harness ของคอร์สนี้เอง) ต้องการเพื่ออ่าน error ของ dev server โดยไม่ต้องขูด output ที่มีสี ANSI

code fence ทุกอันในคอร์สนี้ที่มีบรรทัดแรกเป็น path จริง คือไฟล์จริง ถูกเก็บโดย tools/verify-snippets.mjs และ type-check ด้วย astro check ในรอบเดียวทั่วทั้งคอร์ส:

Terminal window
npm run verify
Per-module fence summary (collected / skipped-no-path / expect-error / tests):
...
reading-astro: 42 / 4 / 4 / 1
...
TOTAL: 180 / 107 / 12 / 15

การรันที่ไม่มี error จริงเลยที่ไหนพิมพ์ no errors, no warnings. เหนือบรรทัดสรุปต่อโมดูลเดียวกันนี้; error ที่พบที่ไหนก็ตามในคอร์สพิมพ์บรรทัด error <file>:fence #N ... หนึ่งบรรทัดต่อความล้มเหลวก่อน แล้วจึงสรุปแบบเดียวกัน — จำนวน error ที่เป็นศูนย์ของโมดูลนี้เองคือสิ่งที่สำคัญสำหรับบทเรียนนี้ ไม่ว่าโมดูลอื่นจะมีจำนวนเท่าไหร่ในการรันครั้งใดครั้งหนึ่งก็ตาม fence ที่ตั้งใจแสดงโค้ดที่พังหรือมีพฤติกรรมผิด (ตัวอย่าง “โค้ดที่ AI มักเขียน” ส่วนใหญ่ใน AI Bug Catalog) เริ่มด้วย // @expect-error <reason> เพื่อให้ harness ข้ามการเก็บมัน — เนื้อหาบทเรียนพก astro check/build/curl output จริงที่เก็บแยกไว้แทนที่จะให้ทุกการรันพยายาม reproduce ความล้มเหลวที่ตั้งใจไว้ node tools/verify-snippets.mjs --build <module>/<lesson> ไปไกลกว่านั้นสำหรับบทเรียนเดียวต่อครั้ง: มันเขียน fence ของบทเรียนนั้นลง path จริง แล้วรัน astro build จริง พิมพ์ส่วนท้ายออกมา — วิธีเดียวที่ harness ของคอร์สนี้ reproduce error ที่เกิดแค่ตอน build อย่าง NoAdapterInstalled หรือ GetStaticPathsRequired ได้จริง ตามต้องการ

การตรวจสอบด้วย AstroPlayground — และขีดจำกัดจริงที่ต้องพูดตรง ๆ

หัวข้อที่มีชื่อว่า “การตรวจสอบด้วย AstroPlayground — และขีดจำกัดจริงที่ต้องพูดตรง ๆ”

บทเรียนสองบทก่อนหน้าในคอร์สนี้ (components/astro-syntax-deep.mdx, components/styles-and-scripts.mdx) ฝัง <AstroPlayground> การตรวจสอบแบบ compile-only ในเบราว์เซอร์ ควรพูดให้ชัดว่ามันรันอะไรจริง ๆ: ตาม module doc comment ของ astro-playground-runtime.ts เอง มันโหลด compiler Rust จริงของคอร์สนี้ในเบราว์เซอร์ไม่ได้เลย (WASM build เดียวของ @astrojs/compiler-rs link ไม่ได้ด้วยซ้ำเมื่อโหลดจาก CDN — LinkError จริงที่ระบุ import napi_create_async_work ที่หายไป) — มันเลยโหลด compiler Go รุ่นเก่าก่อน 7.0 แทน (@astrojs/[email protected] จาก esm.sh) ตัวเดียวกับที่ Astro REPL ทางการใช้มาตลอดสำหรับการ compile ในเบราว์เซอร์

การสลับตัวนั้นมีผลจริงที่พิสูจน์แล้วต่อสิ่งที่มันจับได้และจับไม่ได้: compiler รุ่นเก่านี้หย่อนกว่า Rust compiler จริงของ Astro 7 อย่างเห็นได้ชัด — tag ที่ไม่ปิดหรือ HTML ที่ซ้อนผิดที่ astro check ปฏิเสธตรง ๆ compile ผ่าน playground นี้ได้โดย ไม่มี diagnostic เลย สิ่งที่มัน จับได้ จริงคือ set:html บน element ที่ยังมี child เป็น text-node:

set:html ที่มี child เป็น text-node

---
---
<div set:html={"<mark>Highlighted</mark>"}>
New here? Read the guide first.
</div>

กด Compile: แผง diagnostic จะแสดง WARNING_SET_WITH_CHILDREN จริง — ความผิดพลาดของ Astro ที่แท้จริงและไม่ขึ้นกับเวอร์ชันเดียวกับที่พิสูจน์แล้วในบทเรียน syntax-deep-dive แต่ความหย่อนของ playground นี้เองก็กลับด้านได้เช่นกัน และควรรู้ไว้ก่อนจะเชื่อผลลัพธ์ “ไม่มี diagnostic”: เปลี่ยน child ที่เป็น text-node ข้างบนให้เป็น child ที่เป็น element ซ้อนอยู่ (<p>...</p> แทนข้อความธรรมดา) แล้วใน compiler build เป๊ะ ๆ นี้ warning จะหายไปแบบเงียบ ๆ — ช่องว่างจริงที่ reproduce ได้ ไม่ใช่ทุกกรณี “ยังมี children อยู่” จะถูกจับได้ที่นี่ ใช้ playground นี้เพื่อตรวจสอบ รูปร่าง ของการใช้ set:html ที่น่าสงสัยคร่าว ๆ ไม่ใช่เพื่อพิสูจน์ว่า snippet สะอาด — astro check กับ Rust compiler จริงที่ติดตั้งไว้ (หรือ build จริง) คือการตรวจสอบเดียวที่คอร์สนี้ถือว่าเชื่อถือได้

flowchart TD
  subgraph Static["Static (source only)"]
    Check["astro check<br/>type error จริง: Astro.glob, entry.render(), ViewTransitions, island prop เข้มงวด"]
    Eslint["[email protected]<br/>flat config เท่านั้น lint ไฟล์ .astro"]
    Verify["tools/verify-snippets.mjs<br/>astro check ทั่วทั้งคอร์ส"]
  end
  subgraph Runtime["Runtime (ต้อง render จริง, request จริง, หรือ build จริง)"]
    Container["Container API<br/>HTML จริงของ component ไม่ต้องใช้ browser"]
    Build["astro build / astro sync<br/>NoAdapterInstalled, GetStaticPathsRequired, InvalidContentEntryDataError"]
    Curl["curl กับ server จริง<br/>auth ของ Action, Cache-Control, secret ใน HTML ที่ build แล้ว"]
  end
  subgraph Browser["ต้องใช้ browser จริง"]
    Playground["AstroPlayground<br/>compiler Go รุ่นเก่า — หย่อนกว่า ไม่ใช่ Rust compiler ของคอร์สนี้"]
    Real["session browser จริง<br/>hydration, การจับคู่ transition:persist, client directive"]
  end
เครื่องมือ static พิสูจน์สิ่งต่าง ๆ จาก source ได้เลย; เครื่องมือ dynamic ต้องมีการ render จริง, request จริง, หรือ build จริง
โปรเจกต์มี 1 warning และ 0 error ด้วย flag ค่าเริ่มต้น astro check จะ exit code อะไร และทำไม?
--minimumFailingSeverity  ... [default: "error"]
--minimumSeverity         ... [default: "hint"]
ทำไม astro build จริงถึง reproduce error อย่าง NoAdapterInstalled และ GetStaticPathsRequired ที่ astro check ไม่เคยรายงาน?
การลงทะเบียน component ด้วย Container API พิสูจน์อะไรจริง ๆ และไม่พิสูจน์อะไร?
ทำไมถึงเชื่อ <AstroPlayground> ไม่ได้ว่าเป็นหลักฐานว่า snippet .astro ที่น่าสงสัยถูกต้องจริง ๆ?
ทำไม harness ของคอร์สนี้ถึงแปะ // @expect-error <reason> บน fence 'โค้ดที่ AI มักเขียน' ส่วนใหญ่ใน AI Bug Catalog แทนที่จะเป็น path comment ธรรมดา?