Slide 1

Slide 1 text

JavaScript Application Frameworks the parts | Garann Means @garannm

Slide 2

Slide 2 text

in applications and frameworks, the code is the easy part the hard part is decision making

Slide 3

Slide 3 text

and it is hard to build an app figuring out what it should do translating requirements to workflows making it all work together (even when you have good tools)

Slide 4

Slide 4 text

any framework may need customization a framework is a basis your app may have slightly different needs different ways of handling the same concept may exist within the same app it may have no opinion on other concepts

Slide 5

Slide 5 text

compare to jQuery: tons of functionality some core, some more esoteric discovering new features leads to better ways of doing things the most discoverable features are those we know should be there

Slide 6

Slide 6 text

using a tool well means understanding the decisions it makes, and making good decisions about how to use it

Slide 7

Slide 7 text

what should be there and what we should expect from it

Slide 8

Slide 8 text

we expect framework methods to live on a prototype unlike a library, whose methods should usually not require an instance allows creation of objects set up to work together instantiation lets us keep related functionality together

Slide 9

Slide 9 text

but we also need methods for the app containing the objects global initialization event broadcasting global state changes stateless utilities

Slide 10

Slide 10 text

so it makes sense to start with a global ( f u n c t i o n ( F r m w r k ) { f u n c t i o n _ i n i t ( ) { } F r m w r k . t e s t = f u n c t i o n ( ) { c o n s o l e . l o g ( " y u p " ) ; } ; _ i n i t ( ) ; } ) ( w i n d o w . F r m w r k = { } ) ; F r m w r k . t e s t ( ) ; / / y u p

Slide 11

Slide 11 text

so thatG s nice. but it should do something

Slide 12

Slide 12 text

we were going to instantiate some objects state data or both we don't want to have to create too many types

Slide 13

Slide 13 text

one object we know we need f u n c t i o n _ i n i t ( ) { F r m w r k . a p p = n e w F r m w r k . O b j e c t ( ) ; }

Slide 14

Slide 14 text

so letG s make that the default F r m w r k . O b j e c t = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { s e l : " b o d y " } , o b j ) ; i f ( t h i s . s e l ) { t h i s . e l = $ ( t h i s . s e l ) ; } r e t u r n t h i s ; } ;

Slide 15

Slide 15 text

hold up.. whose $ is that

Slide 16

Slide 16 text

utility libraries it's also good to understand libraries but this is not a talk on libraries make a smart choice providing the most you need but no more jQuery, Underscore, Zepto, etc. focus on connecting pieces, not writing essential tools

Slide 17

Slide 17 text

including third-party libraries or tools can be appended to your core file other users don't need to import the additional script difficult to change or upgrade may conflict with other versions in use

Slide 18

Slide 18 text

leaving it up to implementers other users need to import the script separately, in order framework should work with all supported versions may make sense to allow uses of library to be overriden

Slide 19

Slide 19 text

a note about dependencies

Slide 20

Slide 20 text

in this example, jQuery is used like so: ( f u n c t i o n ( F r m w r k , $ ) { . . . } ) ( w i n d o w . F r m w r k = { } , w i n d o w . j Q u e r y ) ;

Slide 21

Slide 21 text

for a more modular approach, you might use require.js d e f i n e ( [ " j Q u e r y " ] , f u n c t i o n ( $ ) { . . . } ) ;

Slide 22

Slide 22 text

letG s get back to our base object F r m w r k . O b j e c t = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { s e l : " b o d y " } , o b j ) ; i f ( t h i s . s e l ) { t h i s . e l = $ ( t h i s . s e l ) ; } r e t u r n t h i s ; } ;

Slide 23

Slide 23 text

what do we expect from a data object a place to store data the ability to save and update itself notifications if it changes

Slide 24

Slide 24 text

setting and changing data ideally, set on object creation but may need to be set on an empty object (like the app) should be possible to update one or more properties

Slide 25

Slide 25 text

the data should be its own object F r m w r k . O b j e c t = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { s e l : " b o d y " , d a t a : { } } , o b j ) ; i f ( t h i s . s e l ) { t h i s . e l = $ ( t h i s . s e l ) ; } r e t u r n t h i s ; } ;

Slide 26

Slide 26 text

we want control over how thatG s updated F r m w r k . O b j e c t . p r o t o t y p e . s e t = _ s e t = f u n c t i o n ( d a t a , v a l ) { i f ( t y p e o f d a t a = = " s t r i n g " ) { t h i s . d a t a [ d a t a ] = v a l ; } e l s e { f o r ( k e y i n d a t a ) { t h i s . d a t a [ k e y ] = d a t a [ k e y ] ; } } r e t u r n t h i s ; } ;

Slide 27

Slide 27 text

and a shortcut for the app itself F r m w r k . s e t = f u n c t i o n ( ) { _ s e t . a p p l y ( F r m w r k . a p p , a r g u m e n t s ) ; } ;

Slide 28

Slide 28 text

why not just have the implementer modify ÇobjÓ.data directly this is a cheap workaround to observing the objects can fire off events, update server allows for a predictable pattern allows us to do a little magic

Slide 29

Slide 29 text

the downside is it means we also need a way to get data F r m w r k . O b j e c t . p r o t o t y p e . g e t = _ g e t = f u n c t i o n ( k e y ) { r e t u r n t h i s . d a t a [ k e y ] ; } ; F r m w r k . g e t = f u n c t i o n ( ) { r e t u r n _ g e t . a p p l y ( F r m w r k . a p p , a r g u m e n t s ) ; } ;

Slide 30

Slide 30 text

we could also condense the two, jQuery- style F r m w r k . O b j e c t . p r o t o t y p e . d a t a = _ d a t a = f u n c t i o n ( d a t a , v a l ) { i f ( a r g u m e n t s . l e n g t h = = 1 & & t y p e o f d a t a = = " s t r i n g " ) { r e t u r n t h i s . d a t a [ k e y ] ; } e l s e { . . . } ;

Slide 31

Slide 31 text

once we have data, we have something to store data persistence tends to be boring to write we need several types of XHRs we want saving and updating to be as invisible as possible

Slide 32

Slide 32 text

should we assume REST depends very much on your backend may be more JavaScripty to do CRUD from all endpoints: data with no ID: create ID only: read data and ID: update ID and string or number: delete but only if that fits the larger architecture

Slide 33

Slide 33 text

letG s assume it does F r m w r k . O b j e c t = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { s e l : " b o d y " , d a t a : { } , e n d p o i n t : n u l l } , o b j ) ; i f ( t h i s . s e l ) { t h i s . e l = $ ( t h i s . s e l ) ; } r e t u r n t h i s ; } ;

Slide 34

Slide 34 text

we want to sync whenever an update happens F r m w r k . O b j e c t . p r o t o t y p e . s e t = _ s e t = f u n c t i o n ( d a t a , v a l ) { i f ( t y p e o f d a t a = = " s t r i n g " ) { t h i s . d a t a [ d a t a ] = v a l ; } e l s e { f o r ( k e y i n d a t a ) { t h i s . d a t a [ k e y ] = d a t a [ k e y ] ; } } i f ( t h i s . e n d p o i n t ) { t h i s . s y n c ( ) ; } r e t u r n t h i s ; } ;

Slide 35

Slide 35 text

additionally, we want explicit methods to delete or read an object please use your imagination for those Nremember that thing about CRUD being boring Ñ

Slide 36

Slide 36 text

then, of course, we need a function to do the work F r m w r k . O b j e c t . p r o t o t y p e . s y n c = f u n c t i o n ( d a t a , c m d ) { v a r i d = t y p e o f d a t a = = " n u m b e r " ? d a t a : u n d e f i n e d , t h a t = t h i s ; $ . p o s t ( t h i s . e n d p o i n t , { i d : d a t a . i d | | i d , c o m m a n d : c m d , d a t a : i d ? u n d e f i n e d : d a t a } , f u n c t i o n ( r e s ) { i f ( t y p e o f r e s = = " n u m b e r " ) { t h a t . d a t a . i d = r e s ; } e l s e i f ( r e s . i d ) { f o r ( k e y i n r e s ) { t h a t . d a t a [ k e y ] = d a t a [ k e y ] ; } }

Slide 37

Slide 37 text

several decisions reflected there not RESTful, as discussed flexible signature for a single method without explicit flags most important: happens in the background

Slide 38

Slide 38 text

weG ve been talking about objects but we want those objects to talk to a framework

Slide 39

Slide 39 text

it would be nice to have notifications when object data is set when the data is synced with the server if an error occurs anywhere along the way

Slide 40

Slide 40 text

messaging options document-level DOM events super-basic pub/sub promises third-party utilities with multiple options

Slide 41

Slide 41 text

these are all legit. but weG re going to use the simplest

Slide 42

Slide 42 text

we want events to be scoped to objects F r m w r k . O b j e c t = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { s e l : " b o d y " , d a t a : { } , e n d p o i n t : n u l l , e v e n t s : { } } , o b j ) ; i f ( t h i s . s e l ) { t h i s . e l = $ ( t h i s . s e l ) ; } r e t u r n t h i s ; } ;

Slide 43

Slide 43 text

weG ll manage that cache with three methods F r m w r k . O b j e c t . p r o t o t y p e . p u b = _ p u b = f u n c t i o n ( n a m e , a r g s ) { v a r t h a t = t h i s ; i f ( t h i s . e v e n t s [ n a m e ] ) { $ . e a c h ( t h i s . e v e n t s [ n a m e ] , f u n c t i o n ( ) { t h i s . a p p l y ( t h a t , a r g s | | [ ] ) ; } ) ; } } ; F r m w r k . O b j e c t . p r o t o t y p e . s u b = _ s u b = f u n c t i o n ( n a m e , c a l l b a c k ) { i f ( ! t h i s . e v e n t s [ n a m e ] ) { t h i s . e v e n t s [ n a m e ] = [ ] ; } t h i s . e v e n t s [ n a m e ] . p u s h ( c a l l b a c k ) ; r e t u r n [ n a m e , c a l l b a c k ] ; } ; F r m w r k . O b j e c t . p r o t o t y p e . u n s u b = _ u n s u b = f u n c t i o n ( h a n d l e ) { v a r e v t s = t h i s . e v e n t s [ h a n d l e [ 0 ] ] , hat tip to Pete Higgins

Slide 44

Slide 44 text

now when something happens, we can publish an event F r m w r k . O b j e c t . p r o t o t y p e . s e t = _ s e t = f u n c t i o n ( d a t a , v a l ) { i f ( t y p e o f d a t a = = " S t r i n g " ) { t h i s . d a t a [ d a t a ] = v a l ; } e l s e { f o r ( k e y i n d a t a ) { t h i s . d a t a [ k e y ] = d a t a [ k e y ] ; } } t h i s . p u b ( " u p d a t e d " , t h i s . d a t a ) ; i f ( t h i s . e n d p o i n t ) { t h i s . s y n c ( ) ; } r e t u r n t h i s ; } ;

Slide 45

Slide 45 text

or if the wrong thing happens, we can notify observers of the error F r m w r k . O b j e c t . p r o t o t y p e . s y n c = f u n c t i o n ( d a t a , c m d ) { v a r i d = t y p e o f d a t a = = " n u m b e r " ? d a t a : u n d e f i n e d , t h a t = t h i s ; $ . p o s t ( t h i s . e n d p o i n t , { i d : d a t a . i d | | i d | | u n d e f i n e d , c o m m a n d : c m d | | u n d e f i n e d , d a t a : i d ? u n d e f i n e d : d a t a } , f u n c t i o n ( r e s ) { i f ( t y p e o f r e s = = " n u m b e r " ) { t h a t . d a t a . i d = r e s ; } e l s e i f ( r e s . i d ) { f o r ( k e y i n r e s ) { t h a t . d a t a [ k e y ] = d a t a [ k e y ] ; } }

Slide 46

Slide 46 text

global events can be scoped to the app F r m w r k . p u b = f u n c t i o n ( ) { _ p u b . a p p l y ( F r m w r k . a p p , a r g u m e n t s ) ; } ; F r m w r k . s u b = f u n c t i o n ( ) { r e t u r n _ s u b . a p p l y ( F r m w r k . a p p , a r g u m e n t s ) ; } ; F r m w r k . u n s u b = f u n c t i o n ( ) { _ u n s u b . a p p l y ( F r m w r k . a p p , a r g u m e n t s ) ; } ;

Slide 47

Slide 47 text

notifications as an implementer controllers, presenters, viewmodels ideally, publishing events controlled by framework implementations merely listen but we have events we don't control coming from the DOM

Slide 48

Slide 48 text

connecting to the view

Slide 49

Slide 49 text

a JS framework should be decoupled from HTML and CSS maintainability modularity separation of concerns not using JS for things that don't require it

Slide 50

Slide 50 text

note: this is JS frameworks client-side frameworks may be more tightly coupled, and do more view stuff

Slide 51

Slide 51 text

elements of the view templates CSS DOM listeners potentially a data transformation layer

Slide 52

Slide 52 text

an object might have more than one view, though for that we need states

Slide 53

Slide 53 text

a new object type F r m w r k . S t a t e = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { p a r e n t : F r m w r k . a p p , t m p l : n u l l , s e t t i n g s : { } , c a l l b a c k : n u l l } , o b j ) ; r e t u r n t h i s ; } ;

Slide 54

Slide 54 text

tied to the generic object F r m w r k . O b j e c t = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { s e l : " b o d y " , d a t a : { } , e n d p o i n t : n u l l , e v e n t s : { } , s t a t e s : { } } , o b j ) ; i f ( t h i s . s e l ) { t h i s . e l = $ ( t h i s . s e l ) ; } r e t u r n t h i s ; } ;

Slide 55

Slide 55 text

child objects force us to think about initialization we want implementers to be able to pass in literals but we want instances that can have prototype methods our options are: 1. force states to be added explicitly 2. filter states supplied on initialization

Slide 56

Slide 56 text

this is a place where itG s nice to do some magic F r m w r k . O b j e c t = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { s e l : " b o d y " , d a t a : { } , e n d p o i n t : n u l l , e v e n t s : { } , s t a t e s : { } } , o b j ) ; i f ( t h i s . s e l ) { t h i s . e l = $ ( t h i s . s e l ) ; } f o r ( v a r s i n t h i s . s t a t e s ) { i f ( ! t h i s . s t a t e s [ s ] i n s t a n c e o f F r m w r k . S t a t e ) { t h i s . s t a t e s [ s ] = n e w F r m w r k . S t a t e ( t h i s . s t a t e s [ s ] ) ; } }

