Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From monolith web app to micro-frontends

From monolith web app to micro-frontends

Single-Page Application (SPA) is the main-stream modern frontend development approach. However, we quickly hit limitations of monolith SPA in the growing company with multiple product teams, different technologies and release cycles. In this talk we share how these limitations have been overcome by extending microservice architecture to React frontend using dependency injection and Lerna mono-repository.

4ec747b1a9752af99cc37bb2d263896d?s=128

Rustam Aliyev

July 08, 2018
Tweet

More Decks by Rustam Aliyev

Other Decks in Programming

Transcript

  1. From monolith SPA to micro-frontends How we extended microservices architecture

    to frontend Rustam Aliyev @rstml Ivan Martynov @j_martyn 07/07/2018 OneDome
  2. What is ”microservice”? • Architectural pattern • Collection of loosely

    coupled services
  3. Application (PHP, Ruby, etc.) Database

  4. Frontend (SPA) API Backend Database XHR

  5. Conway’s Law Produced system design copies organisational structure M. Conway,

    1967
  6. Frontend (SPA) API Gateway (REST, GraphQL) Backend Database Microservice A

    Team A Backend Database Microservice B Team B Backend Database Microservice N Team N …
  7. Problems of monolith SPA • Ownership ! • Dependency management

    " • Shared components # • Deployment and releases $ • A/B testing %
  8. … Backend Database Microservice A Team A Frontend Backend Database

    Microservice B Team B Frontend Backend Database Microservice N Team N Frontend … API Gateway (REST, GraphQL)
  9. Decoupling Monolith

  10. Typical SPA Anatomy • One entry point (index.js) • SPA

    framework • All components in one bundle ... <script src="https://unpkg.com/react/dist/react.js"></script> <script src="/index.js"></script> ...
  11. Complex monolith SPA • All-in-one SPA bundle • Package per

    product with custom routings • Shared components in separate packages index.js … App A Package App B Package App N Package Shared Components Package(s)
  12. Ways to decompose monolith frontend 1. Strong isolation Web Components

    / IFrame Multiple SPAs / frameworks Communication channels 2. Weak isolation Dependency Injection Single SPA / framework Shared state store
  13. … App A Package Team A App B Package Team

    B App N Package Team N Browser Runtime Dependency Injection Shared Components Package ver.A Shared Components Package ver.B Shared Components Package ver.N Thin SPA (injector) Shared Store (Redux, MobX)
  14. /* app/package.json */ { "dependencies" : { "dependency" : "1.0.0"

    } } /* app.js */ import dependency from 'dependency'; ... dependency.use(); /* index.html */ <script src="/dependency.v1.0.0.js"></script> <script src="/app.v2.0.0.js"></script> <script src="/thin-spa.js"></script> /* app.js */ export default (dependency) => { dependency.use(); } /* thin-spa.js (injector) */ import app from 'app'; import dependency from 'dependency'; ... app(dependency); // wiring Importing vs Dependency Injection
  15. Organising projects

  16. Before: project structure Package Thin SPA Package App A Package

    App B Package Shared Component … Package App N
  17. Before: Local development workflow 1. Manual symlink or npm link

    to test 2. Publish components to NPM 3. Deploy whole app cd ~/components npm link cd ~/application npm link components
  18. Monorepo • A single repository holding the code of many

    packages • Monorepo ≠ monolith Thin SPA Package App A Package App B Package Shared Components Package … App N Package Monorepo Shared Components Package
  19. Lerna • Tool for managing monorepo • Inter-dependency management •

    Publishing • Testing • CLI: bootstrap, publish, etc. • yarn optimised lerna-repo ├─ package.json ├─ lerna.json └─ packages ├─ main-spa │ └─ package.json ├─ design-lib │ └─ package.json ├─ app-a │ └─ package.json └─ app-b ├─ package.json └─ node_modules ├─ design-lib -> ../../design-lib ├─ ...
  20. Lerna • Tool for managing monorepo • Inter-dependency management •

    Publishing • Testing • CLI: bootstrap, publish, etc. • yarn optimised /* lerna.json */ { "lerna": "2.5.1", "npmClient": "yarn", "useWorkspaces": true, // yarn workspaces "version": "independent" } /* package.json */ { // yarn workspaces configuration "workspaces": [ "packages/*" ], "private": true }
  21. Lerna: Local development workflow • Automatically interlinking • Inter-dependencies and

    downstream versions • Automated testing lerna bootstrap # All packages are symlinked now git commit -a -m "Many changes" lerna publish # Changes: # - app-A: 1.0.1 => 1.0.2 # - app-B: 1.2.1 => 1.3.0 # - utils: 1.5.4 => 1.5.5 # - components: 3.0.4 => 3.0.5
  22. Deployment

  23. A … B N … A … B 1 N

    B 2 Monorepo (e.g. Git) Web Server Build, test, deploy Applications Shared components Micro-frontends Thin SPA
  24. Results Same bundle size Migrated gradually in background ~1 month

  25. Summary Before After Ownership ! " Dependency management # $

    Shared components % & Deployment and releases ' ( A/B testing ) *
  26. Future work • Applying Web Components • Communication between modules

    via event bus • Bolt as an alternative to Lerna • Hierarchical dependency injection
  27. Questions?