pirosikick's diary

君のハートにunshift

第51回html5とか勉強会行った #html5j

第51回 HTML5とか勉強会 - connpass

パフォーマンスに関するWeb標準についてとか、Web Animation APIとかは知らなかったのでちゃんと追わないと。。。

Chrome Dev Toolsの使い方とか、やらねばやらねばと思いつつも、FluxとかRact.jsとか、 ものを作るために必要な技術の勉強を優先してしまっているので、 会社で勉強会開くとか無理やりでも時間作らないとなーと思いました。

以下、メモ

ブラウザのパフォーマンスを限界まで高める、HTMLコーディングの考え方

ブラウザのパフォーマンスを限界まで高める HTMLコーディングの考え方

  • 川田寛さん
  • HTML5expoerts.jpとかに書いた記事、半年くらいでレガシー化した
  • 戦略の立て方
    • Webを取り巻く環境は最近ひどくなった
      • ナビゲーション(リンク遷移)が遅い→Wifi、ネットワーク環境
      • ランタイム→クソAndroid端末
    • パフォーマンスを意識せんとアカンで!
    • 戦略で重要なこと→頑張りすぎない
      • 作り込み過ぎはエンジニアを不幸にする
      • 時間を書けるほど得られる効果は低い
    • どれくらいやりゃいいのか?
      • 「90%タイルで1秒以下」のような感じ
      • パーセンタイル
        • レアケースを取り除く
        • データの特徴みて、特定のエラー等起きてないかみる
        • ボトルネックを探す
  • 改善の方法
    • Google I/O 2014のPaul Lewis氏
    • Initial Rnnder
      • 最初のレンダリングを開始するまでの時間
      • 最初のレンダーされるまで
        • リンククリック
        • 名前解決
        • Webサーバへリクエスト
          • ここでリダイレクトされたりとかすると、
          • もう1度名前解決から
        • バッファされてブラウザへ
          • バッファサイズのデフォルトは8KBのことが多い
            • 要するに最初の8KBが大事でござる
        • 対策
          • DNSの最適化
          • リダイレクトの最適化
          • TCP/SSLの最適化
          • ファーストバイトダウンロード
            • HTMLファイル8KB分
    • Visually Complete
      • 見た目が完成している
      • Speed Indexを使え
        • Webページを表示される過程を評価
        • 結果は同じでも、途中でどこまでレンダーされてるかは重要
          • ずっと真っ白で3秒でレンダーされるよりも
          • ちょっとずつレンダーされて3秒で完成するほうが
          • UX的に優れている
      • JS, CSS, imageの最適化
        • Grunt, Gulpでやってくれる
      • Critical Rendering Path
        • 全体の対策
        • ネットワークの最適化
          • HTTP 1.1は
          • 一度に6つのDLしかできないので、
          • タグを書く順序でちょっと変わったりする
          • SPDYはもうちょっと複雑
      • Load Complete
        • 大して重要じゃないけど
        • Load後に、次のページのリソースを読み込んどくテクニックある
  • Web標準
    • Web Performance Working Group
      • public-web-perf@w3.org
      • ブラウザから情報とって最適化しよう
        • Navigation Timing, Resource Timing, User Timing
      • それらをサーバに送る → Beacon
    • Page Visibility
    • requestAnimationFrame
    • Resource Hints
      • Resource Priorities, Prefetch/Prerenderを統合

ブラウザーに優しくして、アニメーションを滑らかに