Slide 57

Slide 57 text

once we have states we can switch between them F r m w r k . O b j e c t . p r o t o t y p e . s t a t e = _ s t a t e = f u n c t i o n ( n a m e ) { i f ( ! n a m e ) { r e t u r n t h i s . _ c u r r e n t S t a t e = = " _ d e f a u l t " ? n u l l : t h i s . _ c u r r e n t S t a t e } i f ( t h i s . s t a t e s [ n a m e ] ) { t h i s . s t a t e s [ n a m e ] . r e n d e r ( ) ; t h i s . _ c u r r e n t S t a t e = n a m e ; r e t u r n t h i s . s t a t e s [ n a m e ] ; } } ; F r m w r k . s t a t e = f u n c t i o n ( ) { _ s t a t e . a p p l y ( F r m w r k . a p p , a r g u m e n t s ) ; } ;

Slide 58

Slide 58 text

and, since theyG re instances, use their methods bringing us back to templates

Slide 59

Slide 59 text

very simple template rendering F r m w r k . S t a t e . p r o t o t y p e . r e n d e r = f u n c t i o n ( ) { v a r d a t a = $ . e x t e n d ( t r u e , { } , t h i s . p a r e n t . d a t a , t h i s . s e t t i n g s ) ; t h i s . p a r e n t . e l . h t m l ( t h i s . t m p l ( d a t a ) ) ; i f ( t h i s . c a l l b a c k ) { t h i s . c a l l b a c k . a p p l y ( t h i s , a r g u m e n t s ) ; } } ;

Slide 60

Slide 60 text

contains several assumptions: t m p l has already been compiled to a function a state will always replace the object it belongs to any partial templates are already accessible somehow the correct CSS is already loaded

Slide 61

Slide 61 text

thatG s a lot can we make some of those more flexible or automatic

Slide 62

Slide 62 text

