|
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