コーディング環境 (2014.08)

日々進化している最近のコーディング (フロントエンド開発) 環境について、
ここ1年くらいのノウハウを詰めて、
極端には新しいもの好きではない視点で整理します。

目次:
1. psdからのスライス
2. Compass
3. スプライトイメージの自動化
4. CoffeeScript
5. Gruntによる自動化
6. ローカルサーバー
7. その他

1. psdからのスライス

slicy

Slicyというアプリを使い始めてからは、ずっとこれです。
Photoshopのレイヤーやグループ名に画像のファイル名(+拡張子)を付けることで、
ワンクリックで画像を書き出せます。

ファイル名に@2xと付けることで、Retina用画像(@2x)と、
等倍画像を同時に書き出すこともできます。

その他に@boundsというレイヤーをつくって矩形領域を指定したり、
@slicesというフォルダをつくって、その中にファイル名と
領域指定用のレイヤーをつくることも出来ます。

公式サイトのヘルプを読んだり、
サンプルをダウンロードすると理解が早いです。

 

2. Compass

CSSにネスト構造をつくって記述できるフレームワーク。
インストールの方法などは公式ドキュメント参照。
このエントリーでは、”gem install compass –pre” でインストール出来る、
Compass 1.0.0.rc.1を使って、SCSSの文法で書いています。

必要なコマンドは
compass watch

 

3. スプライトイメージの自動化

Compassのmixinを使えば、関数や変数を使ってCSSを記述できます。
一番の恩恵として、スプライトイメージの生成の自動化について、
色々試行錯誤した結果、現時点で使っているmixinを紹介します。
参考: Using Compass Generated Sprite Sheets in Responsive Sass, by Jayson Jacobs.

・サーバーにアップするファイルはassetsフォルダにまとめる
・サーバーにアップしないファイルはsourceフォルダにまとめる
・Source Mapを有効にするとChromeでscssファイルのデバッグができる
参考: Working with CSS Preprocessors – Google Chrome
・ロゴ用の画像として、
/resource/images/sprite/logo.png
/resource/images/sprite_2x/logo_2x.png (2倍サイズ)
の2枚が用意されているとする。

config.rb

css_dir = "assets/css"
sass_dir = "source/sass"
images_dir = "source/images"
generated_images_dir = "assets/images"
javascripts_dir = "assets/js"
fonts_dir = "assets/fonts"
output_style = :nested
relative_assets = true
line_comments = true
preferred_syntax = :scss
sass_options = { :sourcemap => true }

HTML

<div class="logo">
<div class="sprite">Logo</div>
</div>

→ .sprite部分に、background-imageが適用される

scssファイル

// スプライト画像
.sprite {
display: block;
overflow: hidden;
background-repeat: no-repeat;
text-align: left;
text-indent: -10000px;
font-size: 1px;
line-height: 1px;
}

@mixin sprite-background($sprites, $sprites-img, $name, $scale, $skip-base-params:false) {
background-image: $sprites-img;
@include background-size(image-width(sprite-path($sprites)) / $scale auto);

//retina時に重複するパラメータをスキップするための分岐
@if not($skip-base-params){
height: image-height(sprite-file($sprites, $name)) / $scale;
width: image-width(sprite-file($sprites, $name)) / $scale;
$ypos: nth(sprite-position($sprites, $name), 2) / $scale;
background-position: 0 $ypos;
}
}

$sprites: sprite-map("sprite/*.png", $spacing: 2px);
$sprites-img: sprite-url($sprites);
$sprites_2x: sprite-map("sprite_2x/*.png", $spacing: 4px);
$sprites-img_2x: sprite-url($sprites_2x);

@mixin sprite-image ($name) {
.sprite {
@include sprite-background($sprites, $sprites-img, $name, 1);
}
.backgroundsize.retina_2x & {
.sprite {
@include sprite-background($sprites_2x, $sprites-img_2x, $name, 2, true);
}
}
}

→ /assets/images/ フォルダ内にスプライトイメージが書き出される。

 