easy fixes F r m w r k . S t a t e . p r o t o t y p e . r e n d e r = f u n c t i o n ( ) { v a r d a t a = $ . e x t e n d ( t r u e , { } , t h i s . p a r e n t . d a t a , t h i s . s e t t i n g s ) ; i f ( t h i s . c s s ) { $ ( " h e a d " ) . a p p e n d ( ' < s t y l e c l a s s = " ' + t h i s . _ n a m e + ' " > ' + t h i s . c s s + } t h i s . c o n t a i n e r ? t h i s . c o n t a i n e r . h t m l ( t h i s . t m p l ( d a t a ) ) : t h i s . p a r e n t . e l . h t m l ( t h i s . t m p l ( d a t a ) ) ; i f ( t h i s . c a l l b a c k ) { t h i s . c a l l b a c k . a p p l y ( t h i s , a r g u m e n t s ) ; } } ;

Slide 63

Slide 63 text

loading templates and partials is trickier should be able to take a URL or a template element should know whether the template's already loaded should handle partials differently and know which partials it requires

Slide 64

Slide 64 text

we should handle that in our constructor F r m w r k . S t a t e = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { p a r e n t : F r m w r k . a p p , t m p l : n u l l , s e t t i n g s : { } , c a l l b a c k : n u l l } , o b j ) ; / / t m p l n e e d s t o b e c o m p i l e d i f ( t h i s . t m p l & & t y p e o f t h i s . t m p l ! = " f u n c t i o n " ) { t h i s . t m p l = _ c o m p i l e T m p l ( t h i s . t m p l , t h i s . p a r t i a l s ) ; } r e t u r n t h i s ; } ;

Slide 65

Slide 65 text