ブラウザーに優しくて、アニメーションを滑らかに

  • Brian Birtlesさん
    • Mozilla Japan
    • オーストラリアの方
    • 10年くらいアニメーションの開発に関わってる
  • アニメーションは多くの情報を伝えるが、
  • パフォーマンスが悪いと不快になる、
  • DOMツリーとレンダーツリー
    • FirefoxではFrame Tree
    • display: noneするとレンダーツリーから外れるので速くなるとか
  • スタイル決定とレイアウト(リフロウ)
    • 高さとかは相対で決まったりするのでレイアウトで決まる
    • FirefoxではReflowの時間見れる
    • リフローを避ける
      • transformを使う
      • 配置と関係ないプロパティを使う
      • font-sizeよりtransform: scale
      • 適用されているスタイルの取得もリフロー発生する
  • 描画のコスト=描画の領域x描画の重さ
    • SVGのフィルタ、box-shadowとかコスト高い
    • svg画像はiframe, objectよりimgタグで。最適化してくれるから
  • レイヤー
    • レイヤー化はブラウザが勝手にやってる
    • Firefox aboudt:config>layer.draw-borders = true
      • どこがレイヤ化されてるか可視化できる
    • will-changeプロパティでレイヤ化する
  • コンポジター上のアニメーション

部分最適化から全体最適化へ ― Webの情報品質管理手法

  • 竹洞陽一郎さん
    • 株式会社Spelldata 代表取締役社長
    • html5j パフォーマンス部部長
    • Spelldataのサイトは世界最速
    • キャリアとして低から高レイヤまで経験してる
  • SoftBank回線は勝手に画像圧縮してる
    • だいたい夜の9時から12時に高負荷で、圧縮処理が重くなる
  • パフォーマンスと情報品質の関係
  • そもそも価値のある情報を送っているか考えろ
    • 「速さ」は情報の質の1つ
    • そもそもの情報の内容が悪ければ
    • コミュニケーションという目的を達成するパフォーマンスは悪い
  • シャノンの情報理論
    • 情報源符号化定理 − 情報をどのように区切れば効率が上がるか
    • 情報路符号化定理
  • 通信路の容量を超えるスピードで情報が入ってくると処理できない
    • 誤りを減らすためにはどう送ればよいか
  • 情報エントロピー
  • 情報の分類
    • 知ってることを知ってる、知らないことを知ってる、知らないことを知らない
    • 「知らないことを知らない」を解決するのが広告
  • トピックに対して意識が高い層、低い層で「言葉」を変えないといけない
  • 情報の三要素
    • 整合性、完全性、アバウトネス
    • コンテキストに合った情報
  • 情報の価値
    • 決定を可能とする情報を提供する
    • on time(時間通りに), in time(時間内に)
  • ダイレクトメールをもっとも活用してるのはGoogle
  • 「情報は関心を消費する」ハーバート・サイモン
    • 情報を適切に配置しないとだめ
  • 選択肢が多いほど決断できない
  • 画像のコスト
    • 「1の写真は1,000言葉にまさる」ジブコーレン
    • Webは見た目の画像が多い。情報じゃない
    • 無線網は有限なので、画像は出来る限り使わない方がいい
  • まとめ
    • パフォーマンスイコール速さではない
    • 情報品質も高めて、全体最適化しよう!

テンプレートエンジンNight行った #tenight

テンプレートエンジンNight on Zusaar

Ustream.tv: ユーザー moznion: Template Engine Night, Recorded on 2014/10/17. コンピュータ

昨日行ってきたー。テンプレートエンジンいっぱいあるなーと思った(小並感)

React.jsみたいにサーバサイドレンダリングが簡単にできるとFE/BEで同じの使えるからいいなーと思ってるけど、mizchiさんがLTで言っていたように、AltJSとの相性が悪かったり、Emmetで書けるとうれしいんだけどまだそういうの無いし(たぶん。あったら教えてほしい)、とかまだまだパーツが足りないんだろうなーと思う。けど、今のところ自分はReact.jsがすごい好き。

あと、PHPならFacebookXHPがかなり良さそうだった。Facebookってすごいなーと思った(小並感)

結構長丁場で自分が知らない分野が多かったのでメモ適当です。。。

ほとんど適当なメモ

