ایجاد PDF با Node.js – از صفر تا صد


همه ما از PDF استفاده میکنیم. PDF یکی از رایجترین فرمتهای فایل به حساب میآید. از این رو بسیاری از اپلیکیشنها، این قابلیت را دارند که از انواع مختلفی از اسناد، فایل PDF بسازند. ایجاد PDF با Node.js با استفاده از کتابخانههای شخص ثالث کار آسانی است و میتوانیم به سهولت این قابلیت را به اپلیکیشنهای خود اضافه کنیم.
در این مقاله، اپلیکیشنی میسازیم که به کاربران امکان میدهد سندهای خود را در یک ادیتور متنی وارد کنند و از روی آن PDF ایجاد نمایند. ما از Express به عنوان بکاند و از ریاکت به عنوان فرانتاند استفاده میکنیم.
بکاند
کار خود را از بکاند آغاز میکنیم.
برای شروع یک دایرکتوری پروژه ایجاد میکنیم که پوشهای به نام backend در آن قرار دارد. سپس در پوشه backend دستور زیر را اجرا میکنیم تا اپلیکیشن Express اجرا شود:
npx express-generator
در ادامه با اجرای دستور npm i پکیجها را نصب میکنیم. سپس پکیجهای خودمان را نصب میکنیم. برای اجرای اپلیکیشن با جدیدترین نسخه جاوا اسکریپت به Babel نیاز داریم. برای درخواستهای «بین دامنهای» (cross-domain) از فرانتاند، پکیج CORS را نصب میکنیم، پکیج HTML-PDF برای تبدیل رشتههای HTML به PDF استفاده میشود، پکیج Multer برای آپلود، Sequelize برای ORM و SQLite3 نیز برای پایگاه داده مورد استفاده قرار خواهند گرفت.
همه این پکیجها را با دستور زیر نصب میکنیم:
npm i @babel/cli @babel/core @babel/node @babel/preset-env cors html-pdf sequelize sqlite3 multer
سپس بخش scripts فایل package.json را طوری تغییر میدهیم که به صورت زیر درآید:
"start": "nodemon --exec npm run babel-node --./bin/www","babel-node": "babel-node"
بدین ترتیب میتوانیم اپلیکیشن را به جای محیط زمان اجرای معمول Node با Babel اجرا کنیم. سپس باید یک فایل به نام .babelrc در پوشه backend ایجاد کرده و کد زیر را در آن قرار دهیم:
کد فوق تعیین میکند که اپلیکیشن را با جدیدترین نسخه از جاوا اسکریپت اجرا میکنیم. سپس کد پایگاه داده را اضافه میکنیم. ابتدا دستور زیر را در پوشه backend اجرا کنید تا کد Sequelize تولید شود:
npx sequelize-cli init
اینک باید فایل config.js را در پروژه خود داشته باشیم. کد زیر را در این فایل اضافه کنید:
کد فوق SQLite را برای پایگاه داده ما اعلان میکند. سپس مدل خود را ایجاد کرده و با اجرای دستور زیر migration میکنیم:
npx sequelize-cli model:create --name Document --attributes name:string,document:text,pdfPath:string
بدین ترتیب یک مدل Document و یک جدول Documents ایجاد میشود. سپس برای ایجاد پایگاه داده دستور زیر را اجرا میکنیم:
npx sequelize-cli db:migrate
اکنون باید مسیرهای خود را ایجاد نماییم. به این منظور فایلی به نام pdf.js در پوشه routes میسازیم و کد زیر را به آن اضافه میکنیم:
عملیات استاندارد CRUD را روی جدول Documents در 4 مسیر نخست اجرا میکنیم. عملیات GET را برای واکشی همه Documents، عملیات POST را برای ایجاد یک Document از روی پارامترهای آن، عملیات PUT را برای بهروزرسانی یک Document بر اساس ID و عملیات DELETE را برای حذف کردن یک Document با گشتن به دنبال ID آن داریم. از HTML در فیلد document برای تولید PDF در ادامه استفاده خواهیم کرد.
generatePdf تابعی است که به ما امکان میدهد PDF را بسازیم. ID را از URL به دست میآوریم و سپس از پکیج HTML-PDF برای تولید PDF بهره میگیریم. با تبدیل سند HTML به یک شیء استریم فایل با استفاده از پکیج HTML-PDF اقدام به تولید PDF میکنیم. سپس استریم را در یک فایل مینویسیم و مسیر را در فایل در مدل Document با ID موجود در پارامتر URL ذخیره میکنیم.
همچنین یک مسیر uploadImage داریم تا به کاربر امکان دهیم که تصاویر را با CKEditor آپلود کند. این پلاگین در پاسخ انتظار پارامترهای uploaded و url را میکشد که تابع ما بازگشت میدهد. سپس باید یک پوشه به نام files در دایرکتوری backend اضافه کنیم. در ادامه در فایل app.js کد موجود را با کد زیر عوض میکنیم:
پوشه فایل را با کد زیر عرضه میکنیم:
app.use(express.static(path.join(__dirname, "files")));
همچنین مسیر pdf را با کد زیر عرضه میکنیم:
var pdfRouter = require("./routes/pdf"); app.use("/pdf", pdfRouter);
فرانتاند
اکنون که بکاند کامل شده است، میتوانیم به فرانتاند بپردازیم. با استفاده از اسکریپت Create React App اپلیکیشن React را ایجاد میکنیم. سپس دستور زیر را در پوشه root پروژه اجرا میکنیم:
npx create-react-app frontend
در ادامه پکیجهای خود را نصب میکنیم. از CKEditor به عنوان ادیتور متن استفاده خواهیم کرد. همچنین از Axios برای ایجاد درخواستهای HTTP، از Bootstrap برای استایلبندی، از MobX برای مدیریت ساده حالت، از React Router برای مسیریابی URL-ها به کامپوننتها و از Formik و Yup برای مدیریت مقادیر فرم و اعتبارسنجی آن استفاده خواهیم کرد.
پکیجهای فوق را با دستور زیر نصب میکنیم:
npm i @ckeditor/ckeditor5-build-classic @ckeditor/ckeditor5-react axios bootstrap formik mobx mobx-react react-bootstrap react-router-dom yup
زمانی که پکیجها نصب شدند، میتوانیم کار را شروع کنیم. در فایل App.js کد موجود را با کد زیر عوض میکنیم:
بدین ترتیب نوار فوقانی و مسیر به صفحه اصلی اضافه میشود. در فایل App.js کد موجود را با کد زیر عوض میکنیم:
بدین ترتیب مقداری فاصلهبندی به صفحه اضافه شده و پیامهای اعتبارسنجی مربوط به ادیتور متنی استایلبندی شده و رنگ navbar نیز تغییر مییابد. سپس فرم را برای افزودن و ویرایش سندها ایجاد میکنیم. به این منظور یک فایل به نام DocumentForm.js در پوشه src ایجاد کرده و کد زیر را اضافه میکنیم:
سپس From مربوط به React Bootstrap را درون کامپوننت Formik قرار میدهیم تا تابع مدیریت را از Formik دریافت کرده و مستقیماً در فیلدهای React Bootstrap مورد استفاده قرار دهیم.
این کار را در مورد CKEditor نمیتوانیم انجام دهیم، از این رو خودمان برخی «دستگیرههای فرم» (form handlers) را برای ادیتور متنی مینویسیم. میتوانیم prop به نام data را در CKEditor تنظیم کنیم تا مقدار ورودی ادیتور متنی تعیین شود. تابع onInit زمانی استفاده میشود که کاربران تلاش کنند یک سند موجود را ویرایش کنند، زیرا باید prop به نام data را با ادیتوری تنظیم کنیم که با اجرای دستور زیر مقداردهی میشود:
prop به نام onChange تابع دستگیره برای تعیین content در زمان بهروزرسانی است و از این رو prop به نام data جدیدترین مقدار را خواهد داشت و در زمان کلیک کاربر روی Save تحویل میشود. ما از پلاگین CKFinder برای آپلود تصاویر استفاده میکنیم. برای این که آن را عملیاتی سازیم، باید URL آپلود تصویر را روی URL مسیر upload در بکاند تنظیم کنیم.
اسکیمای اعتبارسنجی فرم از سوی شیء schema در Yup عرضه شده است که در ابتدای کد ایجاد میشود. ما بررسی میکنیم آیا فیلد name وجود دارد یا نه.
تابع handleSubmit برای تحویل دادهها به بکاند مورد استفاده قرار میگیرد. ما هر دو شیء content و evt را بررسی میکنیم تا ببینیم آیا هر دو فیلد وجود دارند یا نه، زیرا نمیتوانیم از دستگیرههای فرم Formik مستقیماً در کامپوننت CKEditor استفاده کنیم.
اگر همه چیز معتبر باشد، بسته به این که prop به نام edit مقدار true دارد یا نه، یک سند جدید اضافه کرده یا سند موجود را ویرایش میکنیم. زمانی که ذخیرهسازی موفق باشد، getAllDocuments را فراخوانی میکنیم تا با دستور زیر جدیدترین سند را در استور MobX مقداردهی کنیم:
سپس صفحه اصلی را با ایجاد فایل HomePage.js در پوشه src میسازیم:
ما یک جدول React Bootstrap برای لیستبندی سندها به همراه دکمههایی برای حذف یا ویرایش سندها داریم و یک دکمه نیز به تولید PDF اختصاص یافته است. ضمناً یک لینک ppen نیز برای باز کردن PDF در هر ردیف قرار دارد. همچنین دکمهای برای ایجاد PDF در بخش فوقانی جدول وجود دارد.
زمانی که صفحه بارگذاری میشود، getAllDocuments را فراخوانی میکنیم و آنها را در استور MobX مقداردهی میکنیم. سپس modal-های افزودن و ویرایش را به ترتیب با تابعهای openAddTemplateModal ،closeAddModal، cancelAddModal و cancelEditModal باز و بسته میکنیم. در ادامه فایل request.js را در پوشه src ایجاد کرده و کد زیر را به آن اضافه میکنیم:
بدین ترتیب تابعهای مورد نیاز برای ایجاد درخواست به مسیرهای بکاند اضافه میشوند. سپس دستور MobX را ایجاد میکنیم. به این منظور فایل store.js را در پوشه src ایجاد کرده و کد زیر را در آن قرار میدهیم:
تابعی به نام setDocuments داریم که دادههای عکس را در استور قرار میدهد و در HomePage و DocumentForm مورد استفاده قرار میگیرد. ما آن را پیش از اکسپورت کردن، وهلهسازی میکنیم و از این رو تنها در یک محل باید با آن کار کنیم. قطعه کد زیر آرایه documents را در DocumentStore به صورت یک نهاد که تغییراتش میتواند از سوی کامپوننتها مورد نظارت قرار گیرد ایجاد میکند:
تابع setDocuments به صورت تابعی ایجاد شده که میتواند برای تعیین آرایه documents در استور مورد استفاده قرار گیرد. سپس نوار فوقانی را با ایجاد فایل TopBar.js در پوشه src ایجاد کرده و کد زیر را در آن قرار میدهیم:
کد فوق شامل یک Navbar به صورت React Bootstrap است که نوار فوقانی را با لینکی به صفحه اصلی و نام اپلیکیشن نمایش میدهد. ما آن را تنها با token ارائه شده در حافظه لوکال نمایش میدهیم. سپس pathname را بررسی میکنیم تا لینکهای صحیح را با تعیین prop به نام active هایلایت کنیم. سپس در فایل index.html کد موجود را با کد زیر عوض میکنیم:
بدین ترتیب Bootstrap CSS را اضافه میکنیم و عنوان را تغییر میدهیم. پس از نوشتن همه این کدها میتوانیم اپلیکیشن را اجرا کنیم. پیش از اجرای هر چیز، ابتدا nodemon را با اجرای دستور زیر نصب میکنیم:
npm i -g nodemon
بدین ترتیب دیگر لازم نیست در زمان تغییر یافتن فایلها، بکاند را به صورت دستی ریاستارت کنیم. سپس بکاند را با اجرای دستور npm start در پوشه backend و همچنین اجرای دستور npm start در پوشه frontend آغاز میکنیم. در ادامه اگر از شما سؤال شود میخواهید آن را از پورت متفاوتی اجرا کنید، گزینه yes را انتخاب کنید. بدین ترتیب نتیجهای مانند تصویر زیر به دست میآید:
بدین ترتیب به پایان این راهنما میرسیم.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی جاوا اسکریپت
- مجموعه آموزشهای برنامهنویسی
- آموزش Node.js — مجموعه مقالات مجله فرادرس
- استفاده از الگوی طراحی سلکتور در Node.js — از صفر تا صد
- آموزش Node.js: آشنایی با استریم ها و کار با MySQL — بخش دوازدهم
==