and do the loading work, if necessary, in a static function v a r _ t m p l C a c h e = { } ; f u n c t i o n _ c o m p i l e T m p l ( t m p l S t r i n g , p a r t i a l s , n a m e ) { v a r t m p l N a m e = n a m e | | t m p l S t r i n g . r e p l a c e ( " \ / " , " _ " ) . r e p l a c e ( " . " , d e f = { } ; i f ( p a r t i a l s & & t y p e o f p a r t i a l s = = " o b j e c t " & & p a r t i a l s . l e n g t h ) { p a r t i a l s . f o r E a c h ( f u n c t i o n ( p ) { d e f [ p . n a m e ] = _ t m p l C a c h e [ p . n a m e ] ; } ) ; } i f ( _ t m p l C a c h e [ t m p l N a m e ] ) { r e t u r n _ t m p l C a c h e [ t m p l N a m e ] ; } e l s e i f ( $ ( " b o d y " ) . f i n d ( t m p l S t r i n g ) . l e n g t h ) { r e t u r n _ t m p l C a c h e [ t m p l N a m e ] = d o T . t e m p l a t e ( $ ( t m p l S t r i n g ) . h t m l } e l s e { $ . g e t ( t m p l S t r i n g , f u n c t i o n ( t m p l ) { _ t m p l C a c h e [ t m p l N a m e ] = d o T . t e m p l a t e ( t m p l , n u l l , d e f ) ;

Slide 66

Slide 66 text

we also need a way to add partials we can't expect partials to be tied to an object or state we need them to be available when the templates using them are compiled

Slide 67

Slide 67 text

thus, the first method belonging exclusively to the application F r m w r k . a p p . r e g i s t e r T m p l = _ r e g i s t e r T m p l = f u n c t i o n ( n a m e , t m p l S t r i n g ) { _ c o m p i l e T m p l ( t m p l S t r i n g , n u l l , n a m e ) ; } ;

Slide 68

Slide 68 text

why not just use _ c o m p i l e T m p l we could, but itG s nice to have a separate public interface

Slide 69

Slide 69 text

it also helps reflect a different use F r m w r k . O b j e c t = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { s e l : " b o d y " , d a t a : { } , e n d p o i n t : n u l l , e v e n t s : { } , s t a t e s : { } , _ c u r r e n t S t a t e : " _ d e f a u l t " , t m p l s : { } } , o b j ) ; i f ( t h i s . s e l ) { t h i s . e l = $ ( t h i s . s e l ) ; } i f ( t h i s . t m p l s ) { f o r ( v a r t i n t h i s . t m p l s ) { _ r e g i s t e r T m p l ( t , t h i s . t m p l s [ t ] ) ; }

Slide 70

Slide 70 text

real talk: that could be much better everything's easy until it's async external resources are likely to require async code this is an ideal place for promises ..which we'd get from yet another external resource

Slide 71

Slide 71 text

we want a framework to also help manage dependencies what we have could work if dependencies are finite if they're generic, we'd be better off with something like Require.js something like that means we have to think of the framework differently

Slide 72

Slide 72 text

taking Require as an example.. our object types would be modules the app would be a specific dependency we could remove any code to load templates or CSS all this code would be required by implementations

Slide 73

Slide 73 text

one more piece wiring up the DOM

Slide 74

Slide 74 text

weG ve left a place for some implementation code F r m w r k . S t a t e = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { p a r e n t : F r m w r k . a p p , t m p l : n u l l , s e t t i n g s : { } , c a l l b a c k : n u l l } , o b j ) ; / / t m p l n e e d s t o b e c o m p i l e d i f ( t h i s . t m p l & & t y p e o f t h i s . t m p l ! = " f u n c t i o n " ) { t h i s . t m p l = _ c o m p i l e T m p l ( t h i s . t m p l , t h i s . p a r t i a l s ) ; } r e t u r n t h i s ; } ;

Slide 75

Slide 75 text

some frameworks attempt to contain DOM interaction lists of selectors and events callbacks belong to the application or a controller this keeps everything nice and clean but doesn't add a whole lot of functionality

Slide 76

Slide 76 text

what DOM functionality can a framework add re-rendering attaching DOM interactions to state changes forwarding DOM events to framework events

Slide 77

Slide 77 text

the rest is nobodyG s business but the DOMG s

Slide 78

Slide 78 text

what we need to trigger a state change an element to delegate to the selector and event the name of the state to switch to

Slide 79

Slide 79 text

we want this wired up when our state is created F r m w r k . S t a t e = f u n c t i o n ( o b j ) { $ . e x t e n d ( t r u e , t h i s , { p a r e n t : F r m w r k . a p p , t m p l : n u l l , s e t t i n g s : { } , c a l l b a c k : n u l l , t r i g g e r : n u l l } , o b j ) ; / / t m p l n e e d s t o b e c o m p i l e d i f ( t h i s . t m p l & & t y p e o f t h i s . t m p l ! = " f u n c t i o n " ) { t h i s . t m p l = _ c o m p i l e T m p l ( t h i s . t m p l , t h i s . p a r t i a l s ) ; } i f ( t h i s . t r i g g e r & & t h i s . t r i g g e r . l e n g t h ) { t h i s . t r i g g e r . f o r E a c h ( f u n c t i o n ( t ) { $ ( t . c o n t a i n e r | | t h i s . p a r e n t . e l ) . o n ( t . e v e n t , t . s e l e c t o r , t h i s } ) ; }

Slide 80

Slide 80 text

how about more generic events we may still want to fire events scoped to an object our publish method is public, so implementers can do that manually for something very small and unopinionated, that's probably enough

Slide 81

Slide 81 text

but we should talk about opinions

Slide 82

Slide 82 text

this example is more useful as a complement to something else lots of control in HTML or CSS a DOM library a datavis library a widget or component framework a client/server framework

Slide 83

Slide 83 text

there are a lot of tools but only a handful of strategies for augmenting them

Slide 84

Slide 84 text

with HTML/CSS framework provides initial data and rendering states can be exclusively data states, not visual state callbacks set up explicit data updates framework exists to store and sync data

Slide 85

Slide 85 text

CSS specifically cause thatG s kind of hard CSS interactions are an alternative to JS we can observe animations (e.g. a n i m a t i o n S t a r t , a n i m a t i o n E n d ) but we can't directly observe something activating : t a r g e t , for example and we can't forward events from CSS to JS the most foolproof way to integrate with CSS is to listen for the same events

Slide 86

Slide 86 text

with DOM-heavy libraries or plugins object DOM element is just the container stores data for child elements that aren't objects child elements created by object's template object's default state callback listens for library events and updates its data accordingly again, storing and syncing

Slide 87

Slide 87 text

with components or widgets framework objects could be made less generic to be aware of library functions or the two can communicate from their controller code components should manage themselves, so framework only needs to worry about public notifications still storing and syncing, but at a higher level of remove

Slide 88

Slide 88 text

with frameworks that handle the backend again, we can be less generic and rely on server- aware objects those may still need rendering and client-only messaging this time, we're observing third-party events coming not from the user but the server or the data handle the manipulation of data, leave the rest to the underlying framework

Slide 89

Slide 89 text

in the real world, we usually only think about pieces of frameworks in conjunction with existing frameworks

Slide 90

Slide 90 text

what to do with these ideas don't go write a new generic do-everything framework think about what pieces your app needs from a framework choose frameworks that are opionated about those things if you can't find a perfect fit, write a small wrapper that adds just what you need

Slide 91

Slide 91 text

thanks! any questions | garann.com @garannm