Slide 1

Slide 1 text

@BASTAcon & @ManfredSteyer

Slide 2

Slide 2 text

@ManfredSteyer Typical Module Structure Page ▪ 3 AppModule … … … SharedModule Root Module Feature Modules Shared Modules SharedModule

Slide 3

Slide 3 text

@ManfredSteyer Contents • Monorepos • Strategic Design and DDD • Nx & Incremental Compilation • Microfrontends

Slide 4

Slide 4 text

@ManfredSteyer Manfred Steyer

Slide 5

Slide 5 text

@ManfredSteyer Monorepos

Slide 6

Slide 6 text

@ManfredSteyer Monorepo Structure

Slide 7

Slide 7 text

@ManfredSteyer Advantages Everyone uses the latest versions No version conflicts No burden with distributing libs

Slide 8

Slide 8 text

@ManfredSteyer Two Flavors • Like Workspaces/Solutions in different IDEs Project Monorepo • E. g. used at Google or Facebook Company-wide Monorepo

Slide 9

Slide 9 text

@ManfredSteyer Moving back and forth Npm Registry

Slide 10

Slide 10 text

@ManfredSteyer Tooling & Generator https://nrwl.io/nx

Slide 11

Slide 11 text

@ManfredSteyer Visualize Module Structure

Slide 12

Slide 12 text

@ManfredSteyer Further Selected Features of Nx • Restricting access b/w apps and libs • Just recompile changed apps • Parallel compilation in the cloud • Integration of tooling: Cypress, Playwright, Storybook, …

Slide 13

Slide 13 text

@ManfredSteyer Creating a Workspace npm install -g @angular/cli ng new workspace cd workspace ng generate app my-app ng generate lib my-lib ng serve --project my-app ng build --project my-app

Slide 14

Slide 14 text

@ManfredSteyer Creating a Workspace npm install -g @angular/cli npm init nx-workspace workspace cd workspace ng generate app my-app ng generate lib my-lib ng serve --project my-app ng build --project my-app

Slide 15

Slide 15 text

@ManfredSteyer DEMO

Slide 16

Slide 16 text

@ManfredSteyer DDD in a nutshell

Slide 17

Slide 17 text

@ManfredSteyer Methodology for bridging the gap b/w requirements and architecture/ design

Slide 18

Slide 18 text

@ManfredSteyer

Slide 19

Slide 19 text

@ManfredSteyer Domain Driven Design Strategic Design Tactical Design Decomposing a System Design Patterns & Practices

Slide 20

Slide 20 text

@ManfredSteyer Domain Driven Design Strategic Design Tactical Design Decomposing a System Design Patterns & Practices

Slide 21

Slide 21 text

@ManfredSteyer

Slide 22

Slide 22 text

@ManfredSteyer Example Flight System

Slide 23

Slide 23 text

@ManfredSteyer Booking Check-in Boarding Luggage Example Sub-Domains

Slide 24

Slide 24 text

@ManfredSteyer Finding Sub-Domains Book Flight Check-in Passenger Check-in Luggage Board Plane Pickup Luggage Passenger Travel Agency Check-in Agent Boarding Agent

Slide 25

Slide 25 text

@ManfredSteyer Booking Boarding Bounded Context Ubiquitous Language Flight Price Seats Passenger Tickets Flight Ticket

Slide 26

Slide 26 text

@ManfredSteyer Booking Luggage Boarding Check-in Context Map

Slide 27

Slide 27 text

@ManfredSteyer Booking Boarding Shared Feature Feature Feature Feature Feature UI UI UI UI UI UI UI UI UI Domain Domain Domain Domain Domain Domain Util Util Util Util Util Util Enterprise Monorepo Patterns, Nrwl 2018: https://tinyurl.com/y2jjxld7 @ManfredSteyer Shared Kernel (if really needed) & other libs Smart Comp. Dumb Comp.

Slide 28

Slide 28 text

@ManfredSteyer DEMO

Slide 29

Slide 29 text

@ManfredSteyer

Slide 30

Slide 30 text

@ManfredSteyer Finegrained Libraries • Units for dep graph • Unit of recompilation* • Unit of retesting • Access restrictions • Information Hiding • Easy: Just ng g lib …

Slide 31

Slide 31 text

@ManfredSteyer Restricting Access on a folder basis Rainer Hahnekamp, AngularArchitects @softarc/eslint-plugin-sheriff

Slide 32

Slide 32 text

@ManfredSteyer Micro Frontends? Short outlook

Slide 33

Slide 33 text

@ManfredSteyer Booking App Check-in App Boarding App Luggage App Microfrontends

Slide 34

Slide 34 text

@ManfredSteyer Shopping Card App Payment App Recommender App Shipping App Microfrontends

Slide 35

Slide 35 text

@ManfredSteyer

Slide 36

Slide 36 text

@ManfredSteyer Booking Boarding Shared Feature Feature Feature Feature Feature … … … … … … … … … @ManfredSteyer Flight App Deployment Monolith

Slide 37

Slide 37 text

@ManfredSteyer Booking Boarding Shared Feature Feature Feature Feature Feature … … … … … … … … … Booking App Boarding App Microfrontends

Slide 38

Slide 38 text

@ManfredSteyer Booking Boarding Shared Feature Feature Feature Feature Feature … … … … … … … … … Booking App Boarding App Option 1: One App per Domain Monorepo

Slide 39

Slide 39 text