また、Slicyからの作業の効率化を考えて、一つ、自作のRubyのスクリプトを使っています。
ruby mv_sprite.rb
で実行すると、実行したディレクトリ以下の@2xという名前がついた画像を、
_2xにリネームして、さらに_2x付きのディレクトリを作ってその中へ移動します。
@がついたファイル名が、Compassではコンパイルエラーを起こすことへの対処です。
(Compass 0.13.alpha.12時点)
上記mixinも、Slicy書き出し→このRubyの処理、が前提になっています。

例:
assets/images/sprite/logo.png
assets/images/sprite/logo@2x.png

assets/images/sprite/logo.png
assets/images/sprite_2x/logo_2x.png

mv_sprite.rb

# ディレクトリを再帰的に抽出する
require 'pp'
require 'FileUtils'

root = File.expand_path(File.dirname(__FILE__))
root = ARGV[0] if ARGV[0]

# フォルダの一覧を取得
dir_entries = Dir.glob(root + "/" + "**/*")
# pp dir_entries

for filePath in dir_entries do
# pp file
ext = File::extname(filePath) # 拡張子取得

# 画像のみに処理
if( ext == '.jpg' || ext == '.png' || ext == '.gif' )
dir = File::dirname(filePath) # ディレクトリ
base = File::basename(filePath,ext) # 拡張子除去
twox_index = base.index('@2x')

# @2xを含む
if( twox_index && twox_index >= 0 )
p "#{dir}/#{base}#{ext}"
parent_dir = File::dirname(dir) # e.g. path_to_htdocs/common/img
my_dir = File::basename(dir) # e.g. sprite
twox_my_dir = "#{my_dir}_2x" # e.g. sprite_2x
twox_dir = "#{parent_dir}/#{twox_my_dir}" # e.g. path_to_htdocs/common/img/sprite_2x
twox_base_ext = "#{base.sub('@2x', '_2x')}#{ext}" # e.g. hoge_2x.png

# ディレクトリがなければ作る
FileUtils.mkdir_p(twox_dir) unless FileTest.exist?(twox_dir)

# ファイルを移動する
File.rename filePath, "#{twox_dir}/#{twox_base_ext}"

p "#{twox_dir}/#{twox_base_ext}"
p '--'
end
end
end

 

4. CoffeeScript

JavaScripterの間ではすっかり浸透したCoffeeScript を使います。
コードの行数、文字数が減らせるので、その分コメントを充実させられます。

必要なコマンドは
coffee -o assets/js -cw assets/coffee

 

ここまでの内容をまとめたものは、
https://github.com/soohei/compass-coffee-template
にあります。

 

5. Gruntによる自動化

注) 最新の状況はこちら

Gruntはこれまでに書いた、CompassやCoffeeScriptのコンパイル処理、
ソースの結合やMinify、ファイルの監視、簡易サーバーの起動などを
全て一つのコマンドで実行してしまう脅威の仕組みです。
他にGulpというのがあるようなのですが、まだ試していないです..
セットアップ方法は省略します。普段使っている基本的な設定・プラグインの構成は以下。

package.json (使用しているパッケージの一覧)

{
"name": "sample",
"version": "0.0.0",
"author": "Sohei Kitada",
"devDependencies": {
"grunt": "~0.4.5",
// ベンダープレフィックス補完
"grunt-autoprefixer": "~1.0.0",
// メディアクエリーをまとめる
"grunt-combine-media-queries": "~1.0.19",
// CoffeeScript
"grunt-contrib-coffee": "~0.11.0",
// Compass
"grunt-contrib-compass": "~0.9.1",
// ファイルの結合
"grunt-contrib-concat": "~0.5.0",
// 簡易サーバー
"grunt-contrib-connect": "~0.8.0",
// Minify JS
"grunt-contrib-uglify": "~0.5.1",
// ファイルの更新検知
"grunt-contrib-watch": "~0.6.1",
// CSSのプロパティをソートする
"grunt-csscomb": "~3.0.0",
// Minify CSS
"grunt-csso": "~0.6.3",
// シェルコマンドの実行
"grunt-exec": "~0.4.6"
}
}

 

Gruntfile.coffee (タスク)

module.exports = (grunt) ->
# load package.json
grunt.initConfig
pkg: grunt.file.readJSON 'package.json'

