Frontend'in
Gölgelerde Yaşayan Efendisi


Google Closure Tools

Armağan Amcalar

The Frontiers:Mini, Istanbul
20 Haziran 2015

Ben Kimim?

Armağan Amcalar
Startup Kitchen Kurucu Ortak, Baş Yazılım Mimarı
Lonca Kurucu, Kethüda

hobi projeleri

pedals.io
trax.io

Problem

Önyüz uygulama geliştirme yöntemleri yetersiz
Her yeni çatı aynı problemi başka bir şekilde çözmeye çalışıyor

 

Mevcut çözümler temel alınmıyor

 

NIH (not invented here) sendromu hüküm sürüyor

Tarihçe

Dinamik önyüz uygulamalarına izin veren yapı XmlHttpRequest

Microsoft icadı

İlk geniş çaplı uygulamalar
GMail ve Google Maps

Closure Tools?

Google ne kullanıyor?

AngularJS?

Nerelerde kullanıyor?

Search
Gmail
Maps
Docs
Sites

Books
Blogger
Calendar
Google+
Photos

Google Closure Tools

Google'ın en zor uygulamaları için tercihi

2009'dan beri tamamen açık kaynaklı

Yazılım geliştirme döngüsü için baştan sona çözüm

 

Dart, TypeScript, RequireJS, AMD, browserify, grunt, gulp, webpack, SASS, LESS, jade, handlebars, JSHint, JSLint öldürücü.
2009'dan beri.

Y U

NO USE CLOSURE?

İçindekiler

Closure Compiler

Closure Library

Closure Linter

Closure Templates

Closure Stylesheets

Closure Compiler

Klasik anlamda bir derleyici

​Java uygulaması, web uygulaması ya da REST API

Modüler geliştirmeye olanak sağlar

Modül bağımlılıklarını otomatik çözer, modülleri birleştirir

Ölü kodları temizler

Kodu optimize eder

Closure Compiler

Garip JavaScript hatalarına karşı uyarır

Kodu minimize eder (minification)

Okunmaz hâle getirir (obfuscation)

Sentaks kontrolü yapar

Tip kontrolü yapar

Tip-güvenli (type-safe) geliştirmeye olanak sağlar!

Closure Library

Anotasyonlar ile Nesne Tabanlı Programlamaya klasik yaklaşım (sınıflar, arayüzler, kalıtım, gizli değişkenler)

Java benzeri kod tarzı

Modül tabanlı mimari

Olay güdümlü (event-driven) bileşen (component) mimarisi

IE6'da bile çalışan mükemmel performans

Çok geniş kütüphane

UI bileşenleri, DOM manipülasyonları, sunucu iletişimi, animasyon, vektörel programlama, lineer cebir, veri yapıları, birim test altyapısı, i18n altyapısı, vs.

Closure Library

Otomatik bağımlılık yönetimi

Okunabilir kod yazmayı sağlar

Kaynak kodu okunabilir

Dokümentasyonu az

Örnekleri az

Komünitesi az

Closure Library neye benzer?

goog.ui.MenuButton = function(content, opt_menu, opt_renderer, opt_domHelper) {
    var renderer = opt_renderer || goog.ui.MenuButtonRenderer.getInstance();
    goog.base(this, content, renderer, opt_domHelper);

    // Menu buttons support the OPENED state.
    this.setSupportedState(goog.ui.Component.State.OPENED, true);

    if (opt_menu) {
        this.setMenu(opt_menu);
    }

    /** @private {goog.Timer} */
    this.timer_ = new goog.Timer(500);
};
goog.inherits(goog.ui.MenuButton, goog.ui.Button);
goog.provide('tart.ui.NavBarComponent');
goog.require('tart.ui.DlgComponent');

/**
 * Includes back button for back navigation.
 *
 * @constructor
 * @extends {tart.ui.DlgComponent}
 *
 * @param {tart.ui.NavBarComponent.NavBarOptions=} opt_config Config parameters
 *        to include things like title.
 */
tart.ui.NavBarComponent = function(opt_config) {
    goog.base(this);

    this.config = opt_config || {};

    this.hasBackButton = this.config.hasBackButton || this.hasBackButton;
    this.hasMenuButton = this.config.hasMenuButton || this.hasMenuButton;
};
goog.inherits(tart.ui.NavBarComponent, tart.ui.DlgComponent);

/**
* @typedef {{hasBackButton: boolean, hasMenuButton: boolean, title: string}}
*/
tart.ui.NavBarComponent.NavBarOptions;
/**
 * Defines whether the back button is visible.
 *
 * @type {boolean}
 */
tart.ui.NavBarComponent.prototype.hasBackButton = false;

/**
 * Menu button tap event handler. Delegates event handling to subclasses via
 * menuButtonHandler method.
 *
 * @return {number} Returns executing menuButtonHandler if available, or zero.
 */
tart.ui.NavBarComponent.prototype.onMenuButtonTap = function() {
    if (this.menuButtonHandler) return this.menuButtonHandler();

    this.vm.toggleSidebar();
    return 0;
};

/**
 * @enum {string} Dom mapping.
 */
tart.ui.NavBarComponent.prototype.mappings = {
    BACK_BUTTON: 'back-button',
    MENU_BUTTON: 'menu-button'
};

Closure Library

İlk başta biraz zor geliyor ama zamanla alışıyorsun...

