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
490
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
38
React_Performance__2022.pdf
stevekinney
0
31
React Performance v2
stevekinney
0
48
Introduction to Testing
stevekinney
0
170
Web Security, Frontend Masters
stevekinney
0
3.9k
Making Music with the Web Audio API, JSConf Colombia 2023
stevekinney
0
120
React and TypeScript, Turing School
stevekinney
0
380
Redux Workshop, 2021-05-05
stevekinney
2
2.2k
TypeScript and React Utility Types
stevekinney
1
220
Featured
See All Featured
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
430
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.2k
Heart Work Chapter 1 - Part 1
lfama
PRO
7
36k
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
390
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
160
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.2k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
480
Practical Orchestrator
shlominoach
191
11k
How to make the Groovebox
asonas
2
2.2k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
66
55k
A designer walks into a library…
pauljervisheath
211
24k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
180
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?