Using Require.js with CakePHP

Using Require.js with CakePHP

The CakePHP framework provides excellent tools to structure and organize server code -- making development fun and maintainable. Combining these tools with a solid Require.js implementation can elevate the often haphazard front-end development experience to the same level of excellence.

This talk will give a very brief overview of Require.js and it's benefits. It will outline a typical Require.js "Hello World" implementation. This will be followed by a more robust implementation for projects that are backed by CakePHP and have thousands of lines of javascript.

The talk will end with notes on configuring the Require.js optimizer to combine and minify the source for deployment.

9673aada5df552a024234a5220d50501?s=128

Zumba Technology

August 31, 2013
Tweet

Transcript

  1. USING REQUIREJS WITH CAKEPHP Stephen Young @young_steveo Sr. Software Engineer

    - Zumba Fitness
  2. WHAT'S THE POINT?

  3. The Javascript layer of a typical MVC app starts simple.

    ...like a jQuery Zen garden. $ ( f u n c t i o n ( ) { / * a n i m a t e t h e b l o g t i t l e * / $ ( ' . t i t l e ' ) . s l i d e D o w n ( ) ; } ) ;
  4. As the project matures, things get a little more tricky.

    $ ( f u n c t i o n ( ) { / * a n i m a t e t h e b l o g t i t l e * / $ ( ' . t i t l e ' ) . s l i d e D o w n ( 3 5 0 , f u n c t i o n ( ) { $ . g e t ( ' / s t a t s / c o u n t ' ) . d o n e ( f u n c t i o n ( d a t a ) { $ ( ' . s t a t s C o u n t ' ) . h t m l ( d a t a . c o u n t ) . a d d C l a s s ( ' g r e e n ' ) ; } ) ; } ) ; } ) ; Still maintainable... -ish
  5. ...before long

  6. / * m e g a _ f i l

    e . j s * / $ ( f u n c t i o n ( ) { i f ( w i n d o w . i s B l o g P a g e & & t y p e o f w i n d o w . A p p ! = = ' u n d e f i n e d ' ) { v a r a p p = n e w A p p ( ) ; / * a n i m a t e t h e b l o g t i t l e * / $ ( ' . t i t l e ' ) . s l i d e D o w n ( 3 5 0 , f u n c t i o n ( ) { $ . g e t ( ' / s t a t s / c o u n t ' ) . d o n e ( f u n c t i o n ( d a t a ) { $ ( ' . s t a t s C o u n t ' ) . h t m l ( d a t a . c o u n t ) . a d d C l a s s ( ' g r e e n ' ) ; $ . g e t S c r i p t ( ' / j s / s u p e r A w e s o m e P l u g i n ' , f u n c t i o n ( ) { $ . g e t ( ' / p o s t s / s o m e D a t a ' ) . d o n e ( f u n c t i o n ( d a t a ) { i f ( d a t a . p o s t s ) { d o S o m e C o o l S t u f f ( d a t a . p o s t s ) ; } } ) ; } ) ; } ) ; } ) ; } e l s e i f ( w i n d o w . i s C a t e g o r y ) { / * o h , g o d , p l e a s e , s t o p ! * /
  7. Don't forget the layout file...

  8. < s c r i p t s r c

    = " j s / b o x 2 d / c o m m o n / b 2 S e t t i n g s . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o m m o n / m a t h / b 2 V e c 2 . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o m m o n / m a t h / b 2 M a t 2 2 . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o m m o n / m a t h / b 2 M a t h . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 A A B B . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 B o u n d . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 B o u n d V a l u e s . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 P a i r . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 P a i r C a l l b a c k . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 B u f f e r e d P a i r . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 P a i r M a n a g e r . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 B r o a d P h a s e . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 C o l l i s i o n . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / F e a t u r e s . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 C o n t a c t I D . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 C o n t a c t P o i n t . j s " > < / s c r i p t > < s c r i p t s r c = " j s / b o x 2 d / c o l l i s i o n / b 2 D i s t a n c e . j s " > < / s c r i p t >
  9. THERE IS A BETTER WAY.

  10. WHAT IS REQUIREJS? javascript module & file loader AMD (asynchronous

    module definition) optimization tool http://requirejs.org
  11. WHAT'S SO GREAT ABOUT AMD? Encapsulation Dependency Management

  12. AMD EXAMPLE Define your modules: / * d e f

    i n e ( i d ? , d e p e n d e n c i e s ? , f a c t o r y ) ; * / d e f i n e ( " S o m e M o d u l e " , [ " d e p e n d e n c y " ] , f u n c t i o n ( d e p e n d e n c y ) { v a r S o m e M o d u l e = f u n c t i o n ( ) { } ; S o m e M o d u l e . p r o t o t y p e . i n i t = f u n c t i o n ( ) { d e p e n d e n c y . d o S t u f f ( ) ; } ; / * e t c . * / r e t u r n S o m e M o d u l e ; } ) ;
  13. AMD EXAMPLE Load your modules and use them: / *

    r e q u i r e ( d e p e n d e n c i e s , c a l l b a c k ) ; * / r e q u i r e ( [ " M o d u l e A " , " M o d u l e B " ] , f u n c t i o n ( M o d u l e A , M o d u l e B ) { v a r m o d u l e = n e w M o d u l e A ( ) ; M o d u l e A . i n i t ( ) ; / * e t c . * / } ) ;
  14. REQUIRE() OR DEFINE() ? Use `define` to declare a module

    for use elsewhere. Use `require` to pre-load dependencies and/or do some stuff.
  15. WHAT IS CAKEPHP? (just kidding)

  16. HELLO WORLD / * a p p / V i

    e w s / L a y o u t s / s o m e L a y o u t . c t p * / e c h o $ t h i s - > H t m l - > s c r i p t ( " r e q u i r e . j s " , [ " d a t a - m a i n " = > " / j s / b o o t s t r a p " ] ) ; / * a p p / w e b r o o t / j s / b o o t s t r a p . j s * / r e q u i r e j s . c o n f i g ( { p a t h s : { j q u e r y : ' j s / v e n d o r / j q u e r y . m i n ' } } ) ; r e q u i r e ( [ ' j s / l i b s / b l o g s ' ] ) ; / * a p p / w e b r o o t / j s / l i b s / b l o g s . j s * / r e q u i r e ( [ ' j q u e r y ' ] , f u n c t i o n ( $ ) { $ ( f u n c t i o n ( ) { / * e t c . * / } ) ; } ) ;
  17. IT IS THAT SIMPLE. IS IT THAT SIMPLE? IT NEVER

    IS, IS IT? Even with RequireJS, things can get out of hand. As with many great tools, RequireJS gives you plenty of "rope."
  18. TIPS Keep your modules focused; remember the single responsibility principle.

    Define a solid directory structure, and stick to it. (like your CakePHP /app directory) Think "automagic" and document your conventions. / j s / R E A D M E . m d
  19. GOING BEYOND "HELLO WORLD" i.e. What if your project contains

    LOTS of javascript?
  20. DISCLAIMER This works for us, and we like it, but

    feel free to tweak it to meet your needs.
  21. IDENTIFY SECTIONS FOR YOUR PROJECT 1. Break the project down

    into sections, and create a module for each section (e.g. b l o g . j s , s h o p . j s , etc). 2. Identify any functionality that would be shared across multiple sections, and put them into common modules.
  22. CHANGE THE LAYOUT BEFORE: / * ( d a t

    a - m a i n d o e s t h e h e a v y l i f t i n g ) * / e c h o $ t h i s - > H t m l - > s c r i p t ( " r e q u i r e . j s " , [ " d a t a - m a i n " = > " / j s / b o o t s t r a p " ] ) ; AFTER: / * n o m o r e d a t a - m a i n * / e c h o $ t h i s - > H t m l - > s c r i p t ( " r e q u i r e . j s " ) ; < s c r i p t > r e q u i r e ( [ ' / j s / b o o t s t r a p . j s ' ] , f u n c t i o n ( ) { r e q u i r e ( [ ' m o d u l e s / < ? p h p e c h o $ j a v a s c r i p t M o d u l e ; ? > ' ] ) ; } ) ; < / s c r i p t >
  23. MODIFY THE APPCONTROLLER p u b l i c f

    u n c t i o n b e f o r e R e n d e r ( ) { $ t h i s - > s e t ( a r r a y ( ' j a v a s c r i p t M o d u l e ' = > $ t h i s - > j a v a s c r i p t M o d u l e ) ) ; } p u b l i c f u n c t i o n b e f o r e F i l t e r ( ) { / * j u s t a n i c e c o n v e n t i o n , y o u c o u l d u s e a d e f a u l t f i l e t o o * / i f ( ! $ t h i s - > j a v a s c r i p t M o d u l e ) { $ m o d u l e N a m e = I n f l e c t o r : : u n d e r s c o r e ( $ t h i s - > n a m e ) ; $ t h i s - > j a v a s c r i p t M o d u l e = $ m o d u l e N a m e ; } }
  24. NEW BOOTSTRAP.JS FILE r e q u i r e

    j s . c o n f i g ( { p a t h s : { j q u e r y : ' j s / v e n d o r / j q u e r y ' , s o m e L i b : ' j s / l i b s / s o m e L i b ' , a n o t h e r L i b : ' j s / l i b s / a n o t h e r L i b ' } , s h i m : { a n o t h e r L i b : [ ' j q u e r y ' , ' s o m e L i b ' ] } } ) ;
  25. OPTIMIZATION

  26. R.JS RequireJS ships with a great minification/concatenation tool It runs

    in Node.js, Java with Rhino, or a browser It is configurable Bonus: it can minify CSS files for you too (but I'm not going to cover that today)
  27. CONCATENATE DEPENDENCIES r.js will combine modules that are specified as

    dependencies in your module definitions
  28. CONFIGURATION FILE { " m o d u l e

    s " : [ { " n a m e " : " b o o t s t r a p " , " i n c l u d e " : [ " u n d e r s c o r e " , " b a c k b o n e " , " j q u e r y " ] } , { " n a m e " : " b l o g s " , e x c l u d e : [ ' b o o t s t r a p ' ] } , { " n a m e " : " s h o p s " , e x c l u d e : [ ' b o o t s t r a p ' ] } , { " n a m e " : " p r o f i l e s " , e x c l u d e : [ ' b o o t s t r a p ' ] } , / * e t c . * /
  29. THAT'S IT! QUESTIONS?

  30. EXAMPLE REPO github.com/young-steveo/require_cake