compass:
dist:
options:
config: 'config.rb'
outputStyle: 'compressed'
environment: 'production'
dev:
options:
config: 'config.rb'

coffee:
compile:
options:
join: true
files:
'source/js/script.js': ['source/coffee/**/*.coffee']

exec:
mv_sprite:
cmd: 'ruby mv_sprite.rb'

autoprefixer:
options:
browsers: ['last 2 version', 'ie 8', 'ie 9']
default:
src: 'assets/css/style.css'
dest: 'assets/css/style.css'

csso:
default:
src: 'assets/css/style.css'
dest: 'assets/css/style.css'

cmq:
default:
src: 'assets/css/style.css'
dest: 'assets/css/style.css'

csscomb:
default:
src: 'assets/css/style.css'
dest: 'assets/css/style.css'

concat:
jsdefault:
src: [
'source/jslib/**/*.js'
'source/js/**/*.js'
]
dest: 'assets/js/script.js'

license: {
src: [
'source/jslib/_license.js'
'assets/js/script.js'
]
dest: 'assets/js/script.js'
}

uglify:
default:
src: 'assets/js/script.js'
dest: 'assets/js/script.js'

connect:
uses_defaults: {}

watch:
options: # enable livereload
livereload: true
compass: # watch scss files
files: 'source/sass/**/*.scss'
tasks: ['compass:dev']
coffee: # watch scss files
files: 'source/coffee/**/*.coffee'
tasks: ['coffee:compile']
js: # watch js files
files: ['source/js/**/*.js', 'source/jslib/**/*.js']
tasks: ['concat:jsdefault']
image: # watch image files
files: 'source/images/**'
tasks: ['exec:mv_sprite']
html: # watch html files
files: '**/*.html'

# load Grunt Plugins
grunt.loadNpmTasks('grunt-autoprefixer')
grunt.loadNpmTasks('grunt-combine-media-queries')
grunt.loadNpmTasks('grunt-contrib-coffee')
grunt.loadNpmTasks('grunt-contrib-compass')
grunt.loadNpmTasks('grunt-contrib-concat')
grunt.loadNpmTasks('grunt-contrib-connect')
grunt.loadNpmTasks('grunt-contrib-uglify')
grunt.loadNpmTasks('grunt-contrib-watch')
grunt.loadNpmTasks('grunt-csscomb')
grunt.loadNpmTasks('grunt-csso')
grunt.loadNpmTasks('grunt-exec')

# tasks

# defalt
grunt.registerTask('default', ['connect', 'watch']);

# development
grunt.registerTask('dev', ['exec:mv_sprite', 'compass:dev', 'coffee:compile', 'concat:jsdefault']);

# distribution
grunt.registerTask('dist', ['exec:mv_sprite', 'compass:dist', 'autoprefixer', 'cmq', 'csscomb', 'csso', 'coffee:compile', 'concat:jsdefault', 'uglify', 'concat:license']);

return

 

「grunt」の処理内容
・connect
簡易Webサーバーの立ち上げ (プロジェクトによっては使わない)

・ファイルの更新の監視
1) images内が更新されたら…「3. スプライトイメージの自動化」で紹介したRubyコマンドを実行
2) scssが更新されたら…Compassを再コンパイル
3) coffeeが更新されたら…CoffeeScriptを再コンパイル → jsファイルが書き出される
4) jsが更新されたら…JSファイルを一つのファイルに結合

「grunt development」の処理内容
・上記 1),2),3),4)を順番に実行

「grunt distribution」の処理内容
・1)を実行
・2)をdist用の設定 (outputStyle: ‘compressed’) で実行
・ベンダープレフィックスを追加
・メディアクエリーをまとめる
・CSSのプロパティをソート
・CSSをMinify
・3)を実行
・4)を実行
・JSをMinify
・上部にライブラリ関係のライセンスを追加

ここまでの内容をまとめたものは、
https://github.com/soohei/grunt-template
にあります。

 

6. ローカルサーバー

本気で開発する場合は、MAMPでローカルサーバーを立てています。
詳しくは、
MAMP 2 → MAMP 3
MAMPでバーチャルホストの設定 (2種類)
あたりに書かれています。

 

