| Пятница, 13 октября, 2017
Метки: Angular, TypeScript, SEO Комментарии: 3
Одностраничный сайт разработан. Открыт в общем доступе. Но как его продвигать? SEO (Search Engine Optimization) продвижение становится очень затруднительным из-за того, что другие сайты, социальные сети и поисковые системы не видят содержимое вашего сайта, так как оно генерируется в браузерах пользователей, а данные для них подгружаются ajax-запросами. Решаем эту проблему и делаем наш одностраничник информативным для других сайтов с помощью Angular Universal.
Библиотеки для разработки одностраничных приложений все больше и больше завоевывают внимание JavaScript-программистов по всему миру. Такие приложения работают непосредственно в браузере, генерируют содержимое страницы прямо на клиенте, выполняют навигацию и переключение страниц затрагивая сервер только для получения данных, и при этом нагружают сервер и сеть по минимуму. Кроме того, такие приложения обеспечивают прекрасную скорость работы, а также быстрые и удобные интерфейсы для взаимодействия с пользователем. Но есть один недостаток, приложение должно быть проиндексировано поисковыми машинами.
Многие поисковые сайты и социальные сети такие как Facebook и Twitter ожидают чистый HTML для вычитывания из него мета тегов и текстов страниц. Они не могут определить, когда Javascript закончит генерацию страницы и поэтому не получают ценной информации, а всего лишь малый набор тегов. Хотя такие монстры как Google хорошо генерируют страницы динамических сайтов, читают их и индексируют, но пользователи все равно впадают с ступор при попытке поделится ссылкой в социальной сети.
И для этого нужен сервер, который будет выдавать готовый HTML-код. Нам нужно, чтобы поисковые машины, социальные сети и просто пользователи приложения видели страницы, сгенерированные уже на сервере, так как это 100% гарантированный способ доставки содержимого любому клиенту. В этом нам поможет Angular Universal.
Официальный сайт (universal.angular.io) заявляет, что Angular Universal — это рендеринг приложений Angular 2+ на серверной стороне. Фактически это промежуточное приложение (middleware) между node.js и Angular, которое связывает все лучшие качества одностраничных приложений (взаимодействие с пользователем, быстродействие) и статичных сайтов, которые прекрасно дружат с поисковой оптимизацией.
Внимание, для повтора всех шагов, описанных в статье, убедитесь, что у вас глобально установлены версии не ниже (тестировалось, именно с этими с версиями): node.js (v6.9.2), npm (3.10.5), Angular CLI 1.4.4. Проверить версии можно командами соответственно: node -v, npm -v, ng -v. Данная утилита Angular CLI 1.4.4 соберет вам проект с Angular 4.2.x. Если Angular CLI установлен ниже, то переустановите его во избежание нестыковок и возможных проблем.
Angular CLl на момент написания статьи распространяется с именем @angular/cli вместо anguar-cli. Переустановка пакета состоит из трех шагов:
Теперь у нас все готово для сборки обычного Angular-проекта. Создаем обычный проект с помощью команды ng new angular-universal-demo. Более подробно с созданием и запуском проекта на Angular 4 можно тут. По завершении создания запускаем этот проект. В браузере открываем просмотр кода страницы и видим в теле документа body пустой тег app-root, в котором Angular генерирует содержимое страницы.
BrowserModule.withServerTransition({appId: 'my-app'})
AppId можем назначить любое.
import {NgModule} from '@angular/core';
import {ServerModule} from '@angular/platform-server';
import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader';
import {AppModule} from './app.module';
import {AppComponent} from './app.component';
@NgModule({
imports: [
// В AppServerModule должен быть импортирован AppModule
// вместе с ServerModule из @angular/platform-server.
AppModule,
ServerModule,
ModuleMapLoaderModule,
],
// Так как главный загрузочный компонент не наследуется из
// AppModule, то тут тут мы повторяем его подключение.
bootstrap: [AppComponent],
})
export class AppServerModule {}
Здесь мы используем два новых модуля поэтому подключим их:
import { environment } from './environments/environment';
import { enableProdMode } from '@angular/core';
if (environment.production) {
enableProdMode();
}
export {AppServerModule} from './app/app.server.module';
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
// Изменяем формат модуля на "commonjs":
"module": "commonjs",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
],
// Добавляем "angularCompilerOptions" и указывает AppServerModule
// как входящий модуль "entryModule".
"angularCompilerOptions": {
"entryModule": "app/app.server.module#AppServerModule"
}
}
{
"platform": "server",
"root": "src",
"outDir": "dist/dist-server",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.server.ts",
"test": "test.ts",
"tsconfig": "tsconfig.server.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
require('zone.js/dist/zone-node');
require('reflect-metadata');
const express = require('express');
const { ngExpressEngine } = require('@nguniversal/express-engine');
// Import module map for lazy loading
const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader');
// Import the AOT compiled factory for your AppServerModule.
// This import will change with the hash of your built server bundle.
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require(`./dist-server/main.bundle`);
const app = express();
const port = 8000;
const baseUrl = `http://localhost:${port}`;
// Set the engine
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
app.set('view engine', 'html');
app.set('views', './');
app.use('/', express.static('./', {index: false}));
app.get('*', (req, res) => {
res.render('index', {req, res});
});
app.listen(port, () => {
console.log(`Listening at ${baseUrl}`);
});
Две новые библиотеки нужно установить:"build:dynamic": "ng build --prod && ng build --prod --app 1 --output-hashing=false && cpy ./server.js ./dist", "serve:dynamic": "npm run build:dynamic && cd dist && node server"Установим npm install cpy-cli --save-dev.
Набираем команду npm run serve:dynamic, ждем выполнения. В логах мы увидим сборку двух приложений, так как в angular-cli.json мы прописали еще одно серверное. Открываем приложение в браузере. Мы увидим тоже самое, что мы видели запуская команду ng serve. Но посмотрим на исходный код страницы в браузере.
Мы увидим совсем другую картину. Сейчас мы видим внутри тега app-root разметку и тексты.
Это тот вид, которого мы добивались и который будут видеть поисковые системы и другие сайты. Серверный рендеринг открывает широкие перспективы для разработки сайтов программистами активно использующих Angular 4.
Пример проекта можно посмотреть тут https://github.com/ang4-examples/angular-universal-demo
Copyright © CodeHint.ru 2013-2025 (v2.4.7 - работает на Angular Universal)Калькулятор инвест-портфеля