بدون هیچ نرم‌افزاری markdown رو به فرمت‌های مختلف تبدیل کنیم!

تقریبا یه هفته پیش بود که کارای آخر «کتاب سوال و جواب‌های ری‌اکت» رو داشتم انجام میدادم (اگه نمیدونین این کتاب چیه، می‌تونین به مطلب قبلی‌م مراجعه کنین) و دیگه می‌خواستم برای گرفتن یه خروجی قابل ارائه آماده‌ش کنم.موضوعی که خیلی وقت بود ذهنمو مشغول کرده بود، شاید برای شما هم به عنوان یه مسئله مطرح باشه، این بود که چطوری می‌تونیم یه محتوای متنی که حالا مثلا یه کتاب ۲۰۰ صفحه‌ای باشه رو به صورت جمعی روی گیت‌هاب ببریم جلو و امکان اینو داشته باشیم که به صورت پیوسته محتوای تولید شده رو تغییر بدیم و به بعد هر موقع خواستیم به شکل pdf، epub، mobi و بقیه چیزا خروجی بگیریم؟https://www.agingresearch.org/reasonable-and-necessary/tax-papers-falling/تجربه کتاب قبلی(یادگیری اصولی جاواسکریپت) که روی ایندیزاین کار شده بود، خیلی خوشایند نبود! چون هم ویراستاری کتاب خیلی زمان‌بر بود، هم نمیشد به شکل جمعی و بهینه روی کتاب کار کرد و کلی دردسر دیگه داشت.پس استفاده از نرم‌افزارهای ورد یا ایندیزاین کلا منتفی بودن! یه روشی باید پیدا می‌کردم که بشه یه کتاب به فرمت‌های مختلف، قابلیت شخصی‌سازی بالا، پشتیبانی از فارسی و فونت‌های خاص رو فراهم کنه و کنار همه اینا امکان اینو بهمون بده که بتونیم به شکل پیوسته و کم‌هزینه خروجی بگیریم.ایده‌های خیلی زیادی مثل نوشتن یه سیستم از پایه برای تبدیل‌هایی که می‌خواییم یا استفاده از گوگل docs به ذهنم می‌رسید ولی بازم نه فرصتشو داشتم و نه کیفیت کار می‌تونست خوب در بیاد.کلی مطلب راجع به نحوه ساخت pdf و doc و استفاده از LaTeX و... خوندم و کلی هم مینی پروژه براش درست کردم ولی نمیشد!‌همینطوری داشتم توی سایت‌های مختلف می‌گشتم راجع به LaTeX و موتورهای مختلف می‌خوندم که یهو رسیدم به یه repo خیللللی خفن توی گیت‌هاب!https://github.com/shd101wyy/markdown-preview-enhancedاین extension خیلی خیلی خوبه، از KaTeX و MathJax و... هم پشتیبانی می‌کنه، هم برای atom و هم برای vscode قابل استفاده‌ست و خیلی هم configurable ـه.سریع نصب و تستش کردم و همه چی خوب بود. خیلی خوب فارسی رو هم پشتیبانی می‌کرد و هم امکان خروجی گرفتن داشت، ولی... فونتش خیلی داغون بود، لینک‌های فهرست و برگشت به بالا از کار افتاده بودن و pdfاش خیلی استایل ایناش درست نبود و فقط می‌اومد یه خروجی قابل خوندن میداد.یه کم سرچ کردم و دیدم که همون قابلیت configurable بودنش، این اجازه رو میده که روی مراحل مختلف parse شدن و تبدیل متن markdown به فرمت‌های مختلف یه سری جاهاش دست ببریم و بتونیم کارهای دلخواه‌مون رو انجام بدیم. خب تا اینجا فقط می‌دونستم که میشه کنترل کارهای مختلف تبدیل‌های LaTeX رو دست گرفت ولی چطوری؟!من روی vscode باهاش کار کردم و این مطلب رو هم براساس همین پیش‌زمینه می‌نویسم. وقتی این extension نصب می‌شه یه فایل توی root کاربر جاری و تو فولدر `.mume` ایجاد می‌کنه. mume هم به قول خود سازنده قلب این پروژه‌س و تقریبا یه core برای تبدیلات markdown هستش. البته شاید نیازی به دونستن این مسیر نیست، چون با زدن دکمه های Cmd+shift+p می‌تونیم دستوراتی رو بنویسیم که به فایل‌های کانفیگ mume برسیم.توی اون پوشه یه سری فایل داریم، دوتاشون خیلی مهمن، `parser.js` و `style.less`. این دوتا فایل می‌تونن کمک کنن که توی ساخت کتاب تغییراتی بدیم. مثلا توی فایل style.less میشه یه سری css برای استایل دهی صفحات تعریف کرد که موقع خروجی لحاظ بشن! و توی parser میتونیم یه سری توابع callback رو توی مراحل مختلف ساخته شدن کتاب کنترل کنیم. مثل `onWillParseMarkdown` ، `onDidParseMarkdown`، `onWillTransformMarkdown` ، `onDidTransformMarkdown` و ... . حالا احتمالا متوجه میزان اهمیت این دوتا فایل شدین. مسئله مربوط به فونت و استایل‌دهی‌های کلی تقریبا با دستکاری style.less حل شد. بقیه کارهای اصلی لازم بود که با دست کاری‌هایی توی فایل parser باید انجام می‌شد، مثلا لینک‌های فهرست باید با کلیک کردن می‌رفتن به سوال مربوطه. یعنی:هر کدوم از این لینک‌ها باید با کلیک شدنش می‌رفت به سوال مربوطه:مسئله این بود که باید توی مرحال اجرایی برای تولید این فرمت‌ها دستکاری می‌کردم، کتابخونه‌ای که استفاده می‌کردم هم قابلیت callback زدن توی مراحل مختلف رو داشت ولی پیدا کردن markdown توی اون callbackها و تغییر دادنش واقعا سخت بود، چون از یه طرف متن فارسی بود و این کتابخونه همه متن‌ها رو میاد یه انکد htmlEntities اعمال می‌کنه و از یه طرف دیگه کدهای markdown شروعش اکثرا مشخصه ولی پایانش دست خداست :)) ، مثلا تگ‌های ‌هدینگ با # شروع میشن ولی پایانشون آخر خطه. خلاصه فهمیدن این بخش‌ها توی کتاب و دستکاری‌شون توی فرآیند تبدیل یه کم سخت بود. هدینگ‌هایه کاری که انجام دادم این بود که توی callbackای که بعد از ساخته شدن html مربوط به کتاب بود یه سری regex نوشتم که تبدیلاتی می‌خوام رو انجام بدم. یکی از اصلی ترین تبدیل‌ها دکمه عنوان سوالات بود که باید یه هدینگ و یه آی دی برام تولید میکرد. توی فایل parser.js یه تیکه کد توی onDidParseMarkdown نوشتم که روی نتیجه بدست اومده یه کاری رو برام انجام بده: https://gist.github.com/sayjeyhi/ed702fdd3dc8fab86066b22a06e28bd0 خب این کد باعث شد بتونم هدینگ‌های لینک‌دار که سکشن بندی شدن رو توی pdf درست کنم. اگه دقت کنید توی این کد از crypto استفاده کردم دلیلش اینه که من نیاز داشتم یه سری لینک یونیک درست کنم. همونطوری که یه کم پیش هم گفتم این کتابخونه markdown-preview هم میاد متن‌های فارسی رو html encode میکنه و همین باعث میشه لینک‌های فارسی صحیحی تولید نشن و لینک‌های ما هم کار نکنن. پس باید یه جوری به ازای هر سوال یه شناسه منحصر به فرد ایجاد می‌شد و این شناسه یونیک باید توی فهرست هم قابل دسترس می‌بود. برای همین منظور عنوان اون سوال رو md5 اعمال کردم روش و یه شناسه خوب تولید شد که یونیک بود برای اون سوال.دکمه‌های برگشت به بالابعد از هر سوال یه لینکی داریم که کاربر می‌تونه با کلیک روی اون فهرست برگرده این مورد هم باید لینکش درست می‌شد که مثل همون حالت قبلی با یه regex حل شد: https://gist.github.com/sayjeyhi/56b2fbe85e15ffd53b34aa89e9f1a888 یه لینکی هم که لینک مربوط به هرسوال توی فهرست‌ سوالات بود که باید به جواب مورد نظر وصل میشد: https://gist.github.com/sayjeyhi/267c7cacb6b4e881155062451a66afb6 با این دوتا کد دیگه رفت و برگشت به سوالات و همینطور لینک بازگشت به فهرست هم اوکی شده بود و تقریبا خوب بود کارها. تا اینکه یکی از دوستامون توی توئیتر یه ایده‌ای که خودمم یه بار بهش فکر کرده بودم رو دوباره مطرح کرد :خب اینطوری شد که یه کد هم به مراحل اضافه کردم، با یه regex پیچیده‌تر :)) که با کلیک روی بازگشت به فهرست، برمیگرده به سوالی که قبلا اونجا بودین: https://gist.github.com/sayjeyhi/c37cf9b6d1cbd7c50cfe426ca70563f6 خب تا اینجا دیگه لینک‌بندی خیلی اوکی کار می‌کرد، ولی خب یه چیزی ناقص بود! مگه میشد اخه این pdf رو داد به چاپ و ازش برای نسخه فیزیکی هم استفاده کرد؟ خیلی استایل بندی خوبی نداشت، درسته فونتش اوکی شده بود، لینک‌ها برای مطالعه آنلاین درست کار می‌کردن... ولی برای چاپ واقعا ناقص بود.الهه‌ای به نام pupteerخب تا به اینجای داستان داشت خوش می‌گذشت که متوجه کمبودهای نسخه فیزیکی شدم! من ایده‌ال‌ترین حالتم این بود که بتونم استایل کتاب قبلی که با ایندیزاین کار شده بود رو با اینجا هم داشته باشم. پس دست به کار شدم! قالب بندی کتاب یادگیری اصولی جاواسکریپتبا یه نگاه میشه متوجه شد که خیلی جاه‌طلبانه بوده خواسته‌م، واقعا این layout یه صفحه‌نگاری تقریبا کامل محسوب میشه. خب یه کم خواسته‌مو کمتر کردم و اومدم گفتم که تاثیر گذارترین مولفه‌های کتاب رو داشته باشم کافیه، یه لیست درآوردم که لازم بود داشته باشم، شماره صفحات، بیل‌بیلک خط خطی که گوشه هر صفحه قرار گرفته، پیش‌گفتار و paddingهای درست درمون که بشه برای چاپ فرستاد فایل رو.این لیست رو که درست کردم، بیشتر با نحوه‌ کار این کتابخونه آشنا شدم و فهمیدم که یه شخص سومی وجود داره که الهه قصه ماست (البته شخص سوم‌های زیادی رو ساپورت می‌کنه این کتابخونه و میتونه با ابزارهای جانبی ارتباط برقرار کنه، مثلا رو مک calibre رو میشه نصب کرد و از ابزارهایی مث pandoc و prince هم استفاده کرد). همونطوری که گفتیم بین اینا pupteer که توسط گوگل برای مرورگر chrome ساخته شده الهه قصه ماست، چون هم سریعتره هم کیفیت خیلی خوبی ارائه میده و هم خطای خیلی کمی داره. یه ویژگی خوبش هم اینه که قابلیت کانفیگ شدن(تا یه حدی) رو با استفاده از frontmatter رو بهتون میده. https://gist.github.com/sayjeyhi/e58fd79ea81de9be637d6e71e7070237 اگه کد بالا رو به شکل raw مشاهده کنین، می‌بینین که من برای تصاویری که می‌خواستم توی فوتر قرار بدم دوتا عکس برای سمت چپ و راست رو به شکل base64 اضافه کردم، برای page number توی فوتر و مرکز رو انتخاب کردم، حاشیه‌هایی که می‌خواستم رو تنظیم کردم و قطع وزیری رو برای طول و عرض کتاب ست کردم.این تنظیمات فقط موقع ساخت pdf اضافه میشه و کاری با md , mobi و بقیه فرمت‌ها نداره، چون در حقیقت توی بقیه فرمت‌ها صفحه معنی نداره و محتوا به شکل یکپارچه نمایش داده میشه. نتیجه نهایی یه همچین تصویری میشد:یکی از اصلی‌ترین دلیل‌هایی که مانع شد که بتونم عینا استایل قبلی کتاب رو اجرا کنم، عدم امکان ست کردن کانفیگ جداگانه برای صفحات زوج و فرد توی pupteer بود. به همین دلیل توی شماره صفحه و تصاویر فوتر سعی کردم حالتی رو درست کنم که توی همه صفحات یکی باشه. مورد بعدی عدم امکان تنظیم شروع نمایش هدر و فوتر توی pupteer بود که باعث می‌شد از همون صفحه اول نمایش فوتر و هدر شروع بشه و این مشکل بدی بود. به جز این دو مورد بقیه‌ی مسائلی که برای من دغدغه بودن به راحتی حل شدن. این دو مورد هم توی گیت‌هاب بحث شده بود راجع بهشون(شایدم می‌تونستم با یه کم تلاش بیشتر فیکس کنمشون) ولی فعلا دیگه به همین موارد بسنده کردم و کتاب تولید شد ??.یه مورد آخر هم از خوبی‌های کار با این کتابخونه رو بگم. اینکه شما می‌تونین همون لحظه که markdown می‌نویسین، تغییرات رو هم ببنیین و اینطوری احتمال خطا توی تولید محتوا کمتر میشه.البته خیلی ویژگی‌های خوب دیگه مثل امکان تایپ فرمول پیچیده ریاضی، رسم نمودارهای خاص و .. رو هم داره که من بحثی روشون ندارم ولی اگر خواستین حتما به سایت و ریپوشون سر بزنین. دوباره میزارم این پایین:https://github.com/shd101wyy/markdown-preview-enhancedکدهای خودمم که برای تولید کتاب و کانفیگ‌های مربوط به mume بوده رو روی گیت‌هاب ماریوتک گذاشتم:https://github.com/Mariotek/mume-transpile-configموفق و سربلند و پیروز و خرسند و شاااد باشین، مخلصیم. موردی هم بود خوشحال میشم کامنت بزارین :)سایر نوشته‌هام https://vrgl.ir/EKt7v https://vrgl.ir/p7xp2 https://vrgl.ir/M6OIh