ویرگول
ورودثبت نام
محمد محمدعلیان
محمد محمدعلیان
خواندن ۳ دقیقه·۳ سال پیش

چطوری یه PDF فارسی بر اساس HTML توی Node.js بسازیم؟

سلام ✋
باورتون میشه که برای ساخت PDF توی Node.js یه پکیج مخصوص نداریم که بتونه با متن فارسیم کنار بیاد و فایل html css font و ... بدید تا تبدیلش کنه به PDF ؟! (حداقل الان نداریم) (شایدم من نتونستم پیدا کنم)
خب دیگر نگرانی کافیست چون من امروز اومدم که یه راهکار بدم بشوره ببره همه این مشکلات رو و بتونید خیلی ساده PDF رو با بهترین کیفیتی که می‌تونید خروجی بگیرید ?

این عکس از کاور یه مقاله انگلیسی کپی شده است.
این عکس از کاور یه مقاله انگلیسی کپی شده است.

مشکل چیه؟

داستان از اونجایی شروع شد که من یه فایل HTML داشتم، یه فایل CSS و یه سری تصویر و فونت و باید بر اساس دیتاهایی که سمت خودم دارم حین انجام یه اکشن خاص به PDF تبدیلش کنم.
برای اینکه بتونم دیتاهای توی HTML رو داینامیک کنم که از تمپلیت انجین ejs استفاده کردم بعد برای PDF هم رفتم خیلی ریلکس و خوشحال مثل همیشه توی NPM یه سرچ بزنم که یه پکیج پیدا کنم که اینکار رو برام بکنه و رسیدم به پکیج html-pdf و از اونجایی که دانلود زیادی داره انتظار داشتم که گزینه مطلوبی باشه ولی دیدم فیت نیاز من نیست و با کلی بالا پایین نتونستم کاریش بکنم که با متن فارسی کنار بیاد و استایلا و فایل فونتم رو هم استفاده کنه.
این سری توی گوگل بیشتر سرچ کردم و پکیجا و ابزارای دیگه‌ای که معرفی کرده بودن رو هم سعی کردم ازشون استفاده کنم ولی دیدم واقعا دارن اذیت می‌کنن و یه ابزار perfect پیدا کردم که اسمش رو الان یادم نیست ولی اینطوری بود که با داکر میومد بالا و شما بهش ریکوئست میدادی و فایل PDF رو بهت میداد اون و خروجیشم تمیز و خوب بود ولی نسخه رایگانش یه واترمارک بزرگ می‌زد اون پایین که باعث شد ازش استفاده نکنم.

راه حل من چی بود؟

توی سرچایی که داشتم دیدم که یکی اومده و اینکار رو با puppeteer انجام داده و منم چون قبلا باهاش کار کرده بودم گفتم چرا که نه؟
اگه نمی‌دونید puppeteer چیه باید بگم یه پکیج نوده که می‌تونید باهاش browser رو کنترل کنید، یعنی همون مرورگر chrome رو فرض کنید که می‌تونه رابط گرافیکی نداشته باشه و از امکاناتش استفاده کنید. حالا یکی از امکانات مرورگر چیه؟ آفرین! ساخت PDF ?
دغدغم توی استفاده از puppeteer یه چیز بود: پرفرمنس.
فرض کن: قراره کروم باز کنی رو سرور! یا حسین ? ولی دیدم نه واقعا خیلی زیاد منابع مصرف نمی‌کنه و میشه تو production ازش استفاده کرد.
البته باید یه نکته رو توجه کنید که من فقط یه مرورگر باز داشتم و برای ساخت هر PDF صرفا تب جدید می‌ساختم و بعد از تموم شدن ساخت PDF هم تب رو می‌بستم که منابع بیخودی هدر نره.

توجه کنید که با puppeteer می‌تونید مرورگر رو با رابط کاربری گرافیکیش باز کنید (یعنی توی مود غیر headless) ولی برای ساخت PDF حتما باید تو حالت headless باشید.

نمونه کد

این پروژه چون تعداد فایلاش زیاده نتونستم توی gist بذارم و توی این ریپازیتوری قرارش دادم. (star یادتون نره ?)

جواب سوالات احتمالی راجع به نمونه کد

چرا مستقیم page.setContent رو استفاده نکردم و قبلش goto زدم به فایل ejs ؟! از اونجایی که آدرس دهی فایلای assetم به صورت relative بود نیاز بودش که مرورگر توی اون مسیر باشه تا بتونه فایلای font و image و ... رو resolve کنه پس اول رفتم به اون فایل ejs که طبیعیه مرورگر نتونه parseش کنه و بعد با اون فایل تمپلیت، HTMLم رو رندر کردم.

چرا از پکیج puppeteer-core استفاده کردم؟ چون موقع نصب پکیج puppeteer میره و باینری مرورگر رو دانلود می‌کنه و از اونجایی که تحریمیم روی سرور های ایران به مشکل می‌خورره پس از puppeteer-core استفاده کردم تا مسیر فایل باینری مرورگر رو خودم بهش بگم.

چرا ساختار پروژه روی گیتهاب انقد درب و داغونه :) ؟ چون نمونه کده و قرار نیست همین برداشته بشه و توی production استفاده بشه ?


امیدوارم تونسته باشم یخورده کمک کنم.
محمد محمدعلیان | 8 فروردین 1401
کانال تلگرامم | لینکدینم

pdfbackendnode jspdf فارسی با node js
یه ممد 20 ساله که برنامه‌نویس بک-انده. لینکای من: https://redl.ink/Mohammadalian_1383
شاید از این پست‌ها خوشتان بیاید