برنامه نویسی

رندر جانبی سرور جهانی (USSR) در Angular

Summarize this content to 400 words in Persian Lang
در دنیای توسعه وب، فناوری برای یافتن تعادل بهینه بین عملکرد، تجربه کاربر و کارایی توسعه به طور مداوم در حال تکامل است. یکی از فناوری های کلیدی که توسعه قابل توجهی داشته است، رندر سمت سرور (SSR) یا رندر سمت سرور است. چارچوب Angular نقش مهمی در این تکامل ایفا کرده است.

از صفحات استاتیک گرفته تا محتوای پویا

در ابتدا، وب متشکل از صفحات HTML ایستا بود که در آن تمام محتوا بر روی سرور تولید می شد. با نیاز روزافزون به محتوای پویا، فناوری‌های سمت سرور مانند PHP، ASP و JSP ظهور کرده‌اند که به HTML اجازه می‌دهند به سرعت تولید شود.

دوران رندر سمت مشتری و ظهور Angular

انقلابی در توسعه وب با ظهور فریمورک های قدرتمند جاوا اسکریپت رخ داد و Angular (در اصل AngularJS) یکی از پیشگامان در این زمینه بود. AngularJS که توسط گوگل در سال 2010 منتشر شد، رویکرد جدیدی را برای ساخت برنامه های وب پویا با استفاده از رندر سمت مشتری (CSR) ارائه کرد.

Angular (نسخه 2+) که در سال 2016 منتشر شد، این سنت را با ارائه ابزارهای قدرتمند به توسعه دهندگان برای ایجاد برنامه های پیچیده تک صفحه ای (SPA) ادامه داد. این امکان را برای برنامه های کاربردی تعاملی و پاسخگو فراهم می کرد، اما چالش های جدیدی را نیز به همراه داشت:

بارگیری اولیه آهسته به دلیل اندازه بزرگ باندل جاوا اسکریپت.
مشکلات با سئو، زیرا روبات های جستجوگر همیشه نمی توانند محتوای پویا را به درستی ایندکس کنند.
زمان تا First Meaningful Paint افزایش یافت.

احیای SSR و نقش Angular Universal

با درک محدودیت های رویکرد صرفاً سمت مشتری، جامعه Angular به ایده رندر سمت سرور روی آورد، اما در سطح جدیدی. Angular Universal اینگونه متولد شد – راه حل رسمی SSR برای Angular.

Angular Universal به شما امکان می دهد برنامه های Angular را روی سرور رندر کنید که مشکلات کلیدی CSR را حل می کند:

بارگذاری اولیه صفحه را با ارسال HTML از پیش رندر شده بهبود می بخشد.
سئو را با ارائه ربات های جستجوگر با محتوای کامل افزایش می دهد.
عملکرد را در دستگاه های تلفن همراه و شبکه هایی با اتصالات کند بهبود می بخشد.

تمرین کنید

همه چیز در کلمات جالب به نظر می رسد، بیایید سعی کنیم آن را بررسی کنیم.

ابتدا باید به آنچه که برنامه بدون SSR ارائه می دهد نگاه کنید. برای انجام این کار، باید یک پروژه “خالی” ایجاد کنید.

در اینجا و بیشتر، کد را می توان به طور کامل در کنسول درج کرد

# проверяем, что у нас установлен Angular CLI
npm install -g @angular/cli
# создаем наш демо проект
ng new no-ssr-demo

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ممکن است از ما خواسته شود که پارامترهای لازم را انتخاب کنیم، همه جا کلیک کنید enter

در کنسول باید این خروجی را ببینیم

✔ Packages installed successfully.
Successfully initialized git.

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر همه چیز موفقیت آمیز بود، به پروژه بروید و آن را راه اندازی کنید

cd no-ssr-demo/
npm start

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خروجی باید به این شکل باشد

اما بیایید ببینیم مرورگر وقتی برای اولین بار به سایت ما دسترسی پیدا می کند چه چیزی را دریافت می کند، برای این کار از آن استفاده خواهیم کرد curl. اگر اهل ویندوز هستید فقط به آدرس مراجعه کنید view-source:http://localhost:4200/. نتیجه مشابه خواهد بود

# Важно! ваш сайт может быть запушен на другом порту, если это так, просто замените 4200 на ваш порт
curl localhost:4200

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چه نتیجه ای گرفتیم؟

