Основным преимуществом Angular 2+ был рендеринг на стороне сервера, но поверьте мне, это намного сложнее, чем кажется.
Универсальный проект Angular содержит ошибки, в нем отсутствует документация и он несовместим с большинством плагинов. Дело в том, что при создании AOT-сборок контекст браузера `window` или` document` отсутствует. Следовательно, любые плагины, использующие это, не будут работать для рендеринга на стороне сервера.
Я был разочарован этим и придумал другое решение.
Весь смысл предварительного рендеринга или рендеринга на стороне сервера заключается в передаче скомпилированного исходного кода HTML поисковым системам или любому, кто от него зависит. Многие поисковые системы и социальные сети имеют своих пользовательских агентов, которые отправляют запросы на ваш сайт с просьбой предоставить исходный код. Если ваш веб-сайт является SPA (одностраничным приложением), только исходный код, который вы отправляете, находится внутри `index.html`, что плохо. Все представления создаются динамически в клиентском браузере, но, поскольку поисковые системы не являются браузерами и не компилируют JavaScript должным образом, они ожидают скомпилированного исходного кода.
Теперь для нормальной публики, какой исходный код они получают, потому что все будет делать их браузер. Поэтому нам нужно отфильтровать публикацию и движки, а затем придумать некоторые механизмы, позволяющие по-разному обрабатывать их запросы. Возможно серверная динамическая версия для публичной и статическая (скомпилированная на сервере) для движков.
Для публики мы будем обслуживать файлы, созданные Angular CLI, в папке dist.
Для движков мы перенаправим запрос на сервер node.js, который обработает запрос в phantom.js, который является безголовым браузером с движком JavaScript, и вернет сгенерированный им исходный HTML-код.
Я использую nginx как статический файловый сервер и обратный прокси. Я рекомендую вам использовать ту же самую альтернативную конфигурацию, основанную на приведенной ниже логике.
#/etc/nginx/conf.d/website.conf server { listen 80; server_name website.com www.website.com; index index.html index.htm; root /usr/share/nginx/website/dist; location / { add_header Access-Control-Allow-Origin "*"; try_files $uri @prerender; } location @prerender { set $prerender 0; if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot|woff2)") { set $prerender 0; } # redirection if ($prerender = 1) { rewrite .* /http://localhost:8080$request_uri? break; proxy_pass http://127.0.0.1:3000; } if ($prerender = 0) { rewrite .* /index.html break; } } } server { listen 8080; server_name localhost; index index.html index.htm; root /usr/share/nginx/website/dist; location / { try_files $uri$args $uri$args/ /index.html; } }
Мы запускаем дополнительный сервер 8080, чтобы возвращать только динамическую версию.
Нам известны пользовательские агенты, используемые общими движками, с помощью которых мы можем определить, кто является общедоступным, а кто движком. Все статические файлы типа (js | css | xml | less | png |…) разрешаются прямо рядом с блоком try_files $ uri.
Когда движок с любым из вышеперечисленных пользовательских агентов отправляет запрос на website.com, этот запрос будет перенаправлен на `« http://127.0.0.1:3000 женщина/xxxx. `. Здесь следует помнить, что при перенаправлении полный URL-адрес будет иметь вид «http://127.0.0.1:3000/ http: // localhost: 8080 / signin `для URL-адреса запроса из` http://website.com/signin `.
Но когда публичный (один без вышеуказанных пользовательских агентов) отправляет запрос, мы отправим им обычную динамическую версию.
Теперь нам нужно создать сервер узла для обработки приложения Angular в phantom js.
// index.js const express = require(‘express’); const app = express(); const phantom = require(‘phantom’); const sleep = require(‘sleep-promise’); app.use((req, res, next) => { (async function(){ const instance = await phantom.create( [‘ — load-images=no’] ); const page = await instance.createPage(); await page.on(‘onResourceRequested’, (requestData) => console.log(‘Requesting: ‘, requestData.url)); await page.on(‘onError’, err => console.log(‘Error: ‘, err)); const status = await page.open(req.originalUrl.slice(1)); await sleep(5000); // wait 5 seconds to render HTML const content = await page.property(‘content’); await instance.exit(); // send response res.send(content); })(); }); // run app on port 3000 app.listen(3000, () => { console.log(‘Prerender listening app on port 3000!’); });
Выше приведен простой скрипт node.js для запуска экспресс-сервера, который может обрабатывать входящий запрос в phantom.js через порт 3000.
Кеш
Используйте модуль узла apicache для кеширования ответа.
const apiCache = require(‘apicache’); let cache = apiCache.middleware; app.use(cache('1 week'));
Контрольная работа
Чтобы проверить это, просто откройте свой инструмент разработчика Chrome и нажмите на три вертикальные точки в правом верхнем углу. Выберите дополнительные инструменты и условия сети. В раскрывающемся списке агента пользователя выберите бот Google. Теперь, когда вы запросите http: // website.com, вы получите скомпилированный исходный код. Также проверьте view-`source: http: // website .com`