PHPのテンプレートエンジンの話

  • @uzulla
  • PHPにはいっぱいテンプレートエンジンあるけどどれ使えばいいのか?
    • 安定のタグ方式
    • HTML系は破綻しやすい
  • デザイナーが壊す問題
  • オートエスケープ重要やで
  • 次の人のことを考えて選定するべき
    • 他の人がメンテできなくなって困る
  • PHPは高機能だが、テンプレートエンジンとしてはやたら低機能
  • HTMLではないテキスト生成ならPHPはいい
  • FacebookのXHPがいいかんじらしい

仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン

Smartyつらいからテンプレートエンジン作ってる話

  • @atsumu_t 田中集さん
    • pixiv 6年目
  • そもそもPHPにテンプレートエンジンは必要なのか
    • PHPの場合、空白の除去が辛い。CSS崩れる
  • smartyの辛さ
    • スコープ独特
    • 実行速度(pixivでは
      • レスポンスタイムの半分はSmartyで消費されている
    • エスケープ処理
      • 間違えるとXSSになる可能性がありつらい
    • 構文豊富過ぎて、罠にハマってしまう
  • PIXIVの理想→高速、読み書きしやすい
  • 文脈で適切にエスケープ
  • jingu
  • 変換大変や

Scala脳がテンプレートまでコンパイルしてしまう話

Template Engines in Scala // Speaker Deck

  • @tototoshi
  • Scalaの話
  • String Interpolation
  • XML Literal
  • Lift Template
    • Playに押されてる
  • Scalate
    • 多くの記法をサポート
    • Easy to Use

Mixer2

  • わたなべさん bizreach
  • デザイナのせいにするのは甘え

テンプレートの静的解析とリファクタリング

テンプレートの静的解析とリファクタリング // Speaker Deck

Xslate開発の振り返り

Xslate振り返り // Speaker Deck

  • @gfx
    • モバイル・アプリエンジニア
    • はてな
    • 2010頃に開発開始 Xslate
  • Xslate
    • perl最速のテンプレートエンジン
    • 高速と機能が両立しないというのを否定したった
  • ASTをコンパイル
  • 汎用・独自言語型(SmartyとかMustacheみたいな
  • 振り返り
    • Keep
      • Template-Toolkitより100倍高速
      • 値の型でエスケープするか決定
      • PSGIだけを考えて入出力を単純化した
    • Problem
      • 速度にこだわりすぎて実装が難解になった
        • メンテ辛い
        • perlのバージョンアップのたびに壊れる
    • Try(もしテンプレエンジン作る機会あるなら
      • 純粋にホスト言語で実装する
      • プロファイラ
    • hamlはコピペで崩れる。もっといいhamlほしい。

LTタイム

Thymeleaf

  • @eiryu
  • Thymeleaf
  • th:hrefみたいな感じで属性書くと処理される
    • hrefと併用して書いておけばデザイナうれしい

JVMでテンプレートに迷っているあなたに伝えたい

I wanna tell you about "Groovy Template" // Speaker Deck

  • 吉田さん @grimrose
    • 横浜から来たよん
  • Groovy

仮想DOM

仮想DOMテンプレーティング概念 // Speaker Deck

  • @mizchi − JS SPA
  • そもそもHTML→木構造が遅いからどうやっても遅い
  • 仮想DOM
  • ReactはJSXがねーAltJSと相性悪いねー
  • パラダイムチェンジだけど、まだパーツが足りない

D言語の話

jRuby + JavaFX + fxmlでアプリ作ったら地獄だった

  • せみやさん
  • ローカルで動くexe作りたかった

#

  • @ssig33
  • PR&レビューがコスト高いよねー

Razor

Slimテンプレエンジン多すぎ問題

  • @katryo
  • FEとBEで2つ使ってるのおかしくない?
  • 管理コスト・学習コスト無駄じゃない?
  • 人気あるやつ使おう

marionette

  • スク水ドリブンさん
  • _.mixin
  • _.template
    • ひどい実装
    • stack traceで負えない
  • Hogan速い

IME確定前の入力内容をngModelで取得する

ngModelはIME入力確定後に入力内容が変数に反映される。確定前の「はてn」みたいな入力途中の内容は取得できない。

確定前の内容も反映したいときに、上記のようなDirectiveを作るのもありだが、Angular1.3からngModelOptionsが導入され、updateOnでngModelの更新イベントを指定できるようになったので、

<!-- inputイベント発生時にngModelを更新する -->
<input type="text" ng-model="text" ng-model-options="{ 'updateOn': 'input' }">

これで簡単にできる!、、、かと思いきや、上記でも確定後更新となってしまう。。

バグかなーと思いソースを読むとこのあたりIME入力開始〜確定(compositionstartイベントからcompositionendイベントまで)まで更新をストップする処理が書かれている。1.2.2から導入されていて、意図はここに書いていた。

ngModelは(かなり大まかにだけど。。。)、①inputイベントで入力内容を監視、一時的に内部の変数に保持し、②updateOnで指定されているイベント発生、③ngModelで指定されている変数にその内部変数の値をコピーする、という流れになっていて、「一時的に内部の変数に保持」のところがそもそも更新されていないのでupdateOnで指定しても動作しない。

Directiveを使わない解決方法

下記のように特定のinputだけ、compositionstartイベントとcompositionendイベントをstopImmediatePropagationでストップすれば、Directiveを作らずに問題を解決できるのでおすすめや!!

<!doctype html>
<body ng-app="App">
  <p>{{ text }}</p> 
   
  <input type="text" ng-model="text" class="disabled-composition-events">
  
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>

  <script>
     angular.module('App', [])
      .run(function () {
        
        // compositionstart, compositionendをストップする
        angular
          .element('.disabled-composition-events')
          .on('compositionstart compositionend', function (e) {
            e.stopImmediatePropagation();
          });
        
      });
  </script>

</body>

Atomの.atomの.gitignore

最近、VimからAtomに乗り換えようと自宅・会社で触ってる。

で、PackageとかSnippetとか結構追加したので、そろそろ設定をgithubで管理しようと~/.atomを覗いたのだが、どれをコミットすればよいかわからなかったので調べた。

Adding Atom to Your Dotfiles · Splitting Atoms

↑記事をどれくらい信用していいかはわからないけど、下記をコミットしろとのこと。

  • config.cson
  • init.coffee
  • keymap.cson
  • snippets.cson
  • styles.less

packages/storage/は保存しなくてもいいから、.gitignoreに入れてね☆、だってよ。

なので、.gitignoreは、こんな感じにした。

# https://github.com/pirosikick/dot-atom/blob/master/.gitignore
.DS_Store
.node-gyp
packages/
storage/
compile-cache/

config.jsonにはuserIdなど一見センシティブな値が格納されているが、それらはハッシュ化されているので問題無いですよーみたいなことも書いている。

Should I publish my userId? · Issue #7 · atom/exception-reporting · GitHub

Should I publish my userId? · Issue #18 · atom/metrics · GitHub

Angularのservice, factory, providerの使い分け #scripty01

SCRIPTY#1 〜フロントエンド紳士・淑女のための勉強会〜 - connpass

「Angular.jsとThree.jsを一緒に使った時の話」というタイトルでLTしました。 資料とかは後日会社のブログにて公開されるのでもう少々お待ちください。

で、自分の発表の時に「service, factory, providerをどう使い分けているか」という質問があって、なんかうまく回答できたか自信がなかったのと、ちょっと間違ったことを言ってしまったので、ここで補足したいと思います。

単純な違い

Service

angular.module('App')

// exampleをserviceで定義
.service('example', function () {
  this.methodA = function () {
    console.log('call methodA!!');
  }
})

// exampleをInjectする
.controller('Ctrl', ['example', function (example) {
  example.methodA(); // 'call methodA!!'とコンソールに出力される
}]);

Factory

  • .factory()に渡した関数を実行した返り値がDIされる
angular.module('App')

// exampleをserviceで定義
.factory('example', function () {

  function Example() { ... }
  
  Example.prototype.methodA = function () {
    console.log('call methodA!!');
  }
  
  // これがcontrollerや他のserviceにInjectされる
  return new Example()
})

// exampleをInjectする
.controller('Ctrl', ['example', function (example) {
  example.methodA(); // 'call methodA!!'とコンソールに出力される
}]);

Provider

  • factory, serviceと大きく違うのがconfigブロックに渡せること
    • configブロックはアプリケーション開始前に実行される
    • configブロックでproviderのプロパティの変更ができる
  • providerの$getを実行した返り値がDIされる
angular.module('App')

// exampleをproviderで定義
.provider('example', function () {

  // 外に晒す設定値
  this.options.message = 'call method of example.';
  
  // こいつの返り値がcontrollerや他のserviceにInjectされる
  this.$get = function () {
  
    var message = this.options.message;

    // これがInjectされる
    return {
      methodA: function () {
        console.log(message);
      }
    }
  }
})

// configブロックで使う場合、
// サービス名 + ProviderでInjectする。
// 今回の場合、example + Provider = exampleProvider
.config(['exampleProvider', function (exampleProvider) {

  // 設定値をいじり挙動を変えることができる
  exampleProvider.options.message = 'change behavior of methodA.';

}])

// exampleをInjectする
.controller('Ctrl', ['example', function (example) {
  example.methodA(); // 'change behavior of methodA.'とコンソールに出力される
}]);

使い分け

provider

  • 外部に公開するライブラリなど、再利用性を高くしたい場合にproviderを使う
    • 利用者によって設定を変更し挙動を変える必要がある場合など
    • $httpもproviderで定義されていて、headerのデフォルト値などが変更可能
    • ngモジュールのproviderを見るとどういうところで使うべきがだいたいわかるかも
    • 公式の見解
      • providerがコアで、service, factory, value, constantはproviderのシンタックスシュガーである
      • providerは冗長&多くの機能があるが、
      • providerを使うのがoverkillになってしまうケースが多いだろう

serviceとfactory

  • .service.factoryについては「これだ!」っていう理由が無い限り、
  • シンプルな.serviceで定義すればいいんじゃないかと思う。
これだ!っていう理由
  • Angularの外で定義しているクラスとかをそのままインスタンス化して使いたい
  .factory('example', function () {
    // Angularの外で定義しているクラスをそのまま返す
    return new OutOfAngularWorldClass();
  })
  • valueに依存関係がほしい、または初期化関数が欲しい場合
  // .valueは第2引数がそのままInjectされる
  .value('apiKey', 'XXXXXXX')

  // 依存関係がほしい&初期化したい
  .factory('apiKey', ['otherService', function (otherService) {
    // 例えば別のサービスの値や関数を使って初期化して返す
    return otherService.someValue + 'XXXXXXX';
  }]);

注意点

provider, factory, serviceともにシングルトンになっていて、生成後は内部でキャッシュされる。 なので下記のようなfactoryは最初にInjectされたタイミングで生成された値で固定されてしまう

.factory('randomValue', function () {
  // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
  var guid = (function() {
    function s4() {
      return Math.floor((1 + Math.random()) * 0x10000)
                .toString(16)
                .substring(1);
    }
    return function() {
      return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
            s4() + '-' + s4() + s4() + s4();
    };
  })();
  
  return guid();
});

Angular2.0でどうなるか

今日のQ&Aの時に「2.0ではfactory, serviceはなくなるかも」と言いましたが、あれは自分の記憶違いでした。 ごめんなさい。。。

正確には、

  • .config, .constant, .providerが廃止され
  • .constant.valueに一本化、
  • .providerは下記のように.configブロックではなく.valueで設定値の変更が可能になる
  module.value('$http.config', {
    defaultHeaders: {
      // ...
    }
  });

でした。

2.0でDI周りがどうなるかは以前ブログに書いたのと、ここにコードと仕様があるのでそちらを見てください。(ブログの方はちょっとふるくなっているかもです)

まとめ

  • 今はAngular.jsの本が2冊も出てるのでそれを見てからやればいいと思う。
  • 公式のドキュメントが充実しているのでそちらを出来る限り見るのと、
  • derectiveに関してはngモジュールのソースを見て勉強するといいと思う

yeomanのgenerator-webappのオプションからcompassが外れたのを今更調べた

Option for Sass without Compass · Issue #302 · yeoman/generator-webapp · GitHub

Add option for Sass without Compass by kartikluke · Pull Request #315 · yeoman/generator-webapp · GitHub

PRがmergeされたのが3月で今更だけど、気になってたので調べた。

単純にcompassコンパイルが遅いから、libsassのラッパーであるnode-sassを使ったgrunt-sassを使ったら?っていう流れだったっぽい。

compass無いと困らないの?」って思ってたけど、compass/css3くらいしか使ってなかったので、それだったらautoprefixerpleeeaseでできるし、node-sass + pleeeaseでいいやーと思った。

var gulp = require('gulp');
var sass = require('gulp-sass');
var pleeease = require('gulp-pleeease');

gulp.task('sass', function () {
  gulp.src('./scss/**/*.scss')
    .pipe(sass())
    .pipe(pleeease())
    .pipe(gulp.dest('./css/'));
});

Duo.jsちょっと使ってみた #duojs

Duo - A next-generation package manager for the front-end.

ちょっと良さ気だったので調べてみた。

準備

# install duo
$ npm install -g duo

Github APIを使うらしく、duo用にAPI Tokenをここから生成し、 ~/.netrcに下記フォーマットで保存する。

# なんかGHEとかもできそうな感じがするけど調べてはいない
machine api.github.com
  login <username>
  password <生成したGithubのapi token>

これで準備完了。

使う

var uid = require('matthewmueller/uid');
var fmt = require('yields/fmt');

var msg = fmt('Your unique ID is %s!', uid());
window.alert(msg);

上記サンプルコードをindex.jsで保存し、

$ duo index.js > bundle.js

と実行すると、matthewmueller/uidyeilds/fmtGithubから持ってきてくれてbundle.jsに出力してくれる。

css@importに書いているの引っ張ってきてくれて挿入してくれる。

// https://github.com/necolas/normalize.css/
@import 'necolas/normalize.css';

component.jsonpackage.jsonで管理されているリポジトリrequire("github-account/repository-name")だけでOKみたい。

Bowerはbower.jsmainを指定していても、:index.jsみたいに更にどのファイルを読み込むかを指定しないといけなかった。(BowerはcommonJS前提じゃないからだろうなーたぶん)

// https://github.com/mrdoob/three.js
// bower.json有り、mainはbuild/three.min.js
// three.jsはcommonJS対応されてる

// ビルドはエラー無く終了するが、ブラウザでエラー
var THREE = require('mrdoob/three.js@r68'); // Uncaught Error: cannot find module "mrdoob/three.js@r68"

// どこにmainファイルが有るか指定してあげるとうまくいく
var THREE = require('mrdoob/three.js@r68:build/three')

さらっと書いたけど、バージョンはrequire("hoge/hoge@バージョンタグ")で指定。

ローカルのJS, HTML, JSONもrequireできる

// 同じディレクトリにあるlocal.jsもしくは、local/index.js
var local = require('./local');

// HTMLはStringとして
var template = require('./template.html');

// jsonはJavaScriptのオブジェクトとして
var json = require('./data.json');

感想

  • browserify勉強しなきゃ−と思ってたけど、Duoのほうがシンプルで良さそう
  • バージョン指定、パス指定はどうなんだろうかと思った。

browserify、Webpack、componentをもうちょっと使ってみてもう1度考えたい。