NoSsrDemo

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا بریم سراغ مرورگر و مقایسه کنیم html

برچسب ما app-root او با کمک Angular تبدیل به یک قو زیبا شد که متاسفانه ربات بی روح آن را نخواهد دید. اما بیایید این را برطرف کنیم، برای مثال، بیایید یک وبلاگ کوچک بسازیم که بتوان با استفاده از نشانه گذاری نوشت markdown

ایجاد یک وبلاگ Markdown ساده با استفاده از Angular و SSR

اگر مراحل بالا را دنبال کردید، می توانید از این کار صرف نظر کنید

npm install -g @angular/cli

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما در حال ایجاد وبلاگ خود هستیم. به سوال ? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? (y/N) کلیک کنید yes یا y

ng new my-blog –routing –style=scss
cd my-blog

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از خروجی موفقیت آمیز، باید کتابخانه را نصب کنید marked، که ما را تجزیه می کند mardown

npm install marked

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اولین قدم ایجاد منابع نمایش و پیکربندی سرور است

// папка с нашими файлами .md
const articlesFolder = resolve(serverDistFolder, ‘../../../articles’);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در زیر پیاده سازی می کنیم API برای دریافت آنها

server.get(‘/api/articles’, async (req, res) => {
try {
const files = await fs.readdir(articlesFolder);

const articlePromises = files
.filter((file) => file.endsWith(‘.md’))
.map(async (file) => {
const filePath = path.join(articlesFolder, file);
try {
const fileData = await fs.readFile(filePath, ‘utf8’);
return {
fileName: file.replace(‘.md’, ”),
content: fileData.split(‘\n’).slice(0, 150),
};
} catch (err) {
console.error(`Error reading file ${file}:`, err);
return null;
}
});

const articles = await Promise.all(articlePromises);
res.json(articles.filter((article) => article !== null));
} catch (err) {
console.error(‘Error scanning directory:’, err);
res.status(500).json({ error: ‘Unable to scan directory’ });
}
});