@ManfredSteyer Booking Boarding Shared Feature Feature Feature Feature Feature … … … … … … … … … Booking App Boarding App Option 2: One Monorepo per Domain Publish shared libs seperately via npm Repository n Repository 2 Repository 1

Slide 40

Slide 40 text

@ManfredSteyer Benefits Autonomous Teams Separate Development Separate Deployment Own architecture decisions Own technology descisions

Slide 41

Slide 41 text

@ManfredSteyer Integration via Hyperlinks

Slide 42

Slide 42 text

@ManfredSteyer UI Composition w/ Hyperlinks µApp SPA µApp SPA µApp SPA

Slide 43

Slide 43 text

@ManfredSteyer

Slide 44

Slide 44 text

@ManfredSteyer

Slide 45

Slide 45 text

@ManfredSteyer

Slide 46

Slide 46 text

@ManfredSteyer ✓ Simple  Loosing State  Load a new Application

Slide 47

Slide 47 text

@ManfredSteyer

Slide 48

Slide 48 text

@ManfredSteyer Web Components for Shared Widgets?

Slide 49

Slide 49 text

@ManfredSteyer Integration via Shell

Slide 50

Slide 50 text

@ManfredSteyer µService Providing a (SPA based) Shell µApp µApp µApp Shell

Slide 51

Slide 51 text

@ManfredSteyer

Slide 52

Slide 52 text

@ManfredSteyer Idea const Component = import('other-app/xyz') Does not work with webpack/ Angular CLI Even lazy parts must be known at compile time!

Slide 53

Slide 53 text

@ManfredSteyer Webpack 5 Module Federation Shell (Host) Microfrontend (Remote) // Maps Urls in // webpack config remotes: { mfe1: "http://..." } // Expose files in // webpack config exposes: { Cmp: './my.cmp.ts' } import('mfe1/Cmp')

Slide 54

Slide 54 text

@ManfredSteyer Dynamic Module Federation Shell (Host) Microfrontend (Remote) remotes: { } exposes: { Cmp: './my.cmp.ts' } loadRemoteModule({ type: 'module', remoteEntry: 'http://…', exposedModule: './Cmp' })

Slide 55

Slide 55 text

@ManfredSteyer How to Get the Microfrontend's URL? Shell (Host) Microfrontend (Remote) RemoteEntrypoint.js

Slide 56

Slide 56 text

@ManfredSteyer How to Share Libs? Shell (Host) Microfrontend (Remote) shared: [ "@angular/core", "…" ] shared: [ "@angular/core", "…" ]

Slide 57

Slide 57 text

@ManfredSteyer

Slide 58

Slide 58 text

@ManfredSteyer Default Behavior Selecting the highest compatible version ^10.0 ^10.1

Slide 59

Slide 59 text

@ManfredSteyer Default Behavior Conflict: No highest compatible version ^11.0 ^10.1

Slide 60

Slide 60 text

@ManfredSteyer Configuring Singletons shared: { "my-lib": { singleton: true } } 11.0 10.1

Slide 61

Slide 61 text

@ManfredSteyer Configuring Singletons shared: { "my-lib": { singleton: true, strictVersion: true // Error instead of warning! } } 11.0 10.1

Slide 62

Slide 62 text

@ManfredSteyer Relaxing Version Requirements shared: { "my-lib": { requiredVersion: ">=1.0.1 <11.1.1" } }

Slide 63

Slide 63 text

@ManfredSteyer

Slide 64

Slide 64 text

@ManfredSteyer ?

Slide 65

Slide 65 text

@ManfredSteyer Custom Builder

Slide 66

Slide 66 text

@ManfredSteyer

Slide 67

Slide 67 text

@ManfredSteyer 1) ng add @angular-architects/module-federation 2) Adjust generated configuration 3) ng serve

Slide 68

Slide 68 text

@ManfredSteyer 1) npm i @angular-architects/module-federation -D 2) ng g @angular-architects/module-federation:init 3) Adjust generated configuration 4) ng serve

Slide 69

Slide 69 text

@ManfredSteyer

Slide 70

Slide 70 text

@ManfredSteyer

Slide 71

Slide 71 text

@ManfredSteyer Wrap them into Web Components Angular App (MFE) React App (MFE)

Slide 72

Slide 72 text

@ManfredSteyer

Slide 73

Slide 73 text

@ManfredSteyer await import('other-app/web-cmp');

Slide 74

Slide 74 text

@ManfredSteyer await import('other-app/web-cmp'); const rootElm = document.createElement('web-cmp') document.body.appendChild(rootElm);

Slide 75

Slide 75 text

@ManfredSteyer await import('other-app/web-cmp'); const rootElm = document.createElement('web-cmp') document.body.appendChild(rootElm); WrapperComponent

Slide 76

Slide 76 text

@ManfredSteyer

Slide 77

Slide 77 text

@ManfredSteyer https://red-ocean-0fe4c4610.azurestaticapps.net

Slide 78

Slide 78 text

@ManfredSteyer Free eBook (5th Edition) ANGULARarchitects.io/book Module Federation & Nx

Slide 79

Slide 79 text

@ManfredSteyer Choosing a Solution

Slide 80

Slide 80 text

@ManfredSteyer Some General Advice Shared state, navigation b/w apps Hyperlinks Legacy Apps or *very very* strong isolation? iframes Separate Deployment/ mix Technologies? Load Bundles on Demand Monolith little much yes no yes no Module Federation

Slide 81

Slide 81 text

@ManfredSteyer d Slides & Examples Remote Company Workshops and Consulting http://angulararchitects.io