7. その他

最後に、ここまでのワークフローで生まれた、
本番環境にアップ不要のファイルはサーバーに転送しないように、
Transmitを設定しています。

transmit

 

MAMP 2 → MAMP 3

MAMPのphpMyAdminの動作があやしかったので、これを機にローカルのWebサーバーをMAMP2からMAMP3にアップデート。以下手順です。

1)
MAMPのHP(http://www.mamp.info/en/downloads/)から
から最新版をダウンロード。

2)
既存の/Applications/MAMPをリネームして退避。(例: MAMP_old)
ダウンロードしたインストーラーを使って、MAMP 3をインストール。

/Applications フォルダには、新しくできたMAMPフォルダと、これまで使っていたMAMP_oldフォルダが並ぶ。

4)
MAMP_old/db
MAMP_old/conf/apache/httpd.conf

をそれぞれMAMPフォルダの同一階層に上書きコピー。

5)
終了!(MAMP_oldは削除してOK)

MAMPのバーチャルホスト設定については、以前書いた記事「MAMPでバーチャルホストの設定 (2種類)」をどうぞ。

ニューヨークから帰国 (3度目)

1月末から移動を始め、7月後半に再び戻って来ました。
忘れないように記録。

5月
・Bedfordの南の方で再びサブレット暮らし。
・間借りしているPARTY NYが引っ越し。DumboのSTINK DIGITALの中へ。
・Bostonへ1泊、小旅行。

6月
・Bedfordの西の方でサブレット暮らし。
・一人暮らしのアパート探し開始。
・下旬についに新居へ引っ越し。

7月
・ビザの書類が完成。移民局へ申請!
・帰国

一番苦労したのは、新居のインターネットの開通。SSNを持っていないので、電話で説明して、国際免許証をFAXして、電話して工事日の予約して、途中たまたま当たった優しいコールセンターのおばさんがいなければ無理だった。

食生活はとても改善して、炊飯器でご飯を炊いて、冷凍餃子と納豆ばっかり食べてました。
Midoriyaさんありがとう。

そろそろ色々な仕事が落ち着いてきたので、無事にビザが手に入って、あちらへ行ったら色々詰め込む予定。

会社のWebの更新が止まってますが、仕事してます。
順調です。

ニューヨーク 約2ヶ月

再び帰ってきました。

今回は日本の締め切りに重なって、あまりアクティブな出来事がなかったので、
今までに住んだところの記録を書きます。

5週間の滞在で日本に帰省する友人宅を中心に計3部屋に住みました。
家賃の出費がだいぶ改善。みんなありがとう。
東京の家も解約したので、固定費がだいぶ減った。

まずは前回の滞在から

・1月下旬 Bushwick (Morgan Ave)

Airbnbで借りたアパート。
マンハッタンから地下鉄(L)で15分くらい。
駅前のSwallow CafeがGood.
Whole Foods Marketの惣菜ばっかり食べてた。

・2月上旬 East Village (1st Av)

Airbnbで借りたアパート。
同じくLラインのマンハッタンの東端。14st沿いは便利。
ピザばっかり食べてた。日本食も色々あるエリア。
2Avにある味噌屋のラーメンにチャーシューと野菜トッピングがうまい。

・2月中旬 Times Square (42st)

アパートが見つからなくてホテル。
超有名な観光エリア。あまり住む場所ではない。
スープとサンドイッチばっかり食べてた。

・2月下旬 Williamsburg (Bedford Av)

Airbnbで借りたアパート。
Lラインで、Brooklynに入って1駅目。人気エリアで週末はかなり賑わっている。
ベーグルばっかり食べてた。Baglesmithはかなりおすすめ。

ここからが今回の滞在

・3月上旬〜中旬 Lower Eastside (Delancey St / Essex St)

帰省中の友人アパート。
KATZ’Sという有名サンドイッチ屋の近く。
他にもWhynotというカフェや、Mikey’s Burgerというハンバーガー屋が良い。
ベーグルとハンバーガーばっかり食べてた。SOHOが徒歩圏内。住みやすい。