server.get(‘/api/articles/:name’, (req, res) => {
const fileName = req.params.name + ‘.md’;
const filePath = path.join(articlesFolder, fileName);

fs.readFile(filePath, ‘utf8’)
.then((data) => res.send(data))
.catch(() => res.status(404).send(‘Article not found’));
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در ریشه پروژه، یک پوشه ایجاد کنید articles که در آن 1-2 فایل با پسوند md

پس از اجرای دستور npm run build && npm run serve:ssr:my-blog سرور شروع به کار می کند (در اینجا با دقت) پس از هر اصلاح، دستور باید دوباره راه اندازی شود، بنابراین اگر می خواهیم قسمت جلویی را توسعه دهیم و هر بار بیلد ننویسیم، باید آن را اجرا کنیم و جداگانه بنویسیم. npm run startبرای جلوگیری از سقوط درخواست ها، باید فعال کنید server.use(cors()); (خوب، کتابخانه را مطابق با آن نصب کنید)

کار کثیف تمام شده است، اکنون ما یک سرور داریم که محتوای یک مقاله خاص را ارائه می دهد، برای همه یک محتوای کوچک (150 کاراکتر اول) و نام فایل را برمی گرداند.

بریم جلو رو بنویسیم و اول از همه کامپوننت های جدید اضافه کنیم و ایمپورت ها رو اصلاح کنیم (فراموش نکن به پوشه با src/app خوب، برای هر یک پوشه ایجاد کنید)

ng g c ArticleComponent
ng g c HomeComponent

#резолверы
ng g r ArticleResolver
ng g r arcticlesResolver

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

export const routes: Routes = [
{
path: ‘article/:slug’,
component: ArticleComponent,
resolve: {
content: ArticleResolver,
},
},
{
path: ”,
component: HomeComponent,
resolve: {
content: arcticlesResolver
},
},
];

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کامپوننت مقاله

import { AsyncPipe, NgIf } from ‘@angular/common’;
import { Component, inject } from ‘@angular/core’;
import { toSignal } from ‘@angular/core/rxjs-interop’;
import { ActivatedRoute } from ‘@angular/router’;
import { map } from ‘rxjs’;

@Component({
selector: ‘app-article’,
standalone: true,
imports: [AsyncPipe, NgIf],
template: `

`
})
export class ArticleComponent {
readonly #route = inject(ActivatedRoute);

content = toSignal(this.#route.data.pipe(map(({ content }) => content)));
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ArticleResolver

import { inject, Injectable } from ‘@angular/core’;
import { SafeHtml } from ‘@angular/platform-browser’;
import { ActivatedRouteSnapshot, Resolve } from ‘@angular/router’;
import { Observable } from ‘rxjs’;
import { MarkdownService } from ‘../../services/markdown.service’;

@Injectable({ providedIn: ‘root’})
export class ArticleResolver implements Resolve {
readonly #markdownService = inject(MarkdownService);

resolve(route: ActivatedRouteSnapshot): Observable {
const article = route.paramMap.get(‘slug’) ?? ”;
return this.#markdownService.getMarkdownFromServer(article);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کامپوننت صفحه اصلی

import { HttpClient } from ‘@angular/common/http’;
import { Component, inject } from ‘@angular/core’;
import { toSignal } from ‘@angular/core/rxjs-interop’;
import { ActivatedRoute, ResolveFn, RouterModule } from ‘@angular/router’;
import { map } from ‘rxjs’;
import { ArticlePreviewComponent } from ‘../article-preview/article-preview.component’;

interface Article {
fileName: string;
content: string;
}

export const arcticlesResolver: ResolveFn = () => {
const http = inject(HttpClient);

return http.get(‘http://localhost:4000/api/articles’);
};

@Component({
selector: ‘app-home’,
standalone: true,
imports: [RouterModule, ArticlePreviewComponent],
styleUrl: ‘./home.component.scss’,
template: `

@for (item of articles(); track item) {

}
`,
})
export class HomeComponent {
readonly #route = inject(ActivatedRoute);

articles = toSignal(
this.#route.data.pipe(map(({ content }) => content as Article[]))
);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کامپوننت پیش نمایش مقاله

import { AsyncPipe, DatePipe } from ‘@angular/common’;
import {
ChangeDetectionStrategy,
Component,
inject,
input,
} from ‘@angular/core’;
import { toSignal } from ‘@angular/core/rxjs-interop’;
import { RouterLink } from ‘@angular/router’;
import { MarkdownService } from ‘../../services/markdown.service’;

@Component({
selector: ‘app-article-preview’,
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [RouterLink, DatePipe, AsyncPipe],
template: `

{{ name() }}
{{ rendered() }}

Опубликовано {{ currentDate | date : ‘medium’ }}

`,
styles: `
:host {
cursor: pointer;
}
`,
})
export class ArticlePreviewComponent {
readonly #markdownService = inject(MarkdownService);

name = input();
content = input();
currentDate = new Date();

rendered = toSignal(
this.#markdownService.parseMarkdown(this.content() ?? ”)
);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

MarkdownService

import { HttpClient } from ‘@angular/common/http’;
import { inject, Injectable } from ‘@angular/core’;
import { DomSanitizer, SafeHtml } from ‘@angular/platform-browser’;
import { marked } from ‘marked’;
import { from, Observable, of } from ‘rxjs’;
import { map, switchMap } from ‘rxjs/operators’;

@Injectable({
providedIn: ‘root’,
})
export class MarkdownService {
readonly #http = inject(HttpClient);
readonly #sanitizer = inject(DomSanitizer);

getMarkdownFromServer(file: string): Observable {
return this.#http
.get(`http://localhost:4000/api/articles/${file}`, {
responseType: ‘text’,
})
.pipe(
switchMap((res) => {
const parsed = marked.parse(res);
return typeof parsed === ‘string’ ? of(parsed) : from(parsed);
}),
map((html) => this.#sanitizer.bypassSecurityTrustHtml(html)),
);
}

parseMarkdown(content: string): Observable {
return of(content).pipe(
map((markdown) => {
console.log(markdown);
return marked.parse(markdown);
}),
map((html) => this.#sanitizer.bypassSecurityTrustHtml(html as string))
);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مرحله همه چیز باید کار کند، اگر کار نکرد، غم انگیز است، آن را امتحان کنید، گریه کنید، برای من هم کار نمی کند، کد اینجاست https://github.com/alaev-dev/my-blogاما چه به دست آوردیم

واقعی واقعی html، که با اسکریپت های کوچک js

در دنیای توسعه وب، فناوری برای یافتن تعادل بهینه بین عملکرد، تجربه کاربر و کارایی توسعه به طور مداوم در حال تکامل است. یکی از فناوری های کلیدی که توسعه قابل توجهی داشته است، رندر سمت سرور (SSR) یا رندر سمت سرور است. چارچوب Angular نقش مهمی در این تکامل ایفا کرده است.

از صفحات استاتیک گرفته تا محتوای پویا

در ابتدا، وب متشکل از صفحات HTML ایستا بود که در آن تمام محتوا بر روی سرور تولید می شد. با نیاز روزافزون به محتوای پویا، فناوری‌های سمت سرور مانند PHP، ASP و JSP ظهور کرده‌اند که به HTML اجازه می‌دهند به سرعت تولید شود.

دوران رندر سمت مشتری و ظهور Angular

انقلابی در توسعه وب با ظهور فریمورک های قدرتمند جاوا اسکریپت رخ داد و Angular (در اصل AngularJS) یکی از پیشگامان در این زمینه بود. AngularJS که توسط گوگل در سال 2010 منتشر شد، رویکرد جدیدی را برای ساخت برنامه های وب پویا با استفاده از رندر سمت مشتری (CSR) ارائه کرد.

Angular (نسخه 2+) که در سال 2016 منتشر شد، این سنت را با ارائه ابزارهای قدرتمند به توسعه دهندگان برای ایجاد برنامه های پیچیده تک صفحه ای (SPA) ادامه داد. این امکان را برای برنامه های کاربردی تعاملی و پاسخگو فراهم می کرد، اما چالش های جدیدی را نیز به همراه داشت:

  1. بارگیری اولیه آهسته به دلیل اندازه بزرگ باندل جاوا اسکریپت.
  2. مشکلات با سئو، زیرا روبات های جستجوگر همیشه نمی توانند محتوای پویا را به درستی ایندکس کنند.
  3. زمان تا First Meaningful Paint افزایش یافت.

احیای SSR و نقش Angular Universal

با درک محدودیت های رویکرد صرفاً سمت مشتری، جامعه Angular به ایده رندر سمت سرور روی آورد، اما در سطح جدیدی. Angular Universal اینگونه متولد شد – راه حل رسمی SSR برای Angular.

Angular Universal به شما امکان می دهد برنامه های Angular را روی سرور رندر کنید که مشکلات کلیدی CSR را حل می کند:

  • بارگذاری اولیه صفحه را با ارسال HTML از پیش رندر شده بهبود می بخشد.
  • سئو را با ارائه ربات های جستجوگر با محتوای کامل افزایش می دهد.
  • عملکرد را در دستگاه های تلفن همراه و شبکه هایی با اتصالات کند بهبود می بخشد.

تمرین کنید

همه چیز در کلمات جالب به نظر می رسد، بیایید سعی کنیم آن را بررسی کنیم.

ابتدا باید به آنچه که برنامه بدون SSR ارائه می دهد نگاه کنید. برای انجام این کار، باید یک پروژه “خالی” ایجاد کنید.

در اینجا و بیشتر، کد را می توان به طور کامل در کنسول درج کرد

# проверяем, что у нас установлен Angular CLI
npm install -g @angular/cli
# создаем наш демо проект
ng new no-ssr-demo
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ممکن است از ما خواسته شود که پارامترهای لازم را انتخاب کنیم، همه جا کلیک کنید enter

در کنسول باید این خروجی را ببینیم

✔ Packages installed successfully.
    Successfully initialized git.
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر همه چیز موفقیت آمیز بود، به پروژه بروید و آن را راه اندازی کنید

cd no-ssr-demo/
npm start
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خروجی باید به این شکل باشد

توضیحات تصویر

اما بیایید ببینیم مرورگر وقتی برای اولین بار به سایت ما دسترسی پیدا می کند چه چیزی را دریافت می کند، برای این کار از آن استفاده خواهیم کرد curl. اگر اهل ویندوز هستید فقط به آدرس مراجعه کنید view-source:http://localhost:4200/. نتیجه مشابه خواهد بود

# Важно! ваш сайт может быть запушен на другом порту, если это так, просто замените 4200 на ваш порт
curl localhost:4200
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چه نتیجه ای گرفتیم؟

  

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا