Slide 1

Slide 1 text

Arquitetura de Front-end em aplicações de larga escala @shiota | eshiota.com RAILS ED ITIO N

Slide 2

Slide 2 text

Front-end

Slide 3

Slide 3 text

Internet

Slide 4

Slide 4 text

Arquitetura simples Arquitetura complexa

Slide 5

Slide 5 text

Na minha visão, aplicações JavaScript de larga escala são aplicações não- triviais que requerem um esforço significante de manutenção por parte do desenvolvedor, onde a maior parte do trabalho de manipulação de dados e visualização é atribuída ao navegador. Addy Osmani Developer Programs Engineer @ Google

Slide 6

Slide 6 text

Aplicações com front-end de larga escala são aplicações não-triviais que requerem um esforço significante de manutenção por parte do desenvolvedor, onde organização, modularização, otimização e reutilização de código são cruciais. Eduardo Shiota Yasuda Loves cat videos on Youtube

Slide 7

Slide 7 text

Aplicações de pequena escala

Slide 8

Slide 8 text

style.css templates application.js & jQuery / plugins imagens CMS

Slide 9

Slide 9 text

CSS simples Centenas de linhas Fácil de manter

Slide 10

Slide 10 text

JS Simples Plugins e algumas funções Uma função autoexecutável jQuery

Slide 11

Slide 11 text

Aplicações de Larga escala

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

HTML, CSS e JavaScript modulares

Slide 18

Slide 18 text

Noção de módulo

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

HTML & CSS modular

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

Slide 26

Slide 26 text

Your starred content

Slide 27

Slide 27 text

Recommended contacts

Slide 28

Slide 28 text

Slide 29

Slide 29 text

/********************************** * patterns/side_list.scss **********************************/ .side-list { list-style: none outside; padding: 0; } .side-list li { margin-bottom: 10px; overflow: hidden; } /********************************** * patterns/arrowed_list.scss **********************************/ .arrowed-list li { margin-bottom: 0.2em; position: relative; } .arrowed-list li:before { content: "\25B8"; display: inline-block; margin-right: 0.3333em; }

Slide 30

Slide 30 text

/********************************** * patterns/side_block.scss **********************************/ .side-block { margin-bottom: 1.5em; } .side-block h3 { border-bottom: 1px solid #cecece; font-size: 1em; /* 16px / 16px */ margin-bottom: 0.8em; padding-bottom: 0.1em; }

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Recommended contacts

Slide 33

Slide 33 text

Slide 34

Slide 34 text

Slide 35

Slide 35 text

/********************************** * patterns/data_card.scss **********************************/ .data-card { min-height: 120px; position: relative; } /* Override width and height as needed */ .data-card > img { position: absolute; left: 0; top: 0; width: 120px; height: 120px; } /* Override padding-left as needed */ .data-card .card-content { padding-left: 140px; }

Slide 36

Slide 36 text

/*************************************** * patterns/small_entity_list.scss * * children extend patterns/data_card ***************************************/ .small-entity-list .data-card { min-height: 60px; } .small-entity-list .data-card > img { width: 60px; height: 60px; } .small-entity-list .data-card .card-content { padding-left: 80px; }

Slide 37

Slide 37 text

.button .large-button .confirm-button .send-button

Slide 38

Slide 38 text

.button { border-radius: 5px; font-family: "proxima-nova", sans-serif; height: 2em; line-height: 2em; padding: 1em; color: #fff; text-shadow: 0 -1px 0 #000; } .large-button { font-size: 3em; } .confirm-button { background: #ffba00; box-shadow: 0 3px 0 #cd9600; } .send-button { /* styles for icon placement */ }

Slide 39

Slide 39 text

.button .large-button .confirm-button .send-button

Slide 40

Slide 40 text

.button .small-button .confirm-button .send-button

Slide 41

Slide 41 text

Multiple classes + Single responsabilities Short inheritance (3-4 levels max) Portable classes

Slide 42

Slide 42 text

Organizando os módulos

Slide 43

Slide 43 text

/* * application.css example w/ Asset Pipeline * *= require base/reset *= require core/typography *= require core/forms *= require_tree ./patterns *= require ui/buttons *= require ui/loader *= require ui/datepicker */

Slide 44

Slide 44 text

application.scss w/ SASS

Slide 45

Slide 45 text

base/_functions.scss

Slide 46

Slide 46 text

core/_typography.scss

Slide 47

Slide 47 text

ui/_loader.scss

Slide 48

Slide 48 text

application-ec8971025292ecb7dd2c99d430d7a76e.css

Slide 49

Slide 49 text

Leituras

Slide 50

Slide 50 text

oocss.org

Slide 51

Slide 51 text

smacss.com

Slide 52

Slide 52 text

JavaScript modular

Slide 53

Slide 53 text

JavaScript não é (só) jQuery

Slide 54

Slide 54 text

shareTypeSelector.js shareForm.js shareField.js newsfeed.js

Slide 55

Slide 55 text

shareForm shareTypeSelector shareField mediator.js trigger("share- type-changed") on("share-type-changed") shareProxy newsfeed on("new-post") trigger("new-post") init init submit get data onsuccess

Slide 56

Slide 56 text

Modules + Tests = OMGBBQW00T

Slide 57

Slide 57 text

/** Loader constructor @params {Function} placement Function that determines the loader's placement @constructor **/ ns("EDEN.ui.Loader", function (placement) { if (!(this instanceof EDEN.ui.Loader)) { return new EDEN.ui.Loader(placement); } this.frame = 1; this.framesQty = 8; this.stack = []; this.animating = false; this.$loader = $("
"); this.$renderer = this.$loader.find("b"); this.placement = placement; this.init(); });

Slide 58

Slide 58 text

/** Animation speed (in frames per second) @property fps @type Number @default 20 **/ EDEN.ui.Loader.prototype.fps = 20; /** Fading speed @property fadeSpeed @type Number @default 150 **/ EDEN.ui.Loader.prototype.fadeSpeed = 150;

Slide 59

Slide 59 text

/** Inits the loader by inserting it into the DOM. If a placement argument wasn't passed to the constructor, uses a generic placement. @method init **/ EDEN.ui.Loader.prototype.init = function () { if (!this.placement) { this.placement = function ($loader) { $loader.appendTo($("body")); }; } this.placement.call(this, this.$loader); };

Slide 60

Slide 60 text

/** Starts the loader by fading in and starting the animation. If there are multiple processes, stacks the requests. @method start **/ EDEN.ui.Loader.prototype.start = function () { this.stack.push((new Date()).getTime()); if (this.stack.length === 1) { this._startAnimation(); } }; /** Stops the loader by fading out and stoping the animation If there are any processes pending, pops the requests until it can actually stop. @method stop **/ EDEN.ui.Loader.prototype.stop = function () { this.stack.pop(); if (!this.stack.length) { this._stopAnimation(); } };

Slide 61

Slide 61 text

/** Starts the loader animation @private **/ EDEN.ui.Loader.prototype._startAnimation = function () { this.animating = true; this._renderAnimation(); }; /** Stops the loader animation @private **/ EDEN.ui.Loader.prototype._stopAnimation = function () { this.animating = false; };

Slide 62

Slide 62 text

/** Loops the animation, calling itself according to the fps @private **/ EDEN.ui.Loader.prototype._renderAnimation = function () { if (!this.animating) { return true; } this._draw(); setTimeout(this._renderAnimation.bind(this), 1000 / this.fps); }; /** Draws the animation @private **/ EDEN.ui.Loader.prototype._draw = function () { this.$renderer.removeClass().addClass("f" + this.frame); this.frame = this.frame + 1 > this.framesQty ? 1 : this.frame + 1; }; /** Returns the animation stack. @return Array @private **/ EDEN.ui.Loader.prototype._getAnimationStack = function () { return this.stack; };

Slide 63

Slide 63 text

não achei um logo maior :(

Slide 64

Slide 64 text

it("appends the loader to body as a default", function () { var loader = new Loader(); expect($("body").find(".loader").length).toEqual(1); }); it("appends the loader through an argument function", function () { var loader = new Loader(function ($loader) { $("#loader-placeholder").append($loader); }); expect($("#loader-placeholder").find(".loader").length).toEqual(1); }); it("stops the animation if stack is empty", function () { loader.start(); loader.stop(); expect($(".loader").data("spinning")).not.toBeTruthy(); });

Slide 65

Slide 65 text

it("renders the animation at default speed (20fps)", function () { jasmine.Clock.useMock(); spyOn(loader, "draw"); loader.start(); jasmine.Clock.tick(2000); // The first renderAnimation call renders the first frame, and then // starts the frame counting. So it'll always be (fps * seconds) + 1 expect(loader.draw.calls.length).toEqual(41); });

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

jasmincerice + guard-jasmine + PhantomJS + Jenkins = OMGWTFBBQW00TROFL

Slide 69

Slide 69 text

github.com/bradphelan/jasminerice/

Slide 70

Slide 70 text

github.com/netzpirat/guard-jasmine

Slide 71

Slide 71 text

phantomjs.org

Slide 72

Slide 72 text

Jenkins » rake guard:jasmine

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

SOLID principles Loose coupling » Portable Testable MV**

Slide 75

Slide 75 text

Organizando os módulos

Slide 76

Slide 76 text

// application.js with Asset Pipeline // //= require jquery //= require jquery_ujs //= require jquery/jquery.inputmask //= require jquery/jquery.validate //= require jquery/jquery.uniform //= require i18n //= require i18n/translations //= require i18n/setLocale //= require_tree shims //= require tools/namespace //= require accounting //= require handlebars-1.0.0.beta.6 //= require eden/events //= require eden/dispatcher //= require eden/appMediator //= require_tree ./jquery //= require_tree ./eden/ui //= require_tree ./eden/presenters //= require_tree ./eden/validators //= require ./eden/forms/SubmitButton //= require_tree ./eden/forms //= require_tree ./eden/components //= require_tree ./eden/views //= require_tree ./eden/proxies //= require_tree ./eden/commands //= require_tree ./eden/services //= require_tree ./eden/modules //= require eden/app

Slide 77

Slide 77 text

documentcloud.github.com/jammit/

Slide 78

Slide 78 text

requirejs.org

Slide 79

Slide 79 text

//my/shirt.js now has some dependencies, a cart and inventory //module in the same directory as shirt.js define(["./cart", "./inventory"], function(cart, inventory) { //return an object to define the "my/shirt" module. return { color: "blue", size: "large", addToCart: function() { inventory.decrement(this); cart.add(this); } }; } );

Slide 80

Slide 80 text

github.com/jwhitley/requirejs-rails

Slide 81

Slide 81 text

Leituras

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

addyosmani.com/largescalejavascript

Slide 84

Slide 84 text

addyosmani.github.com/todomvc/

Slide 85

Slide 85 text

Ferramentas para manter a organização

Slide 86

Slide 86 text

github.com/cowboy/grunt

Slide 87

Slide 87 text

html5boilerplate.com

Slide 88

Slide 88 text

compass-style.org

Slide 89

Slide 89 text

Exemplos com compass

Slide 90

Slide 90 text

Geração de sprites

Slide 91

Slide 91 text

/* Attributes a sprite map to a variable */ $icon-sprite: sprite-map("icon/*.png", $spacing: 16px, $repeat: no-repeat, $layout: vertical);

Slide 92

Slide 92 text

$icon-sprite: sprite-map("icon/*.png", $spacing: 16px, $repeat: no-repeat, $layout: vertical);

Slide 93

Slide 93 text

/* Compass sprite function receives the map variable and image as arguments */ background: sprite($icon-sprite, arrow_dropdown) no-repeat; /* Compiled CSS */ background: url(/assets/icon-s5dab8c2901.png) -40px -158px no-repeat;

Slide 94

Slide 94 text

Inline images - base64

Slide 95

Slide 95 text

/* Generates a base64 image */ background: #f5f3eb inline-image("bg_dots.png") repeat; /* Compiled CSS */ background: #f5f3fb url('data:image/ png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAMAAAAcVM5PAAAAGXRFWH RTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAlQTFRF5+TW//////// 4qZUpQAAAAN0Uk5T// 8A18oNQQAAACBJREFUeNpiYGBgAgMGBkYog4mJXAbILAiDkVxzAAIMAEMOAPMId2O WAAAAAElFTkSuQmCC') repeat;

Slide 96

Slide 96 text

Vendor prefixes

Slide 97

Slide 97 text

.my-gradient { background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -moz-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -ms-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -o-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); }

Slide 98

Slide 98 text

.my-gradient { background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -moz-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -ms-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -o-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); }

Slide 99

Slide 99 text

/* Generates vendor-prefixed rules */ .my-gradient { @include background-image( linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)) ); } /* Compiled CSS */ .my-gradient { background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -moz-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -ms-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: -o-linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); background-image: linear-gradient(right, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0)); }

Slide 100

Slide 100 text

Resumindo

Slide 101

Slide 101 text

Modules, motherf*cker.

Slide 102

Slide 102 text

Aprenda JavaScript.

Slide 103

Slide 103 text

Use ferramentas e frameworks. <3

Slide 104

Slide 104 text

Se você chegar nesse ponto...

Slide 105

Slide 105 text

No content

Slide 106

Slide 106 text

DOUBLE RAINBOW ALL THE WAY OMG SO INTENSE

Slide 107

Slide 107 text

No content

Slide 108

Slide 108 text

Thanks! @shiota | eshiota.com