Slide 1

Slide 1 text

Pulling the strings.

Slide 2

Slide 2 text

@dcousineau

Slide 3

Slide 3 text

@croscon

Slide 4

Slide 4 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Single Page Apps

Slide 5

Slide 5 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com

Slide 6

Slide 6 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com

Slide 7

Slide 7 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com

Slide 8

Slide 8 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com https://leanpub.com/u/davidsulc

Slide 9

Slide 9 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Goals

Slide 10

Slide 10 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Simplified Architecture

Slide 11

Slide 11 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Front End Back End Classical JS Modules Per Page Bootstrapping Modules JS + HTML UI Assembly CSS Styling Controller-Action Per URL Controller Actions Heavy Templates Asset Management JS Scaffolding Full Page Loads Minor AJAX Updates RESTful API?

Slide 12

Slide 12 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Front End Back End SPA JS Modules Single Bootstrapping Modules Unified Module Arch Pure-JS UI Assembly CSS Styling Bootstrap Action(s) Asset Management First-Class REST API

Slide 13

Slide 13 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com require.js

Slide 14

Slide 14 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Modular Code Rapid Development Efficient Production

Slide 15

Slide 15 text

+Divide Into Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com UI Widgets Functional “Pages” Utilities

Slide 16

Slide 16 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Marionette

Slide 17

Slide 17 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Backbone.js Underscore.js Backbone.Marionette.js

Slide 18

