Astro 7 با تغییر به موتور markdown مبتنی بر Rust یعنی Sätteri، یک ارتقای روان را برای سایت‌هایی که به ریاضیات (math)، لنگرهای عنوان (heading anchors) و پیکربندی سفارشی (custom configuration) متکی هستند، به یک کابوس سه‌جانبه تبدیل کرد. معادلات درون‌خطی (Inline equations) همچنان کار می‌کنند، اما بلوک‌های ریاضی نمایشی (display-math blocks) به صورت قطعه‌کدهای متن ساده ظاهر می‌شوند، شناسه‌های عنوان (heading IDs) ناپدید می‌شوند و هر گزینه اضافی که در پیکربندی Astro اضافه کنید، بی‌صدا نادیده گرفته می‌شود. توسعه‌دهندگانی که از نسخه‌های قبلی Astro مهاجرت می‌کنند، اکنون مجبورند پلاگین‌ها را بازنویسی کنند یا با خطر خرابی صفحات مواجه شوند.

چرا این تغییر اهمیت دارد

موتور جدید، یک syntax highlighter داخلی را قبل از هر پلاگین ارائه‌شده توسط کاربر اجرا می‌کند و تنها سه فیلد پیکربندی سطح بالا (top-level) را می‌پذیرد. این انتخاب‌ها با روشی که اکثر پروژه‌های Astro ویژگی‌ها را اضافه می‌کنند، در تضاد است: یعنی از طریق پلاگین‌های remark (MDAST) و rehype (HAST) که انتظار دارند پس از هایلایت کردن اجرا شوند، و از طریق یک شیء پیکربندی منعطف که به پارسر markdown زیرین منتقل می‌شود.

پیامدهای این تغییر در هر صفحه‌ای که ریاضیات سبک LaTeX را با محتوای معمولی ترکیب می‌کند، خود را نشان می‌دهد. ریاضیات درون‌خطی ($a+b$) به درستی رندر می‌شود، اما یک بلوک نمایشی ($$a+b$$) در یک تگ <pre> قرار می‌گیرد و به جای یک معادله فرمت‌شده، مارک‌آپ خام را نشان می‌دهد. لنگرهای عنوان که لینک‌های فهرست مطالب (table-of-contents) یا لینک‌دهی عمیق (deep-linking) را فعال می‌کنند، ناپدید می‌شوند؛ زیرا پلاگین تولید ID قبل از هندلر داخلی ID اجرا می‌شود و چیزی برای پلاگین autolink باقی نمی‌گذارد تا به آن متصل شود. توسعه‌دهندگانی که سعی کردند syntax highlighter مربوط به Shiki را با یک شیء shikiConfig تنظیم دقیق کنند، متوجه می‌شوند که این تنظیمات بدون هیچ اثری ناپدید شده است.

راهکارهای فنی

۱. رندر کردن ریاضیات قبل از هایلایت کردن

علت اصلی، ترتیب عملیات است: هایلایتر Sätteri ابتدا متن را تصاحب کرده و بلوک ریاضی را به عنوان کد ساده طبقه‌بندی می‌کند. برای بازپس‌گیری ریاضیات، پردازش را به لایه MDAST (درخت نحو انتزاعی که نشان‌دهنده markdown قبل از تبدیل شدن به HTML است) منتقل کنید. هرگونه پلاگین ریاضی در سطح HAST را با معادل‌های MDAST آن‌ها جایگزین کرده و آن‌ها را قبل از مرحله هایلایتر اجرا کنید. در عمل، پلاگین‌های remark-math را با نسخه‌ای جایگزین کنید که به مرحله تجزیه (parsing) markdown متصل می‌شود، سپس اجازه دهید هایلایتر روی گره‌های ریاضی که قبلاً تبدیل شده‌اند، کار کند.

۲. تغییر ترتیب پلاگین‌های heading-ID

