راهنمای گام به گام: با رندر سمت سرور و استقرار Firebase، برنامه Angular خود را بهینه سئو کنید

مشتری برای یک جلسه در اوایل ساعت 7:00 صبح تماس می گیرد و می گوید که با کارشناسان سئو صحبت کرده اند و سایت ما از نظر سئو رتبه بسیار پایینی دارد، بنابراین هیچ تعاملی در جستجوی Google دریافت نمی کنیم. این اتفاق پس از یک ماه از استقرار برنامه ما رخ داد. مشتری به صراحت می گوید: “اگر مردم نتوانند ما را در گوگل پیدا کنند، کسب و کار چه فایده ای دارد؟” این در واقع یک بیانیه بسیار درست بود، و من با این ایده موافق بودم. بنابراین، بعداً، یک فنجان قهوه، شروع به حفاری کردم تا بفهمم چگونه اپلیکیشن Angular 18 خود را سئوساز کنم.
پس از کمی حفاری، با رندر سمت سرور (SSR) و دو بسته، یعنی “@angular/platform-server” و “@angular/ssr” برخوردم.
اگر به angular.dev در بخش SSR نگاه کنید، آنها سه فایل سرور را به شما نشان می دهند که چیزی شبیه به این هستند:
my-app
|-- server.ts # application server
└── src
|-- app
| └── app.config.server.ts # server application configuration
└── main.server.ts # main server application bootstrapping
بنابراین من پیش رفتم و سه فایل سرور را در برنامه خود ایجاد کردم.
قبل از اینکه ادامه دهم و محتویات سه فایل سرور را نشان دهم، تغییر دیگری وجود داشت که باید در فایل app.config.ts خود ایجاد کنم.
من مجبور شدم ارائه دهندگان خود را تغییر دهم تا دو ارائه دهنده Factory جدید اضافه کنم، یعنی provideZoneChangeDetection، که از بسته “@angular/core” می آید، و ارائهClientHydration، که از بسته “@angular/platform-browser” می آید.
provideZoneChangeDetection خود توضیحی است به این معنا که ما برنامه Angular را برای استفاده از Zone.js برای تشخیص تغییر پیکربندی میکنیم، و گزینه eventCoalescing تضمین میکند که تشخیص تغییر تنها یک بار زمانی که چندین رویداد از یک نوع راهاندازی میشوند اجرا میشود.
provideClientHydration صرفاً برای Angular Universal است که به برنامه میگوید در هنگام راهاندازی برنامه Angular از HTML ارائهشده توسط سرور در سمت کلاینت مجدداً استفاده کند، بهجای اینکه برنامه را کاملاً دوباره رندر کند.
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideClientHydration()
...rest of the Factory providers
]
با این تغییرات اکنون به سراغ فایل های سرور می رویم.
ما با app.config.server.ts با تعریف پیکربندی به صورت زیر شروع می کنیم:
const serverConfig: ApplicationConfig = {
providers: [provideServerRendering()],
};
export const config = mergeApplicationConfig(appConfig, serverConfig);
پیکربندی ارسال شده به mergeApplicationConfig، هم پیکربندی سرور جدید و هم پیکربندی قبلی است که ما برای ارائه تشخیص تغییرات و هیدراتاسیون کلاینت تغییر داده ایم.
با این تغییرات به main.server.ts می رویم.
کد موجود در main.server.ts به شکل زیر است:
const bootstrap = () =>
bootstrapApplication(AppComponent, {
providers: config.appConfig.providers,
});
export default bootstrap;
ماژول بوت استرپ صادر شده قرار است به فایل server.ts وارد شود و server.ts سرور اصلی ما خواهد بود که به برنامه ما برای SSR سرویس می دهد.
چیزی شبیه به این خواهد شد.
export function app(): express.Express {
const server = express();
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');
const indexHtml = join(serverDistFolder, 'index.server.html');
const commonEngine = new CommonEngine();
server.set('view engine', 'html');
server.set('views', browserDistFolder);
server.get(
'**',
express.static(browserDistFolder, {
maxAge: '1y',
index: 'index.html',
}),
);
// All regular routes use the Angular engine
server.get('**', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;
commonEngine
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: browserDistFolder,
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
})
.then(html => res.send(html))
.catch(err => next(err));
});
return server;
}
function run(): void {
const port = process.env['PORT'] || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
run();
در این مرحله ممکن است دیده باشید که ما از express در فایل server.ts استفاده می کنیم و این درست است، ما در واقع از express برای ایجاد یک سرور و ارائه برنامه از آنجا استفاده می کنیم.
همچنین می توانید مشاهده کنید که ماژول بوت استرپ به عملکرد رندر موتور معمولی منتقل می شود که از بسته angular/ssr که در ابتدا نصب کرده ایم می آید.
از نظر پیکربندی ما 90٪ در آنجا هستیم. اکنون باید تغییراتی در فایل angular.json ایجاد کنیم تا مطمئن شویم که ساختها از ssr پشتیبانی میشوند.
در بخش ساخت angular.json بعد از بخش اسکریپت این را اضافه کنید
"extractLicenses": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true,
"server": "src/main.server.ts",
"prerender": true,
"ssr": {
"entry": "server.ts"
}
با این قطعه در جای خود، پیکربندی اکنون کامل شده است.
اکنون وقتی اسکریپت ساخت خود را اجرا می کنید، خواهید دید که پوشه دیگری در داخل dist به نام سرور ایجاد می کند. شما می توانید یک اسکریپت برای خدمت به برنامه از پوشه dist ایجاد کنید
"serve:ssr": "node dist/your-app-name/server/server.mjs",
می توانید متوجه شوید که موتور view mjs است، من وارد جزئیات آن قطعه کد نمی شوم، برای تغییر آن به فایل server.ts مراجعه کنید، اما با این کار باید ssr را آماده داشته باشید.
اکنون هنگامی که از متا از @angular/platform-browser استفاده می کنید، باید بتوانید تگ های ایجاد شده را هنگام رفتن و مشاهده منبع صفحه خاص مشاهده کنید.
چیزی شبیه به این
import { Meta } from '@angular/platform-browser';
private metaService = inject(Meta);
this.metaService.addTag({
name: 'description',
content: 'Welcome to our page !',
});
قطعه دوم میزبانی برنامه با استفاده از Firebase است. به راستی تنها کاری که باید انجام دهیم این است که فایل firebase.json را به شکلی شبیه به این تغییر دهیم.
"hosting": {
"public": "dist/your-application-name/browser",
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
اگر مانند من از فرمان استقرار firebase استفاده میکنید، ما همچنان میخواهیم کد کلاینت را اجرا کنیم، نه کد سرور را در firebase، بنابراین در پیکربندی خود به جای سرور به مرورگر اشاره میکنیم. به دلیل تغییر پیکربندی که در فایل angular.json ایجاد کردهایم، همچنان باید بتوانید متا تگها را در بسته مشتری ببینید. و با این مراحل توانستم متا تگ ها و محتوایی را که در مرورگر در منبع صفحه رندر شده است ببینم.
این تجربه من در ایجاد سئوی نرم افزار Angular بوده است. از اینکه پست را خواندید متشکرم
سپاسگزاریها
این مقاله از پیاده سازی های Angular SSR که در صفحات GitHub زیر یافت می شود الهام گرفته شده است:
“ganatan/angular-ssr” (https://github.com/ganatan/angular-ssr)
“angular-university/angular-ssr-course” (https://github.com/angular-university/angular-ssr-course)
میخواهم از دست اندرکاران هر دو پروژه به خاطر دیدگاههای ارزشمند و نمونههای کدشان که به من در ایجاد این محتوا کمک زیادی کردهاند، تشکر کنم.