Міжзастосункові зв’язки зі Single-Spa та RxJS

11 хв. читання
Міжзастосункові зв’язки зі Single-Spa та RxJS

Сьогодні розглянемо, як організувати взаємодію мікрофронтенду (компонентний зв'язок) із RxJ. Ми також застосуємо стратегію кодового доступу, як-от підмодулі Git, щоб зберегти єдине джерело та легко ділитися основною кодовою базою між застосунками. Робитимемо все максимально просто, щоб зосередитись більше на базових концепціях та практиці.

Задум нашого проєкту — створити застосунок Todo, у якому користувачі вводитимуть текст, натискатимуть «Додати» і цей пункт з'являтиметься у списку завдань. Користувачі також зможуть видаляти елементи кнопкою «Закрити».

Загалом ми розглянемо чотири проєкти:

  • Todo-Core (TypeScript);

  • Todo (Single-Spa);

  • Todo-Form (Angular);

  • Todo-List (React).

Міжзастосункові зв’язки зі Single-Spa та RxJS
Міжзастосункові зв’язки зі Single-Spa та RxJS

Todo-Core (підмодулі Git)

Ключовий модуль застосовуватиметься у всіх застосунках і матиме всю основну логіку із загальними моделями та службами. Крім того, він буде використовуватися як підмодуль Git.

Примітка: Замість підмодулів Git можна користуватися пакунками node як стратегією створення спільного коду, це може бути навіть простіше.

1. Створіть репозиторій з назвою todo-core (може містити README.md).

2. Клонуйте свій репозиторій:

git clone http://github.com/your_username/todo-core.git

3. Перейдіть до проєкту:

cd todo-core

4. Ініціалізуйте проєкт Node:

npm init --yes

5. Установіть бібліотеку rxjs:

npm install rxjs

6. Ініціалізуйте проєкт TypeScript:

tsc --init

7. Оновіть tsconfig.json:

{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

8. Додайте .gitignore:

node_modules

9. Додайте src/base.service.ts:

import { BehaviorSubject } from "rxjs";

export abstract class BaseService {
  abstract list$: BehaviorSubject<string[]>;
  abstract addTodo(todo: string): void;
  abstract removeTodo(index: number): void;
}

10. Додайте src/base.service.impl.ts:

import { BehaviorSubject } from "rxjs";

import { BaseService } from "./base.service";

export const BaseServiceImpl: BaseService = Object.freeze({
  list$: new BehaviorSubject<string[]>([]),
  addTodo(todo: string): void {
    this.list$.next([...this.list$.getValue(), todo]);
  },
  removeTodo(todoIndex: number): void {
    const updatedList = this.list$
      .getValue()
      .filter((el, index) => index !== todoIndex);
\t\t\t
\t\t\tthis.list$.next(updatedList);
  },
});

11. Додайте src/index.ts:

export * from "./base.service";
export * from "./base.service.impl";

12. Закомітьте та надішліть зміни до віддаленого репозиторію:

git add .
git commit -m "Core project setup"
git push
Міжзастосункові зв’язки зі Single-Spa та RxJS

Todo (макет застосунку Single-Spa)

Цей проєкт буде відповідати за структуру фреймворку та макет вмісту.

1. Створіть теку проєкту та перейдіть до неї:

mkdir todo && cd todo

2. Ініціалізуйте макет проєкту Single-Spa:

create-single-spa --layout

та виберіть:

  • Directory for new project — .

  • Select type to generate — single-spa root config

  • Which package manager do you want to use? — npm

  • Will this project use TypeScript — y

  • Organization name — obaranovskyi

3. Встановіть залежності:

npm install

4. Відкрийте src/microfrontend-layout.html та вилучіть цей рядок:

<application name="@single-spa/welcome"></application>

5. Відкрийте src/index.ejs та вилучіть цей рядок:

"@single-spa/welcome": "https://unpkg.com/single-spa-welcome/dist/single-spa-welcome.js",
Міжзастосункові зв’язки зі Single-Spa та RxJS

Вбудовування підмодулів:

6. Додайте todo-core підмодулем Git:

git submodule add https://github.com/your_user/todo-core.git

7. Додайте src/externals.ts:

export * from "../todo-core/src/index";

8. Оновіть src/obaranovskyi-root-config.ts:

import { BaseServiceImpl } from "./externals";

// ...

window["todoCore"] = BaseServiceImpl;

9. Запустіть проєкт:

npm start
Міжзастосункові зв’язки зі Single-Spa та RxJS

Застосунок Todo-Form (Angular)

У цьому проєкті ми створимо todo-форму з кнопкою надсилання.

1. Створіть застосунок Angular за допомогою Angular CLI

ng new todo-form

та виберіть:

  • Do you want to enforce stricter type checking and stricter bundle budgets in the workspace? — y

  • Would you like to add angular routing? — n

  • Which stylesheet format would you like to use? — SCSS

2. Перейдіть до проєкту й установіть залежності:

cd todo-form && npm install

3. Установіть Single-Spa:

ng add single-spa-angular

та виберіть:

  • Does your application use angular routing? — n

  • Does your application use the browserAnimationModule — n

Міжзастосункові зв’язки зі Single-Spa та RxJS

Вбудовування підмодулів:

4. Додайте todo-core підмодулем Git:

git submodule add https://github.com/your_user/todo-core.git

5. Додайте paths з мапінгом todo-core до tsconfig.json:

{
  "compilerOptions": {
    ...
    "baseUrl": "./",
    "paths": {
      "@todo-core/*": ["./todo-core/src/*"]
    }
  },
  ...
}

Примітка: baseUrl обов'язково має бути на своєму місці.

6. Оновіть src/app/app.module.ts:

import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';

import { BaseService } from '@todo-core/base.service';
import { AppComponent } from './app.component';
import { TodoFormComponent } from './todo-form/todo-form.component';

@NgModule({
  declarations: [AppComponent, TodoFormComponent],
  imports: [BrowserModule, FormsModule],
  providers: [{ provide: BaseService, useValue: (window as any).todoCore }],
  bootstrap: [AppComponent],
})
export class AppModule {}

7. Оновіть src/app/app.component.html:

<app-todo-form></app-todo-form>

Реалізація компонента Todo-форми

8. Згенеруйте компонент todo-form:

ng generate component todo-form

9. Оновіть src/app/todo-form/todo-form.component.html:

<div class="todo-form">
    <div class="todo-form-container">
        <input type="text" [(ngModel)]="todo" placeholder="Enter text
..." class="todo-form-input">
        <button (click)="addTodo()" class="todo-form-submit">Add</button>
    </div>
</div>

10. Оновіть src/app/todo-form/todo-form.component.ts:

import { Component } from '@angular/core';

import { BaseService } from '@todo-core/base.service';

@Component({
  selector: 'app-todo-form',
  templateUrl: './todo-form.component.html',
  styleUrls: ['./todo-form.component.scss'],
})
export class TodoFormComponent {
  todo!: string;

constructor(private readonly baseService: BaseService) {}

addTodo(): void {
    if (!this.todo) {
      return;
    }

this.baseService.addTodo(this.todo);
    this.todo = '';
  }
}

11. Оновіть src/app/todo-form/todo-form.component.scss:

.todo-form {
    position: relative;
    left: calc(50% - 250px);
    top: 200px;
\t\t
\t\t&-input {
        width: 500px;
        padding: 11px 20px;
        margin: 8px 0;
        display: inline-block;
        border: 1px solid #ccc;
        box-sizing: border-box;
    }
\t\t
\t\t&-submit {
        background-color: crimson;
        border: none;
        color: white;
        padding: 10px 40px;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 16px;
        margin-left: 15px;
    }
}

12. Установіть залежності:

npm install

13. Запустіть проєкт:

npm run serve:single-spa:todo-form
Міжзастосункові зв’язки зі Single-Spa та RxJS

Оновлення проєкту Todo:

14. Включіть бібліотеку zone.js до src/index.ejs:

<script src="https://unpkg.com/zone.js"></script>

15. Оновіть імпорт асоціативного масиву (map) SystemJS у src/index.ejs:

<script type="systemjs-importmap">
    {
      "imports": {
        "@obaranovskyi/root-config": "//localhost:9000/obaranovskyi-root-config.js",
        "@obaranovskyi/todo-form": "//localhost:4200/main.js"
      }
    }
  </script>

16. Зареєструйте застосунок у src/obaranovskyi-root-config.ts:

registerApplication(
  "@obaranovskyi/todo-form",
  () => System.import("@obaranovskyi/todo-form"),
  (location) => true
);
Міжзастосункові зв’язки зі Single-Spa та RxJS

Todo List (React)

У цьому проєкті ми створимо список завдань із функціональністю вилучення елементів.

1. Створіть теку проєкту та перейдіть до неї:

mkdir todo-list && cd todo-list

2. Встановіть проєкт Single-Spa/React:

create-single-spa --framework react

та виберіть:

  • Directory for new project — .

  • Which package manager do you want to use? — npm

  • Will this project use TypeScript — y

  • Organization name — obaranovskyi

  • Project name — todo-list

3. Встановіть залежності:

npm install

4. Встановіть бібліотеку rxjs:

npm install rxjs
Міжзастосункові зв’язки зі Single-Spa та RxJS

Вбудовування підмодулів:

5. Додайте todo-core підмодулем Git:

git submodule add https://github.com/your_user/todo-core.git

6. Додайте src/externals.ts:

import { BaseService } from "../todo-core/src/base.service";

export const baseService: BaseService = (window as any).todoCore as BaseService;
export * from "../todo-core/src/index";

7. Додайте src/TodoList.tsx:

import React from "react";
import { Subject, takeUntil } from "rxjs";
import { baseService } from "./externals";
import "./TodoList.css";

export interface IProps {}
export interface IState {
  todos: string[];
}

export class TodoList extends React.Component<IProps, IState> {
  destroy$: Subject<void> = new Subject<void>();

constructor(props) {
    super(props);
    this.state = { todos: [] };
  }
\t
\tcomponentDidMount(): void {
    this.observeTodos();
  }
\t
\tobserveTodos(): void {
    baseService.list$
      .pipe(takeUntil(this.destroy$))
      .subscribe((list: string[]) => {
        this.setState({ todos: list });
      });
  }
\t
\tcomponentWillUnmount(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
\t
\tremoveTodo = (index: number) => {
    baseService.removeTodo(index);
  };
\t
\trender() {
    return (
      <div className="main">
        <div className="container">
          <div className="total">Total: {this.state.todos.length}</div>
          <div className="list">
            <ol>
              {this.state.todos.map((todo: string, index: number) => (
                <li key={index}>
                  {todo}{" "}
                  <span
                    role="button"
                    tabIndex={0}
                    className="close"
                    onClick={() => this.removeTodo(index)}
                  >
                    [x]
                  </span>
                </li>
              ))}
            </ol>
          </div>
        </div>
      </div>
    );
  }
}

8. Додайте src/TodoList.css:

.main {
  font-family: sans-serif;
  position: relative;
  top: 200px;
  left: calc(50% - 250px);
}

.container {
  max-width: 1000px;
}

.total {
  text-decoration: underline;
}
.close {
  cursor: pointer;
  color: red;
}

9. Оновіть root.component.tsx:

import { TodoList } from "./TodoList";

export default function Root(props) {
  return <TodoList />;
}

10. Запустіть проєкт:

npm start -- --port 8500
Міжзастосункові зв’язки зі Single-Spa та RxJS

Todo project updates:

11. Оновіть src/index.ejs:

<script type="systemjs-importmap">
    {
      "imports": {
        "react": "https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.production.min.js",
        "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.production.min.js",
        "@obaranovskyi/todo-list": "//localhost:8500/obaranovskyi-todo-list.js",
        "@obaranovskyi/root-config": "//localhost:9000/obaranovskyi-root-config.js",
        "@obaranovskyi/todo-form": "//localhost:4200/main.js"
      }
    }
  </script>

12. Зареєструйте застосунок у src/obaranovskyi-root-config.ts:

registerApplication(
  "@obaranovskyi/todo-list",
  () => System.import("@obaranovskyi/todo-list"),
  (location) => true
);

Тепер усе повинно працювати чудово! :)

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.8K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація