|
5 | 5 | > Репозиторий с Angular CLI и Angular Universal
|
6 | 6 |
|
7 | 7 | **Переводы**:
|
| 8 | + |
8 | 9 | - [Русский](./README-RU.md)
|
9 | 10 | - [English](./README.md)
|
10 | 11 | - [Românesc](./README-RO.md)
|
11 | 12 |
|
12 | 13 | **Ресурсы**:
|
| 14 | + |
13 | 15 | - публичный чат https://t.me/angular_universal_ru
|
14 | 16 | - https://ssr.angular.su/ - серверный рендеринг master
|
15 | 17 | - https://csr.angular.su/ - клиенский рендеринг master
|
16 | 18 |
|
17 | 19 | # Планы:
|
18 |
| -- [x] Angular 7 |
| 20 | + |
| 21 | +- [x] Angular 11 |
19 | 22 | - [x] `document is not defined` и `window is not defined` - [тут](./defined.md)
|
20 | 23 | - [x] [Angular Material2](https://material.angular.io/) **UI компоненты** - [отдельная ветка](https://github.com/Angular-RU/angular-universal-starter/tree/material2)
|
21 | 24 | - [x] [Primeng](https://www.primefaces.org/primeng/) **UI компоненты** - [отдельная ветка](https://github.com/Angular-RU/angular-universal-starter/tree/primeng)
|
22 | 25 | - [x] импорт модулей в зависимости от платформы (`MockServerBrowserModule`)
|
23 | 26 | - [x] выполнение запросов к api на сервере `TransferHttp`
|
24 | 27 | - [x] работа с Cookies на сервере `UniversalStorage`
|
25 |
| -- [x] Uses **[ngx-meta](https://github.com/fulls1z3/ngx-meta)** для SEO (*title, meta tags, and Open Graph tags for social sharing*). |
| 28 | +- [x] Uses **[ngx-meta](https://github.com/fulls1z3/ngx-meta)** для SEO (_title, meta tags, and Open Graph tags for social sharing_). |
26 | 29 | - [x] используется ngx-translate для поддержки интернационализации (i18n)
|
27 | 30 | - [x] используется ORIGIN_URL - для абсолютных запросов
|
28 | 31 | - [x] @angular/service-worker(`ng add @angular/pwa --project universal-demo`)
|
29 | 32 |
|
30 | 33 | ## Как запустить
|
| 34 | + |
31 | 35 | - `yarn` или `npm install`
|
32 | 36 | - `yarn start` или `npm run start` - для клиенского рендеринга
|
33 |
| -- `yarn ssr` или `npm run ssr` - для серверного рендеринга |
| 37 | +- `yarn ssr` или `npm run ssr` - для серверного рендеринга |
34 | 38 | - `yarn build:universal` или `npm run build:universal` - для сборки в релиз
|
35 | 39 | - `yarn server` или `npm run server` - для запуска сервера
|
36 | 40 | - `yarn build:prerender` или `npm run build:prerender` - для генерации статики по `static.paths.ts`
|
37 | 41 | - для запуска отслеживания изменения кода при ssr запустите `npm run ssr:watch`
|
38 | 42 |
|
39 | 43 | ## Как использовать этот репозиторий в своем проекте:
|
| 44 | + |
40 | 45 | Для переноса ssr в свой репозиторий вам необходимы файлы:
|
41 |
| - - .angular-cli.json |
42 |
| - - server.ts |
43 |
| - - prerender.ts |
44 |
| - - webpack.config.js |
45 |
| - - main.server.ts |
46 |
| - - main.browser.ts |
47 |
| - - shared/* |
48 |
| - - forStorage/* |
49 |
| - - environments/* |
50 |
| - - app.browser.module.ts |
51 |
| - - app.server.module.ts |
| 46 | + |
| 47 | +- .angular-cli.json |
| 48 | +- server.ts |
| 49 | +- prerender.ts |
| 50 | +- webpack.config.js |
| 51 | +- main.server.ts |
| 52 | +- main.browser.ts |
| 53 | +- shared/\* |
| 54 | +- forStorage/\* |
| 55 | +- environments/\* |
| 56 | +- app.browser.module.ts |
| 57 | +- app.server.module.ts |
52 | 58 |
|
53 | 59 | ## Ссылки
|
54 |
| -Официальный пример на анлийиском: https://github.com/angular/universal-starter |
| 60 | + |
| 61 | +Официальный пример на анлийиском: https://github.com/angular/universal-starter |
55 | 62 | Модули используемые для universal:
|
| 63 | + |
56 | 64 | - https://github.com/angular/universal/tree/master/modules/aspnetcore-engine -движок для .net core
|
57 | 65 | - https://github.com/angular/universal/tree/master/modules/common - TransferHttpCacheModule для синхронизации запросов сервера и клиента
|
58 |
| -- https://github.com/angular/universal/tree/master/modules/express-engine - Express Engine для запуска рендеринга в node, в нашем приложении используется. Обратите внимание, что актуальная версия не ниже 5.0.0-beta.5 |
59 |
| -- https://github.com/angular/universal/tree/master/modules/hapi-engine - Hapi Engine альтернативный движок для рендеринга. В примере не используется, принципиально в схеме подключения не отличается от express-engine |
60 |
| -- https://github.com/angular/universal/tree/master/modules/module-map-ngfactory-loader - модуль поиска модулей для LazyLoading - вещь нужная и используемая. Обратите внимание, что актуальная версия не ниже 5.0.0-beta.5 |
| 66 | +- https://github.com/angular/universal/tree/master/modules/express-engine - Express Engine для запуска рендеринга в node, в нашем приложении используется. Обратите внимание, что актуальная версия не ниже 5.0.0-beta.5 |
| 67 | +- https://github.com/angular/universal/tree/master/modules/hapi-engine - Hapi Engine альтернативный движок для рендеринга. В примере не используется, принципиально в схеме подключения не отличается от express-engine |
| 68 | +- https://github.com/angular/universal/tree/master/modules/module-map-ngfactory-loader - модуль поиска модулей для LazyLoading - вещь нужная и используемая. Обратите внимание, что актуальная версия не ниже 5.0.0-beta.5 |
61 | 69 |
|
62 | 70 | ## Особенности(Важно)
|
63 |
| -- модуль для TransferHttp использует `import { TransferState } from '@angular/platform-browser';` и необходим для реализации запроса rest api на сервере и остутствия повторного запроса второй раз. Смотрите `home.component.ts` (задержка 3с) |
| 71 | + |
| 72 | +- модуль для TransferHttp использует `import { TransferState } from '@angular/platform-browser';` и необходим для реализации запроса rest api на сервере и остутствия повторного запроса второй раз. Смотрите `home.component.ts` (задержка 3с) |
64 | 73 |
|
65 | 74 | ```ts
|
66 |
| -this.http.get('https://reqres.in/api/users?delay=3').subscribe(result => { |
67 |
| - this.result = result; |
| 75 | +this.http.get('https://reqres.in/api/users?delay=3').subscribe((result) => { |
| 76 | + this.result = result; |
68 | 77 | });
|
69 | 78 | ```
|
70 |
| -- `export const AppRoutes = RouterModule.forRoot(routes, { initialNavigation: 'enabled' });` - чтобы не было мигания страницы! |
71 | 79 |
|
72 |
| -- для работы с куками написан `AppStorage`, который при помощи DI позволяет отдавать разную реализацию для сервера и бразуера. Смотрите `server.storage.ts` и `browser.storage.ts` по реализациям. В `server.ts` есть |
| 80 | +- `export const AppRoutes = RouterModule.forRoot(routes, { initialNavigation: 'enabled' });` - чтобы не было мигания страницы! |
| 81 | + |
| 82 | +- для работы с куками написан `AppStorage`, который при помощи DI позволяет отдавать разную реализацию для сервера и бразуера. Смотрите `server.storage.ts` и `browser.storage.ts` по реализациям. В `server.ts` есть |
| 83 | + |
73 | 84 | ```ts
|
74 | 85 | providers: [
|
75 |
| - { |
76 |
| - provide: REQUEST, useValue: (req) |
77 |
| - }, |
78 |
| - { |
79 |
| - provide: RESPONSE, useValue: (res) |
80 |
| - } |
81 |
| -] |
| 86 | + { |
| 87 | + provide: REQUEST, |
| 88 | + useValue: req, |
| 89 | + }, |
| 90 | + { |
| 91 | + provide: RESPONSE, |
| 92 | + useValue: res, |
| 93 | + }, |
| 94 | +]; |
82 | 95 | ```
|
83 |
| -для работы с REQUEST и RESPONSE через DI - это необходимо для реализации UniversalStorage при работе с cookies. |
84 | 96 |
|
85 |
| -- webpack.config.js прописан исключительно для сборки файла server.ts в server.js, так как angular-cli имеет [баг](https://github.com/angular/angular-cli/issues/7200) для работы с 3d зависимостями. |
| 97 | +для работы с REQUEST и RESPONSE через DI - это необходимо для реализации UniversalStorage при работе с cookies. |
| 98 | + |
| 99 | +- webpack.config.js прописан исключительно для сборки файла server.ts в server.js, так как angular-cli имеет [баг](https://github.com/angular/angular-cli/issues/7200) для работы с 3d зависимостями. |
86 | 100 | - для решения части проблем используется следущий код в `server.ts`
|
87 | 101 |
|
88 | 102 | Решение проблем глобальных переменных, в том числе `document is not defined` и `window is not defined`
|
89 |
| -```ts |
| 103 | + |
| 104 | +```````ts |
90 | 105 | const domino = require('domino');
|
91 | 106 | const fs = require('fs');
|
92 | 107 | const path = require('path');
|
93 | 108 | const template = fs.readFileSync(path.join(__dirname, '.', 'dist', 'index.html')).toString();
|
94 | 109 | const win = domino.createWindow(template);
|
95 | 110 | const files = fs.readdirSync(`${process.cwd()}/dist-server`);
|
96 |
| -const styleFiles = files.filter(file => file.startsWith('styles')); |
| 111 | +const styleFiles = files.filter((file) => file.startsWith('styles')); |
97 | 112 | const hashStyle = styleFiles[0].split('.')[1];
|
98 |
| -const style = fs.readFileSync(path.join(__dirname, '.', 'dist-server', `styles.${hashStyle}.bundle.css`)).toString(); |
| 113 | +const style = fs |
| 114 | + .readFileSync(path.join(__dirname, '.', 'dist-server', `styles.${hashStyle}.bundle.css`)) |
| 115 | + .toString(); |
99 | 116 |
|
100 | 117 | global['window'] = win;
|
101 | 118 | Object.defineProperty(win.document.body.style, 'transform', {
|
102 | 119 | value: () => {
|
103 | 120 | return {
|
104 | 121 | enumerable: true,
|
105 |
| - configurable: true |
| 122 | + configurable: true, |
106 | 123 | };
|
107 | 124 | },
|
108 | 125 | });
|
109 | 126 | global['document'] = win.document;
|
110 | 127 | global['CSS'] = style;
|
111 |
| -// global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest; |
112 | 128 | global['Prism'] = null;
|
113 |
| - |
114 |
| -``` |
115 |
| - |
116 |
| -```ts |
| 129 | +``````ts |
117 | 130 | global['navigator'] = req['headers']['user-agent'];
|
118 |
| -``` |
| 131 | +``````` |
| 132 | + |
119 | 133 | это позволяет убрать часть проблем при работе с `undefined`.
|
0 commit comments