Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Building Modular Frontend Architectures
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
190
React_Performance__2022.pdf
stevekinney
0
43
React Performance v2
stevekinney
0
64
Introduction to Testing
stevekinney
0
190
Web Security, Frontend Masters
stevekinney
0
4.2k
Making Music with the Web Audio API, JSConf Colombia 2023
stevekinney
0
130
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
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
390
AI: The stuff that nobody shows you
jnunemaker
PRO
9
940
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
550
How GitHub (no longer) Works
holman
316
150k
GitHub's CSS Performance
jonrohan
1033
470k
Mobile First: as difficult as doing things right
swwweet
225
10k
Building AI with AI
inesmontani
PRO
1
1.2k
Google's AI Overviews - The New Search
badams
0
1.1k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
380
Product Roadmaps are Hard
iamctodd
55
12k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
290
A Modern Web Designer's Workflow
chriscoyier
698
190k
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?