Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pulling The Strings: Backbone.Marionette and Require.JS for Single Page Apps

Pulling The Strings: Backbone.Marionette and Require.JS for Single Page Apps

Presented at empireJS 2014 - https://www.youtube.com/watch?v=4K4JKtAGPu4

Daniel Cousineau

May 05, 2014
Tweet

More Decks by Daniel Cousineau

Other Decks in Programming

Transcript

  1. 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?
  2. 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
  3. +Divide Into Daniel Cousineau // follow me : @dcousineau or

    http://dcousineau.com UI Widgets Functional “Pages” Utilities
  4. 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; });
  5. 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(); });
  6. 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; };
  7. 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; }); });
  8. 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) { //... }); } });
  9. 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; };
  10. 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; });
  11. 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); },
  12. +Pre-load data Daniel Cousineau // follow me : @dcousineau or

    http://dcousineau.com <script> Blueprint = window.Blueprint || {}; Blueprint._config = ...; Blueprint._current_user = ...; <?php if (isset($preload)): ?> Blueprint._preload = <?php echo json_encode($preload); ?>; <?php endif; ?> </script>
  13. 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 }); }
  14. Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com <script

    src="/js/blueprint.min.js" defer></script> <script data-main="/js/main" src="/js/require.js"></script>
  15. 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 } })
  16. Daniel Cousineau // follow me : @dcousineau or http://dcousineau.com <div

    class="collapse navbar-collapse pull-right"> <ul class="nav navbar-nav"> <li class="drop-target"> <a class="noop">learn more</a> <ul class="dd-nav"> <li><a href="/about-bpr">about bpr</a></li> <li><a href="/how-it-works">how it works</a></li> <li><a href="/help-faqs">HELP / FAQ</a></li> </ul> </li> <li><a href="/log-in" …>log in</a></li> <li><a href="/create-registry" …>sign up</a></li> </ul> </div>
  17. 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<div class=\"collapse navbar-collapse pull-right\">\n <ul class=\"nav navbar-nav\">\n <li class=\"drop-target\">\n <a class=\"noop\">learn more</a>\n <ul class=\"dd-nav\">\n <li><a href=\"/about-bpr\">about bpr</a></li>\n <li><a href=\"/how-it-works\">how it works</a></li> \n <li><a href=\"/help-faqs\">HELP / FAQ<span class=\"lowercase\">s</span></a></li>\n </ ul>\n </li>\n <li><a href=\"/log-in\" data-bpr-goto=\"viewlogin\" id=\"login\" class=\"login\">log in</a></li>\n <li><a href=\"/create-registry\" data-bpr-goto=\"createregistry\" id=\"sign-up\">sign up</ a></li>\n </ul>\n</div>\n\n"; return buffer; }); Handlebars.registerPartial('template_blueprint_toolbar_loggedout', t); return t; });
  18. 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 } })
  19. 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
  20. THANKS. FOR YOUR ATTENTION Daniel Cousineau // follow me :

    @dcousineau or http://dcousineau.com