شناسه‌های عنوان (Heading IDs) توسط یک پلاگین داخلی تولید می‌شوند که اکنون پس از پلاگین‌های کاربر اجرا می‌شود. مولدهای سفارشی ID یا slug را به ابتدای لیست پلاگین‌ها منتقل کنید تا ابتدا اجرا شوند. یک توالی معمولی که لینک‌های لنگر را بازیابی می‌کند به این صورت است:

۱. پلاگین slug/ID ۲. پلاگین autolink ۳. هر پلاگین remark دیگر

با قرارگیری زودهنگام IDها، پلاگین autolink می‌تواند عناصر <a> مورد انتظار را متصل کند و فهرست مطالب به بخش‌های درست اشاره خواهد کرد.

۳. رعایت طرحواره (schema) سخت‌گیرانه پیکربندی Sätteri

Sätteri در پیکربندی markdown در Astro تنها سه فیلد را می‌پذیرد. هر چیز دیگری، مانند shikiConfig ، بی‌صدا حذف می‌شود. برای حفظ تم‌های سفارشی یا تغییرات هایلایتر، آن تنظیمات را به سطح مناسب در سلسله‌مراتب پیکربندی Astro منتقل کنید.

راهنمای سریع جایگزینی

اگر در حال انتقال یک پشته (stack) کلاسیک markdown در Astro هستید، پلاگین‌های قدیمی remark را با پرچم‌های ویژگی (feature flags) جدیدی که Sätteri می‌شناسد، جایگزین کنید:

  • remark-gfmfeatures.gfm
  • remark-frontmatterfeatures.frontmatter
  • remark-mathfeatures.math
  • remark-directivefeatures.directive
  • remark-smartypantsfeatures.smartPunctuation
  • remark-wiki-linkfeatures.wikilinks

این پرچم‌ها همان قابلیت‌ها را بدون نیاز به بارگذاری جداگانه پلاگین فعال می‌کنند.

قوانینی برای سازگاری پلاگین‌ها با Sätteri

  • فقط یک بار عبور (Single pass only) – پلاگین‌ها درخت را تنها یک بار می‌بینند؛ آن‌ها نمی‌توانند گره‌هایی را که در مراحل بعدی خط لوله (pipeline) ایجاد شده‌اند، دوباره بررسی کنند.
  • کارخانه برای وضعیت (Factory for state) – برای هر صفحه یک شیء وضعیت (state object) تازه بسازید تا از نشت داده‌ها بین صفحات جلوگیری شود.
  • گره‌های تغییرناپذیر (Immutable nodes) – هنگام نیاز به تغییر، یک گره جدید برگردانید؛ تغییر دادن (mutating) یک گره موجود می‌تواند مراحل پردازش بعدی را مختل کند.
  • بدون قطعات ریشه (No root fragments) – به جای ایجاد یک گره قطعه (fragment node) در سطح بالا، خواهر-برادرها (siblings) را از طریق کمک‌کننده‌های درج (insertion helpers) ارائه شده وارد کنید.

هنگام تطبیق یک پلاگین موجود، به خروجی نمونه در فایل README تکیه نکنید. HTML پلاگین اصلی را رندر کنید، آن مارک‌آپ را ثبت کنید و از آن به عنوان نقطه مرجع برای نسخه سازگار با Sätteri خود استفاده کنید.

نتیجه‌گیری

موتور Sätteri در Astro 7 سرعت را به ارمغان می‌آورد اما باعث تغییر ترتیب زنجیره پردازش markdown می‌شود: رندر کردن ریاضیات در سطح MDAST، قرار دادن پلاگین‌های heading-ID در ابتدا، و محدود کردن پیکربندی به سه فیلد پذیرفته‌شده. با دنبال کردن نگاشت feature-flag و رعایت قوانین single-pass و immutable-node، ریاضیات، anchorها و تم‌بندی‌های سفارشی که سایت شما به آن‌ها وابسته است را بازیابی خواهید کرد. این تلاش در ابتدا انجام می‌شود؛ اما پاداش آن، یک خط لوله (pipeline) markdown پیش‌بینی‌پذیرتر و سریع‌تر است.