Репозиторий с Angular CLI и Angular Universal
Переводы:
Ресурсы:
- публичный чат https://t.me/angular_universal_ru
- https://ssr.angular.su/ - серверный рендеринг master
- https://csr.angular.su/ - клиенский рендеринг master
- Angular 5
-
document is not defined
иwindow is not defined
- тут - Angular Material2 UI компоненты - отдельная ветка
- Primeng UI компоненты - отдельная ветка
- импорт модулей в зависимости от платформы (
MockServerBrowserModule
) - выполнение запросов к api на сервере
TransferHttp
- работа с Cookies на сервере
UniversalStorage
- Uses ngx-meta для SEO (title, meta tags, and Open Graph tags for social sharing).
- используется ngx-translate для поддержки интернационализации (i18n)
- используется ORIGIN_URL - для абсолютных запросов
- @angular/service-worker(
ng add @angular/pwa --project universal-demo
) - Ionic - необходимо собрать веб версию, пока есть проблемы отдельная ветка
yarn
илиnpm install
yarn start
илиnpm run start
- для клиенского рендерингаyarn ssr
илиnpm run ssr
- для серверного рендерингаyarn build:universal
илиnpm run build:universal
- для сборки в релизyarn server
илиnpm run server
- для запуска сервераyarn build:prerender
илиnpm run build:prerender
- для генерации статики поstatic.paths.ts
- для запуска отслеживания изменения кода при ssr запустите:
npm run ssr:cw
- сборка clientnpm run ssr:sw
- сборка servernpm run ssr:webpack
-сборкаserver.js
npm run ssr:server
- server с watch
Для переноса ssr в свой репозиторий вам необходимы файлы:
- .angular-cli.json
- server.ts
- prerender.ts
- webpack.config.js
- main.server.ts
- main.browser.ts
- shared/*
- forStorage/*
- environments/*
- app.browser.module.ts
- app.server.module.ts
Официальный пример на анлийиском: https://github.com/angular/universal-starter Модули используемые для universal:
- https://github.com/angular/universal/tree/master/modules/aspnetcore-engine -движок для .net core
- https://github.com/angular/universal/tree/master/modules/common - TransferHttpCacheModule, на данный момент мной не используется, если знаете куда и зачем его встаить - напишите мне или в issue, pull request
- https://github.com/angular/universal/tree/master/modules/express-engine - Express Engine для запуска рендеринга в node, в нашем приложении используется. Обратите внимание, что актуальная версия не ниже 5.0.0-beta.5
- https://github.com/angular/universal/tree/master/modules/hapi-engine - Hapi Engine альтернативный движок для рендеринга. В примере не используется, принципиально в схеме подключения не отличается от express-engine
- https://github.com/angular/universal/tree/master/modules/module-map-ngfactory-loader - модуль поиска модулей для LazyLoading - вещь нужная и используемая. Обратите внимание, что актуальная версия не ниже 5.0.0-beta.5
- модуль для TransferHttp использует
import { TransferState } from '@angular/platform-browser';
и необходим для реализации запроса rest api на сервере и остутствия повторного запроса второй раз. Смотритеhome.component.ts
(задержка 3с)
this.http.get('https://reqres.in/api/users?delay=3').subscribe(result => {
this.result = result;
});
-
export const AppRoutes = RouterModule.forRoot(routes, { initialNavigation: 'enabled' });
- чтобы не было мигания страницы! -
для работы с куками написан
AppStorage
, которыйй при помощи DI позволяет отдавать разную реализацию для сервера и бразуера. Смотритеserver.storage.ts
иbrowser.storage.ts
по реализациям. Вserver.ts
есть
providers: [
{
provide: REQUEST, useValue: (req)
},
{
provide: RESPONSE, useValue: (res)
}
]
для работы с REQUEST и RESPONSE через DI - это необходимо для реализации UniversalStorage при работе с cookies.
- webpack.config.js прописан исключительно для сборки файла server.ts в server.js, так как angular-cli имеет баг для работы с 3d зависимостями.
- для решения части проблем используется следущий код в
server.ts
Решение проблем глобавльных переменных, в том числе document is not defined
и window is not defined
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.join(__dirname, '.', 'dist', 'index.html')).toString();
const win = domino.createWindow(template);
const files = fs.readdirSync(`${process.cwd()}/dist-server`);
const styleFiles = files.filter(file => file.startsWith('styles'));
const hashStyle = styleFiles[0].split('.')[1];
const style = fs.readFileSync(path.join(__dirname, '.', 'dist-server', `styles.${hashStyle}.bundle.css`)).toString();
global['window'] = win;
Object.defineProperty(win.document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true
};
},
});
global['document'] = win.document;
global['CSS'] = style;
// global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
global['Prism'] = null;
global['navigator'] = req['headers']['user-agent'];
это позволяет убрать часть проблем при работе с undefined
.