・3月下旬 Midtown East (Grand Central)

帰省中の友人アパート2。
初ミッドタウン。日本食デリがあったり、ここは日本人エリアだと思った。
ビジネス街なので、昼は人が多くて、夜は少なめ。高いビルが多い。
住みやすいけどランドリーとか値段が高い。

・4月上旬 Williamsburg (Bedford Av)

前に住んだ時と1ブロック違い。
PARTYのトムの部屋をサブレット。初ルームシェア。Thanks Tom!
色々なところに住んで、Williamsburgに戻って来たら、やはり良いエリアだった。
ビザが取れたら、Williamsburgでアパート探すことになりそう。

少し締め切りが落ち着いて、ニューヨーク中心に動きそうな仕事もいくつか始まって、
楽しくなったところで、2週間の一時帰国。ビザ申請の準備を進めたり、
ここでしゃべります。

それと、そのビザ申請にあたってポートフォリオの印刷が必要だったので、
弊社Webをアップデートしました。
http://td-inc.jp/category/portfolio を印刷すると、ポートフォリオが完成。
(いくつかオンラインでは紹介してないプロジェクトもあるけれど)

ニューヨーク 1ヶ月目

1月末に東京からニューヨークへ行き、1ヶ月間過ごして東京に帰ってきました。
来週には再びニューヨークに戻る予定なので、今のうちに少しまとめます。

まず今回のニューヨーク行きのきっかけは、

日本の外でイケてるインターフェースのデザイン・実装野郎として身を立てて、
ゆくゆくは世界中から仕事のオファーが来るようになりたい、好きな場所に住みたい。
(今はニューヨークが気になる)

同級生たちが、留学してバリバリ活躍しているのを昨年訪ねて回ったら、
じっとしていられなくなった。

という2つです。

そしていざニューヨーク行ってからの生活ですが、
Airbnbでアパートを借りたり転々としながら、仕事と英語の勉強をしていました。

まず仕事については、今はまだ日本のメンバーと日本との仕事を継続しています。
仕事場は、先日超かっこいいCut CopyのMVをリリースしたばかりのPARTY NYの
川村さん幹太さんトムが集うオフィス(部屋)に、居候として置いていただけました。
本当にありがとうございます。またすぐに戻ります。

次に英語ですが、語学学校に行き始めて3日で、生活リズムが合わずに不登校になり、
その後はオンライン英会話と自習をしていました。
どこに行っても一日の長さは同じなので、新しいことを始めるには自分に合ったリズム大事です。
その後は、
・午前中に家で仕事(日本が残業中)
・昼からオフィス(日本は寝ている)
・20時前にオフィスを出て、夕飯を食べるか買って帰って、
・21時から家で英会話(スカイプ相手はバンクーバーで夕方)
・そのあと仕事再開(日本が始業している)
というサイクルでした。日本にいた時よりも生活サイクルがまともです。

他にも新しい出来事はたくさんあるのですが、
トータルで振り返ると、もうしばらくニューヨークを拠点にしてみたいと思っています。

仕事もビザ取得もNYの住居探しも、引き続きたくさんの人の力を借りる予定です。
これからもよろしくお願いします。

2014

あけましておめでとうございます。

2013年も、たくさんの素敵なお仕事の機会、出会いがありました、
どうもありがとうございました。

2011年の独立からもうすぐ丸3年、
その後結成したT-Dは、昨年10月で無事に2周年を迎え、3期目に入りました。
また、3月には、THE GUILDという会社の設立に加わり、
こちらでも日々刺激を受けながらやっています。

2014年は、2013年に考えたことを行動に移そうと思っています。
まず、1月末からニューヨークへ行きます。
まだ半年分くらいの計画しかありませんが、
時差と、いくつかの壁を乗り越えて、本気で仕事を続けます。

フジロックには戻ります、今年も苗場で乾杯しましょう!
その前にも、何度か戻る予定ですのでFacebook等でお知らせします。

今年も最高のデザイン、UI、実装を、ネットとリアルに残すべく、
T-D, THE GUILDでの活動を続けて参ります。

どうぞよろしくお願いします。

北田 荘平