Closure Linter

Düzenli ve tutarlı kod yazmaya yardımcı olur

Google JavaScript Biçim Rehberi'ni uygular

JSDoc anotasyonlarını kontrol eder

Basit hataları otomatikman düzeltir

Closure Compiler ile uyumlu çalışır

 

Kafanız rahat eder!

Closure Linter

$ gjslint path/to/my/file.js
----- FILE  :  path/to/my/file.js -----

Line 46, E:0110: Line too long (87 characters).
Line 54, E:0214: Missing description in @return tag
Line 66, E:0012: Illegal semicolon after function declaration
Line 150, E:0120: Binary operator should go on previous line "+"
Line 175, E:0011: Missing semicolon after function assigned to a variable
Line 210, E:0121: Illegal comma at end of array literal
Line 220, E:0002: Missing space before ":"

$ fixjsstyle path/to/my/file.js

Fixed 10 errors in path/to/my/file.js

Closure Templates

Önyüz (JavaScript) ve arkayüz (Java) için template sistemi

Kolay ve okunabilir template oluşturma

Önden derleme ile maksimum performans

i18n altyapısı

XSS koruması

{namespace soy.examples.simple}

/**
 * Says hello to a person.
 * @param name
 */
{template .helloName}
    {msg desc="Says hello to a person."}
      Hello {$name}!
    {/msg}
{/template}

/**
 * Says hello to everyone.
 * @param names
 */
{template .helloNames}
    {foreach $name in $names}
        {call .helloName}
            {param name: $name /}
        {/call}
        {if not isLast($name)}
            <br>  // break after every line except the last
        {/if}
    {/foreach}
{/template}

Closure Templates çıktısı

/**
 * @fileoverview Templates in namespace soy.examples.simple.
 */

if (typeof soy == 'undefined') { var soy = {}; }
if (typeof soy.examples == 'undefined') { soy.examples = {}; }
if (typeof soy.examples.simple == 'undefined') { soy.examples.simple = {}; }

soy.examples.simple.helloName = function(opt_data, opt_ignored) {
  return 'Hello ' + soy.$$escapeHtml(opt_data.name) + '!';
};

soy.examples.simple.helloNames = function(opt_data, opt_ignored) {
  var output = '';
  var nameList10 = opt_data.names;
  var nameListLen10 = nameList10.length;
  for (var nameIndex10 = 0; nameIndex10 < nameListLen10; nameIndex10++) {
    var nameData10 = nameList10[nameIndex10];
    output += soy.examples.simple.helloName({name: nameData10}) + 
      ((! (nameIndex10 == nameListLen10 - 1)) ? '<br>' : '');
  }
  return output;
};

Closure Stylesheets

CSS için değişken, fonksiyon, mixin vs. desteği sağlar

CSS'leri birleştirir, optimize eder

CSS tarz kontrolü yapar

CSS'yi küçültür (minification)

Okunmaz hâle getirir (obfuscation)

Closure Stylesheets

@def NAV_WIDTH    180px;
@def NAV_PADDING  3px;

.nav {
  position: absolute;
  width: NAV_WIDTH;
  padding: NAV_PADDING;
}

.content {
  position: absolute;
  margin-left: add(NAV_PADDING,
                   NAV_WIDTH,
                   NAV_PADDING);

}
.nav {
  position: absolute;
  width: 180px;
  padding: 3px;
}
.content {
  position: absolute;
  margin-left: 186px;
}
.nav

 

.content

 

Closure Stylesheets

{namespace example}

/**
 * @param title
 */
{template .dialog}
<div class="{css dialog-content}">
  <title class="{css dialog-title}">
    {$title}
  </title>
</div>
{/template}
.dialog-content {
  padding: 10px;
}

.dialog-title {
  font-weight: bold;
}

Closure Stylesheets

.dialog-content {
  padding: 10px;
}

.dialog-title {
  font-weight: bold;
}
.a-b {
  padding: 10px;
}

.a-c {
  font-weight: bold;
}
CLOSURE_CSS_NAME_MAPPING = {
  "dialog": "a",
  "content": "b",
  "title": "c"
};

Closure Stylesheets

goog.provide('example');
goog.require('soy');
goog.require('example');

example.dialog = function(opt_data) {
  return '<div class="' + goog.getCssName('dialog-content') + '">' + 
      '<title class="' + goog.getCssName('dialog-title') + '">' + 
      soy.$$escapeHtml(opt_data.title) +
      '</title></div>';
};
example.dialog = function(opt_data) {
  return '<div class="a-b">' +
      '<title class="a-c">' + soy.$$escapeHtml(opt_data.title) + '</title>' + 
      '</div>';
};

Sonuç

Web'in en performanslı kütüphanesi

Bütün bileşenlerin bir arada olduğu en kapsamlı çözüm

2009'dan beri yayında!

tartJS

2011'den beri açık kaynaklı

Google Closure üzerine inşa edildi

Modern web ve hibrit uygulamalar için,

  • iki MVC çatısı
  • iki bileşen (component) çatısı
  • bir mobil uygulama çatısı

 

Türk mühendisliği ürünü

Fork edin, PR açın, ekonomiye can verin

Referanslar

Teşekkürler!

İletişimde kalalım!

Armağan Amcalar

hello@arm.ag
twitter: @dashersw
github: dashersw
blog: arm.ag