Slide 18 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com define(['backbone', 'marionette'], function(Backbone, Marionette) { var App = new Marionette.Application(); ! App.addRegions({ toolbar: '#navbar' , main: '#main' }); ! var NotFoundView = Backbone.View.extend({ //... }); ! App.on("notfound", function() { App.main.show(new NotFoundView()); }); ! App.on("start", function() { //... }); ! return App; });

Slide 19

Slide 19 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com

Slide 20

Slide 20 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com require.config({ baseUrl: "/js", paths: { //... }, shim: { //... } }); ! require([ 'blueprint/app', 'blueprint/app/static', 'blueprint/app/auth', ‘blueprint/app/ toolbar', 'blueprint/app/registry', ‘blueprint/app/checkout' ],function(App){ App.start(); });

Slide 21

Slide 21 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com define([ 'blueprint/app', 'marionette' ], function(App, Marionette) { App.module("Toolbar", function(Toolbar, App) { var ToolbarLayout = Backbone.Marionette.Layout.extend({ /**/ }); var LoggedOutView = Marionette.ItemView.extend({ /**/ }); var LoggedInView = Marionette.ItemView.extend({ /**/ }); ! var loggedInViewFactory = function() { return new LoggedInView({ model: App.Auth.getCurrentUser() }); }; ! var loggedOutViewFactory = function() { return new LoggedOutView(); }; ! var toolbarFactory = function () { var layout = new ToolbarLayout() , toolbar = App.Auth.isLoggedIn() ? loggedInViewFactory() : loggedOutViewFactory(); layout.on('render', function() { layout.links.show(toolbar); }); ! return layout; };

Slide 22

Slide 22 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com define([ 'blueprint/app', 'marionette' ], function(App, Marionette) { App.module("Toolbar", function(Toolbar, App) { //... ! //called _once_ when app is made and booted up Toolbar.on("start", function() { var layout = toolbarFactory(); App.toolbar.show(layout); ! App.vent.on("login", function() { layout.links.show(loggedInViewFactory()); }); ! App.vent.on('logout', function() { layout.links.show(loggedOutViewFactory()); }); }); ! return App.Toolbar; }); });

Slide 23

Slide 23 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com define([‘blueprint/app', 'hbs!template/blueprint/registry/create/layout', 'marionette'], function(App, formLayoutTpl, Marionette) { App.module("Registry.Create", function(CreateRegistry, App) { //layout for all pages, main thing that is loaded var Layout = Marionette.Layout.extend({ template: layoutTpl , className: 'wrapper set-top' , regions: { form_container: '#main-form-container' } }); var FormLayout = Marionette.Layout.extend({ template: formLayoutTpl , regions: {form: '#form-wrapper'} , initialize: function () { this.listenTo(this.form, 'show', function () { this.$('.selectpicker').selectpicker(); }); this.listenTo(this.model, 'invalid', function (data) { //... }); } });

Slide 24

Slide 24 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com define([‘blueprint/app', 'hbs!template/blueprint/registry/create/layout', 'marionette'], function(App, formLayoutTpl, Marionette) { App.module("Registry.Create", function(CreateRegistry, App) { var registryLayoutFactory = function () { var model = new Models.Model.Registry(); ! var layout = new Layout({model: model}); var breadcrumbs = new BreadcrumbView({ crumbs: [/*...*/] }); ! var formLayout = new FormLayout({ model: model }); ! layout.on('render', function() { layout.form_container.show(formLayout); layout.breadcrumbs.show(breadcrumbs); }); ! return layout; };

Slide 25

Slide 25 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com define([‘blueprint/app', 'hbs!template/blueprint/registry/create/layout', 'marionette'], function(App, formLayoutTpl, Marionette) { App.module("Registry.Create", function(CreateRegistry, App) { CreateRegistry.Controller = Marionette.Controller.extend({ createRegistry: function() { Util.navigate("create-registry", {title: "Lorem Ipsum"}); App.vent.trigger('toolbar:fixed', false); ! var layout = registryLayoutFactory(); ! //now take over the main area of the app and show the layout App.main.show(layout); App.vent.trigger('toolbar:current', 'menu-create'); } }); ! CreateRegistry.Router = new Marionette.AppRouter({ appRoutes: { "create-registry": “createRegistry" } , controller: CreateRegistry.Controller() }); }); ! return App.Registry.Create; });

Slide 26

Slide 26 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com

Slide 27

Slide 27 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com $('some selector').on('doesnt matter', no);

Slide 28

Slide 28 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com this.$el.on('much better', yes);

Slide 29

Slide 29 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com this.model.on('doesnt matter’, no);

Slide 30

Slide 30 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com this.listenTo( this.model, 'much better’, yes );

Slide 31

Slide 31 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com onRender: function() { $(window).on( 'resize.' + this.cid , _.throttle(this.resizeCallback, 50) ); }, ! onClose: function() { $(window).off('.' + this.cid); },

Slide 32

Slide 32 text

+Pre-load data Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Blueprint = window.Blueprint || {}; Blueprint._config = ...; Blueprint._current_user = ...; <?php if (isset($preload)): ?> Blueprint._preload = <?php echo json_encode($preload); ?>; <?php endif; ?>

Slide 33

Slide 33 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com /** * @param {Backbone.Model} model Model object to fill * @param {Function} identifier Takes 2 args: model, preload * @param {Function} success Triggers on successful preload or successful fetch * @param {Function} error Triggers on failed fetch */ preloadOrFetchModel: function(model, identifier, success, error) { if (Util.hasLocalPreloadData()) { var preload = Util.getLocalPreloadData() , preloadData = identifier(model, preload); ! if (preloadData) { model.set(preloadData, {silent: true}); success(); return; } } ! model.fetch({ success: success , error: error }); }

Slide 34

Slide 34 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com R.js

Slide 35

Slide 35 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Same Dev Architecture

Slide 36

Slide 36 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com

Slide 37

Slide 37 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com Single HTTP Request Single Cached File

Slide 38

Slide 38 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com ({ baseUrl: '../public/js', name: "vendor/almond", include: ["main"], mainConfigFile: "../public/js/main.js", out: "../public/js/blueprint.min.js", findNestedDependencies: true, ! preserveLicenseComments: false, ! inlineText: true, pragmasOnSave: { excludeHbsParser : true, excludeHbs: true, excludeAfterBuild: true } })

Slide 39

Slide 39 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com

Slide 40

Slide 40 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com define('hbs!template/blueprint/toolbar/loggedout',['hbs','Handlebars'], function( hbs, Handlebars ){ var t = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) { this.compilerInfo = [4,'>= 1.0.0’]; helpers = this.merge(helpers, Handlebars.helpers); var buffer = ""; ! ! buffer += "\n\n\n\n"; return buffer; }); Handlebars.registerPartial('template_blueprint_toolbar_loggedout', t); return t; });

Slide 41

Slide 41 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com //>>excludeStart('excludeHbsParser', pragmas.excludeHbsParser) ... //>>excludeEnd('excludeHbsParser')

Slide 42

Slide 42 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com ({ baseUrl: '../public/js', name: "vendor/almond", include: ["main"], mainConfigFile: "../public/js/main.js", out: "../public/js/blueprint.min.js", findNestedDependencies: true, ! preserveLicenseComments: false, ! inlineText: true, pragmasOnSave: { excludeHbsParser : true, excludeHbs: true, excludeAfterBuild: true } })

Slide 43

Slide 43 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com 1.2M blueprint.js 626K blueprint.min.js 230K blueprint.js.gz 137K blueprint.min.js.gz

Slide 44

Slide 44 text

THANKS. FOR YOUR ATTENTION Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com

Slide 45

Slide 45 text

Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com https://leanpub.com/u/davidsulc