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