Это продолжение статьи Гибридные мобильные приложения: совместное использование логики между приложениями Angular2 и Ionic2. В 2016 году это была наша первая попытка поделиться бизнес-логикой на основе Ngrx между приложением Angular2 и мобильным приложением Ionic2, но при этом использовался довольно нестабильный npm link
хак с тремя отдельными проектами npm Typescript.
С последними интерфейсами командной строки Angular8 и Ionic4 теперь есть очень элегантный способ добиться этого благодаря структуре проекта монорепо.
Цели остались прежними:
- инкапсулировать всю бизнес-логику (на основе @ ngrx / store) в основной модуль и
- сохраняйте конкретный макет представления, разметку и логику навигации в проектах мобильных и веб-приложений.
Примечание: @ ngrx / store - это управление состоянием на основе RxJS, вдохновленное Redux для приложений Angular. В настоящее время это самый популярный способ структурировать сложную бизнес-логику в приложениях Angular.
Демо-приложение и репозиторий на Github
Вот репо нашего доказательства концепции:
Репо использует структуру монорепозитория Nx Workspace (с настраиваемой интеграцией Ionic, подробно описанной позже):
- /, корень проекта на основе Angular (версия 8.1.2) и @ ngrx / store (версия 8.1.0), управляемый Angular CLI
- / libs / core, общий модуль с логикой состояния, редукторов и действий,
- / apps / web, веб-приложение.
- / apps / mobile, мобильное приложение на базе Ionic (версия 4.7.1), управляемое Ionic CLI
Для демонстрации мы используем пример кода счетчика (действия и редукторы) из @ ngrx / store.
Модуль core обеспечивает:
- CounterState интерфейс, модель состояния счетчика
- Редуктор counterReducer, управление состоянием счетчика на основе отправленных действий,
- Действия счетчика увеличения, уменьшения и сброса
В мобильном или веб-приложении мы используем эти активы для построения модели состояния приложения.
import {CounterState} from ‘@ngrx-demo/core’; export interface AppState { counter: CounterState, // Add other states here }
И предоставляйте действия, службы и редукторы во время начальной загрузки приложения.
import {ActionReducerMap} from '@ngrx/store'; import {counterReducer} from '@ngrx-demo/core'; import {AppState} from './app.state'; const reducers: ActionReducerMap<AppState> = { counter: counterReducer }; @NgModule({ imports: [ BrowserModule, StoreModule.forRoot(reducers) ] bootstrap: [ AppComponent ], declarations: [ AppComponent ], }) export class AppModule { }
Теперь мы можем использовать эти активы в любом компоненте представления приложения.
// HTML component template <h2> {{counter$ | async}} </h2> <p> <button (click)=”increment()”> +1 </button> <button (click)=”decrement()”> -1 </button> </p> <p> <button (click)=”reset()”> Reset </button> </p>
С соответствующим компонентом:
// Typescript angular component import {CounterActions} from '@ngrx-demo/core'; import {AppState} from './app.state'; @Component({ templateUrl: 'some.component.html' }) export class SomeComponent { counter$: Observable<number>; constructor(private store: Store<AppState>) { this.counter$ = this.store.select(s => s.counter.total); } decrement() { this.store.dispatch(new CounterActions.DecrementAction()); } increment() { this.store.dispatch(new CounterActions.IncrementAction()); } reset() { this.store.dispatch(new CounterActions.ResetAction()); } }
Вся бизнес-логика полностью заключена в общий модуль. Например, мы могли бы добавить в микс @ ngrx / effects, чтобы обрабатывать асинхронные вызовы API.
Представление «знает» только о доступных действиях для отправки и модели состояния, на которую оно может подписаться.
Интеграция приложения Ionic в рабочую область Nx
По умолчанию Nx Workspaces не поддерживает приложения Ionic. Поскольку Ionic использует собственный интерфейс командной строки и зависимости для создания, тестирования и запуска приложения, / app / mobile имеет собственный /app/mobile/package.json (который не зависит от из основного рабочего пространства /package.json), и поэтому он является собственным / app / mobile / node_modules.
Ионная настраиваемая конфигурация
В package.json Ionic предоставляет несколько хуков для настройки конфигурации по умолчанию. Мы используем параметры конфигурации ionic_watch и ionic_webpack и 2 пользовательских файла конфигурации, хранящихся в / app / mobile / config.
// app/mobile/package.json { ... "description": “An Ionic project”, "config": { "ionic_watch": "./config/watch.config.js", "ionic_webpack": "./config/webpack.config.js" }, ... }
Разрешение модуля машинописного текста
Чтобы иметь возможность использовать наши общие модули и получить правильное разрешение модуля Typescript, мы используем настраиваемое свойство сопоставления путей в /app/mobile/tsconfig.json. В нашем приложении мы используем @ ngrx-demo, но вы можете, например, использовать @local.
// app/mobile/tsconfig.json { "compilerOptions": { ... "baseUrl": ".", "paths": { "@ngrx-demo/*": ["../../libs/*"] } ... }
И TSConfig paths plugin webpack plugin в нашей настраиваемой конфигурации Webpack, чтобы Webpack знал об этих настраиваемых сопоставлениях путей.
// app/mobile/config/webpack.config.js const TsconfigPathsPlugin = require(‘tsconfig-paths-webpack-plugin’); const resolveConfig = { extensions: [‘.ts’, ‘.js’, ‘.json’], modules: [path.resolve(‘node_modules’)], plugins: [ new TsconfigPathsPlugin({}) ] }; // Default config update const webpackConfig = require(‘../node_modules/@ionic/app-scripts/config/webpack.config’); webpackConfig.dev.resolve = resolveConfig; webpackConfig.prod.resolve = resolveConfig;
Живая перезагрузка
Приятно иметь возможность получать выгоду от интерактивной перезагрузки во время разработки: при запуске ionic serve
, если файл обновляется в / libs / *, изменения обнаруживаются, и мобильное приложение автоматически перезагружается в вашем браузере. Для этого мы используем настраиваемую конфигурацию часов:
// app/mobile/config/watch.config.js // Default config update const watchConfig = require(‘../node_modules/@ionic/app-scripts/config/watch.config’); watchConfig.srcFiles.paths = [ ‘{{SRC}}/**/*.(ts|html|s(c|a)ss)’, ‘../../libs/**/*.(ts|html|s(c|a)ss)’ ];
Инструменты разработчика Ngrx Store
И, наконец, что не менее важно, во время разработки Ngrx Store Dev Tools необходимо для отладки вашего приложения, но он должен быть отключен в производственной среде. Для этого мы используем настраиваемые сопоставления путей @ app / env (чтобы имитировать переменные среды в приложениях Angular) благодаря https://github.com/gshigeto/ionic-environment-variables.
// app/mobile/tsconfig.json { "compilerOptions": { ... "baseUrl": ".", "paths": { "@app/env": ["src/environments/environment"], "@ngrx-demo/*": ["../../libs/*"] } ... }
С сопоставлением псевдонимов в нашей настраиваемой конфигурации Webpack.
// app/mobile/config/webpack/config.json ... webpackConfig.dev.resolve.alias = { "@app/env": path.resolve('../src/environments/environment.ts') }; webpackConfig.prod.resolve.alias = { "@app/env": path.resolve('../src/environments/environment.prod.ts') };
Затем мы можем просто импортировать переменные среды в наше приложение Ionic!
import {StoreModule} from '@ngrx/store'; import {StoreDevtoolsModule} from '@ngrx/store-devtools'; ... import {environment} from '@app/env'; @NgModule({ ... imports: [ BrowserModule, IonicModule.forRoot(AppComponent), DemoCoreModule, StoreModule.forRoot(reducers), EffectsModule.forRoot([]), !environment.production ? StoreDevtoolsModule.instrument({maxAge: 25}) : [] ], ... }) export class AppModule { }
Преимущества рабочего пространства и монорепо
Вот и все! Как видите, эта новая структура проекта намного чище, чем первоначальное решение 2016 года.
Он обладает всеми преимуществами, описанными в документации Nx Зачем нужна рабочая область (за исключением унифицированного управления зависимостями, поскольку приложение Ionic требует собственных зависимостей):
Единое управление версиями
Все в этом текущем коммите работает вместе
Ярлык или ветка могут фиксировать то же самое
Продвигает совместное использование и повторное использование кода
Легко разбить код на модули библиотеки
Легко использовать / внедрять этот код и последние изменения в нем.
Преимущества рефакторинга
Редакторы кода и IDE осведомлены о «рабочем пространстве»
Может иметь одну фиксацию для рефакторинга, охватывающего приложения в домене.
Единый опыт разработчика
Обеспечивает доступность всего необходимого зависимого кода
Если у вас есть какие-либо вопросы или предложения по улучшению демонстрационного приложения, не стесняйтесь отправлять вопрос или запрос на перенос!
Примечание: мы нанимаем! Вы обалденный fullstack или front-end разработчик, который хочет работать на Angular, Java или Groovy? Вы должны связаться со мной, чтобы присоединиться к команде нашей мечты в Париже!
Если вам понравилась эта статья, нажмите кнопку ❤, чтобы порекомендовать ее. Это поможет другим пользователям Medium это обнаружить.