Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Building Modular Frontend Architectures
Search
Steve Kinney
August 07, 2019
500
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Building Modular Frontend Architectures
Steve Kinney
August 07, 2019
More Decks by Steve Kinney
See All by Steve Kinney
Enterprise UI, v2
stevekinney
0
290
React_Performance__2022.pdf
stevekinney
0
47
React Performance v2
stevekinney
0
82
Introduction to Testing
stevekinney
0
200
Web Security, Frontend Masters
stevekinney
0
4.4k
Making Music with the Web Audio API, JSConf Colombia 2023
stevekinney
0
140
React and TypeScript, Turing School
stevekinney
0
390
Redux Workshop, 2021-05-05
stevekinney
2
2.2k
TypeScript and React Utility Types
stevekinney
1
230
Featured
See All Featured
Balancing Empowerment & Direction
lara
6
1.3k
Embracing the Ebb and Flow
colly
88
5.2k
Marketing to machines
jonoalderson
1
5.9k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
320
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.2k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
860
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
270
Building Adaptive Systems
keathley
44
3.2k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
490
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
840
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
Transcript
BUILDING MODULAR FRONTEND ARCHITECTURES Steve Kinney Senior Principal Engineer Twilio
TABLE OF CONTENTS 01. Defining Modularity 02. Layers of an
Application 03. Creating Modular UI 04. Modular Deployment
BUT, FIRST—WHO AM I?
AND WHO ARE YOU?
None
WHAT DO WE MEAN BY MODULAR?
None
None
SEPARATION IS NOT MODULARITY
MODULARITY DOES NOT HAPPEN BY ACCIDENT.
WHAT ARE SOME OF THE MOVING PARTS? • User Interface
• State Management • Location Within the Application • Communication with the Server
PATTERNS FOR APPLICATIONS • Model • View • Controller
PATTERNS FOR WEB APPLICATIONS • Model • View • Controller
• Routing • Data Fetching
MICROSERVICE VERSUS MODULAR ARCHITECTURES
MICRO-FRONTEND VERSUS MODULAR ARCHITECTURES
Micro-Frontend One Micro-Frontend Two Build Pipeline Build Pipeline Micro-Frontend One
Micro-Frontend Two Application Shell
STARTING SMALL
SINGLE RESPONSIBILITY A given component or module of your application
should have only one reason why you’d need to change it.
class CampaignsList extends React.Component { state = { campaigns: []
}; componentDidMount() { getCampaignsFromApi() .then(campaigns !=> this.setState({ campaigns })); } render() { <section> { this.state.campaigns.map(campaign !=> { <Campaign campaign={campaign} !/> }) } !</section> } }
class CampaignsFetcher extends React.Component { state = { campaigns: []
}; componentDidMount() { getCampaignsFromApi() .then(campaigns !=> this.setState({ campaigns })); } render() { <Campaigns campaigns={campaigns} !/>; } } const CampaignsList = ({ campaigns }) !=> ( <section> {campaigns.map(campaign !=> { <Campaign campaign={campaign} !/>; })} !</section> );
TAKING THIS PATTERN A STEP FURTHER • Tired: Multiple responsibilities
• Wired: Separating responsibilities • Inspired: Creating reusable, higher-order components
const withCampaigns = (WrappedComponent) !=> { return class extends React.Component
{ state = { campaigns: [] }; componentDidMount() { getCampaignsFromApi() .then(campaigns !=> this.setState({ campaigns })); } render() { return <WrappedComponent campaigns={campaigns} !/> } } }; const CampaignsList = ({ campaigns }) !=> ( <section> {campaigns.map(campaign !=> { <Campaign campaign={campaign} !/>; })} !</section> ); withCampaigns(CampaignsList);
withCurrentUser(withCampaigns(CampaignsList));
SEPARATING STATE FROM THE UI
None
Reducer New State State Action User Interface
{ TYPE: 'MESSAGE_SAVE', PAYLOAD: { … } }
const mapStateToProps = (state) !=> { return state.campaigns; }; const
mapDispatchToProps = { deleteCampaign, getCampaignStats, }; connect(mapStateToProps, mapDispatchToProps)(Campaigns);
WHEN YOU INTERACT WITH THE UI, IT SIMPLY FIRES ACTIONS.
REDUX DOES NOT HAVE ANY CONCEPT OF DATA FETCHING.
None
API Data Adapter User Interface Data
None
THE URL IS A FUNDAMENTAL PART OF THE WAY THE
WEB WORKS.
SINGLE-SENDS/:ID/EDITOR/PREVIEW
SINGLE-SENDS/:ID/DELETE
routeFor('single-sends'); routeFor('single-sends', id); RouteRegistry.add('multi-sends', '/multi-sends');
BUILDING COMPOSABLE COMPONENTS
WHAT IS COMPOSABILITY?
None
None
None
Automation Design Editor Side Panel Top Navigation Drag and Drop
Module Editor Preview Settings Tab Build Tab Tags Tab Desktop Preview Mobile Preview Plain Text Preview
PREFER DEPENDENCY INJECTION TO IMPORTING
Configuration Component
<DragAndDropEditor content={singleSendHtml} onChange={updateSingleSendContent} hasImageManager={true} !/>
const configuration = { colorTheme: { baseName: 'FlexDark' } };
React.createContext(configuration);
Configuration in Context API Automations Index Page Automations Design Editor
Automations Code Editor Design Editor Drag and Drop Modules Design Editor Preview HTML Editor Code Editor Preview
None
None
BECAUSE WE’VE ENCAPSULATED OUR MODULES AND MADE THEM COMPOSABLE, OUR
APPLICATION IS EXTENSIBLE.
Flex.Component.Content.add( <MyComponent key="demo-component"!/>, { options } ); Flex.Component.Content.replace( <MyComponent key="demo-component"!/>,
{ options } );
MODULARITY AND PERFORMANCE
“NETWORKS, CPUS, AND DISKS ALL HATE YOU. ON THE CLIENT,
YOU PAY FOR WHAT YOU SEND IN WAYS YOU CAN'T EASILY SEE.” ALEX RUSSEL, GOOGLE
None
None
None
import('./filename') .then(() !=> …);
export const Routes = ( <Fragment> <Route routeId="automations" path="/automations" component={Automations}!/>
<Route routeId="campaigns" path="/campaigns" component={Campaigns}!/> <Route routeId="contacts" path="/contacts" component={Contacts}!/> <Route routeId="custom-fields" path="/custom-fields" component={CustomFields}!/> <Route routeId="marketing-templates" path="/marketing-templates" component={MarketingTemplates}!/> <Route routeId="notifications" path="/notifications" component={Notifications}!/> <Route routeId="overview" path="/overview" component={Overview}!/> <Route routeId="senders" path="/senders" component={Senders}!/> <Route routeId="templates" path="/templates" component={Templates}!/> <Route routeId="tour" path="/tour" component={Tour}!/> <Route routeId="welcome" path="/welcome" component={Welcome}!/> !</Fragment> );
import Loadable from 'react-loadable'; import LoadingPage from '!../LoadingPage'; export default
Loadable({ loader: () !=> import('./components/page'), loading: LoadingPage, });
None
None
None
THANK YOU + QUESTIONS?