laravel-elixir使ってtypescript扱ってみた

# laravel-elixir使ってみた

![laravle-elixir-v3.png](https://qiita-image-store.s3.amazonaws.com/0/78857/c3a83b63-cdf0-9cca-4783-52e48f9bacdb.png)


## 環境

- vagrant
- VirtualBox
- PHP7
- Laravel5
- CentOS7

## やったこと

Laravel5でlaravel-elixir使って、sassとtypescrptをgulpでコンパイルからversioning、minifyまで自動で行う。

## [laravel-elixir](http://laravel.com/docs/5.1/elixir#introduction)って??


``` 公式#introduction.
Laravel Elixir provides a clean, fluent API for defining basic Gulp tasks for your Laravel application.
Elixir supports several common CSS and JavaScript pre-processors, and even testing tools.
Using method chaining, Elixir allows you to fluently define your asset pipeline.

For example:

elixir(function(mix) {
    mix.sass('app.scss')
       .coffee('app.coffee');
});

If you've ever been confused about how to get started with Gulp and asset compilation, you will love Laravel Elixir.
However, you are not required to use it while developing your application.

You are free to use any asset pipeline tool you wish, or even none at all.
```

つまり、Laravelではcssやjsのbuildツールにgulpを使うけど、gulpをもっと流暢に使いやすくwrapして提供してあげるよ。
それがlaravel-elixirだよって言ってるみたい。
そもそもgulpに関しては以下。

## [gulp](http://gulpjs.com/)って??

![gulp.png](https://qiita-image-store.s3.amazonaws.com/0/78857/fe373b84-983b-4785-09f6-4a6005b36ba4.png)


Node.jsを使ったフロントエンドのbuildツールです。
altJSやsass,stylus等を生のjsやcssに変換してくれるツール。
また、変換だけでなく、cache対策としてのversiongや、minifyと呼ばれるファイル圧縮(jquery.min.jsとかのあの「min」)もタスク自動化して管理できる優れもの。
似た者に[grunt](http://gruntjs.com/)とか[fly](https://github.com/bucaran/fly)がある。

※flyは自分も2015/12/16(水)のJSオジサンで登壇してる人が話しているの聞いて初めて知った。

## とりあえず使ってみる

今回は以下を取り扱って見る。
※laravel-elixir初めて使います。間違いや、回りくどいことがあれば、ご指摘願います。

- jsはtypescript
- cssはsass

以上!

一番最初にやって欲しいのは、開発環境localマシン自体にgulpコマンドをインストールすること。

```
npm install -g gulp
```

上記コマンドでgulpがinstallされたら、Laravel5のプロジェクトで作業を行う。

``` ※補足.
npmもパッケージ管理ツールです。
npm自体はnodeを落とせば入ってくるので、nodejsをご自分の環境に入れてください。

また、-gはグローバル領域を表します。
```
Laravel5プロジェクトにはデフォルトで以下のようなpackage.jsonが作成されている。

``` package.json
     1	{
     2	  "private": true,
     3	  "devDependencies": {
     4	    "gulp": "^3.8.8"
     5	  },
     6	  "dependencies": {
     7	    "laravel-elixir": "^3.0.0",
     8	    "bootstrap-sass": "^3.0.0"
     9	  }
    10	}
```

package.jsonはPJ単位でパッケージ管理するのに使用します。
※超かいつまんで書いてます
追加したい場合は、後述(typescriptの項で)しますが、**--save-dev**で追加されます。

なので、package.jsonを元にパッケージをinstallします。
下記コマンドをpackage.jsonのある階層で叩きます。

```
npm install
```

これでgulpが反映されます。
あとはgulpを実際に行うだけです。

Laravel5のプロジェクトにはデフォルトでgulpfile.jsが以下のように作成されてます。

``` gulpfile.js
     1	var elixir = require('laravel-elixir');
     2	
     3	/*
     4	 |--------------------------------------------------------------------------
     5	 | Elixir Asset Management
     6	 |--------------------------------------------------------------------------
     7	 |
     8	 | Elixir provides a clean, fluent API for defining some basic Gulp tasks
     9	 | for your Laravel application. By default, we are compiling the Sass
    10	 | file for our application, as well as publishing vendor resources.
    11	 |
    12	 */
    13	
    14	elixir(function(mix) {
    15	    mix.sass('app.scss');
    16	});
```

15行目でapp.scssをcssにコンパイルしているみたいです。

Laravel5では、resources下に開発中のリソース群があったと記憶しているので、、、

```
$ pwd
/home/vagrant/hogehoge/resources/assets/sass
$ ls -tlr
合計 4
-rw-rw-r--. 1 vagrant vagrant 72  8月 30 20:31 app.scss
$ cat -n app.scss 
     1	// @import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap";
     2	
$ 
```

ありました。こいつがコンパイル対象のscssです。
じゃ、早速コンパイルしてcssに展開してみます。
ただ、app.scssは中身が空なので、公式のdemoからソース持ってきて、app.scssに書き込んでからコンパイルしてみます。

[ここ](http://sass-lang.com/guide)のソースを持ってくる。
app.scssに書き込む。

``` app.scss
$font-stack:    Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}
```

これがコンパイルされて、cssに展開されればOKってことですね。

では早速。gulpfile.jsがある階層まで戻り、以下のコマンドを叩く。

```
gulp
```

するとなにやらlogが吐き出され、終了しますね。

```
Starting 'sass'...

Fetching Sass Source Files...
   - resources/assets/sass/app.scss


Saving To...
   - public/css/app.css

Finished 'default' after 520 ms
gulp-notify: [Laravel Elixir] Sass Compiled!
```

いかにもなlogです。public下にコンパイル結果が格納されているみたいなので、見てみます。

``` public/css/app.css
$ pwd
/home/vagrant/hogehoge/public/css
$ ls -tlr
合計 4
-rw-rw-r--. 1 vagrant vagrant 59 12月 17 16:24 app.css
$ cat -n app.css 
     1	body {
     2	  font: 100% Helvetica, sans-serif;
     3	  color: #333;
     4	}[vagrant@localhost css]
$ 
```

ちゃんとcssが展開されてますね。

## typescriptの導入

![typescript2.jpg](https://qiita-image-store.s3.amazonaws.com/0/78857/2dac15d1-334f-c0e2-19c3-2d5b55af3fbf.jpeg)


```
npm install --save-dev laravel-elixir-typescript
npm install --save-dev gulp-typescript
```

これでpackage.jsonが更新される

``` package.json
     1	{
     2	  "private": true,
     3	  "devDependencies": {
     4	    "gulp": "^3.8.8",
     5	    "gulp-typescript": "~2.10.0",
     6	    "laravel-elixir-typescript": "~1.0.1",
     7	    "gulp-notify": "~2.2.0"
     8	  },
     9	  "dependencies": {
    10	    "laravel-elixir": "^3.0.0",
    11	    "bootstrap-sass": "^3.0.0"
    12	  }
    13	}
```

コンパイル対象のtsファイルを作成します。
下記の記載も、[typescriptの公式demo](http://www.typescriptlang.org/Playground)から適当にパチってきたソースです。

```
mkdir resources/assets/typescript
vi resources/assets/typescript/app.ts
```

``` app.ts
class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

var greeter = new Greeter("world");

var button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
    alert(greeter.greet());
}

document.body.appendChild(button);
```

最後にgulpfile.jsを記載します。

``` gulpfile.js
     1	var elixir = require('laravel-elixir');
     2	elixirTypscript = require('elixir-typescript');
     3	
     4	elixir(function(mix) {
     5	    // resources/sass/下を見に行く
     6	    mix.sass('app.scss');
     7	    // node_moduleしたのelixir-typescript下にextensionがあったのでそこ読んだ。
     8	    // 第一引数にファイル名を第二引数に展開先を指定するだけみたい。
     9	    // 対象ファイルは.ts下を探して全てコンパイルする。
    10	    mix.typescript('app.js', 'public/js/');
    11	    // versioning
    12	});
```

elixir-typescriptはnode_module下に展開されています。

``` node_modules/elixir-typescript/index.js
$ pwd
/home/vagrant/hogehoge/node_modules/elixir-typescript
$ cat -n index.js 
     1	var gulp = require('gulp');
     2	var elixir = require('laravel-elixir');
     3	var ts = require('gulp-typescript');
     4	var concat = require('gulp-concat');
     5	var _ = require('underscore');
     6	
     7	// Laravel Elixir Reporter
     8	var _laravelReporter = require('./reporter');
     9	
    10	var Task = elixir.Task;
    11	
    12	elixir.extend('typescript', function (output, dest, options) {
    13	
    14	    var pluginName = 'typescript';
    15	    var search = '**/*.+(ts)';
    16	    var assetPath = './' + elixir.config.assetsPath;
    17	
    18	    options = _.extend({
    19	        sortOutput: true
    20	    }, options);
    21	
    22	    new Task(pluginName, function () {
    23	        var tsResult = gulp.src(assetPath + '/**/*.ts')
    24	            .pipe(ts(options, undefined, _laravelReporter.ElixirMessage()));
    25	        return tsResult
    26	            .pipe(concat(output))
    27	            .pipe(gulp.dest(dest || './public/js/app.js'));
    28	    })
    29	        .watch(assetPath +  '/typescript/**');
    30	});
$ 
```

ここの12行目からを読むと、第一引数にコンパイル後のファイル名を指定し、第二引数にコンパイル結果の格納先を指定するとあったので、

``` gulpfile.js
mix.typescript('app.js', 'public/js/');
```

こうしました。
また、**「resources/assets/typescript」下に配置された全ての.tsファイルをコンンパイルして、連結する**みたいですね。

では

```
gulp
```

で結果を見てます。

```
$ pwd
/home/vagrant/hogehoge/public/js
$ cat -n app.js 
     1	var Greeter = (function () {
     2	    function Greeter(message) {
     3	        this.greeting = message;
     4	    }
     5	    Greeter.prototype.greet = function () {
     6	        return "Hello, " + this.greeting;
     7	    };
     8	    return Greeter;
     9	})();
    10	var greeter = new Greeter("world");
    11	var button = document.createElement('button');
    12	button.textContent = "Say Hello";
    13	button.onclick = function () {
    14	    alert(greeter.greet());
    15	};
    16	document.body.appendChild(button);
```

おー!ちゃんとjsに展開されている!!

## versioning

``` gulpfile.js 
     1	var elixir = require('laravel-elixir');
     2	elixirTypscript = require('elixir-typescript');
     3	
     4	elixir(function(mix) {
     5	    // resources/sass/下を見に行く
     6	    mix.sass('app.scss');
     7	    // node_moduleしたのelixir-typescript下にextensionがあったのでそこ読んだ。
     8	    // 第一引数にファイル名を第二引数に展開先を指定するだけみたい。
     9	    // 対象ファイルは.ts下を探して全てコンパイルする。
    10	    mix.typescript('app.js', 'public/js/');
    11	    // versioning
    12	    mix.version([
    13	      'js/app.js',
    14	      'css/app.css'
    15	    ]);
    16	});
```

最後の12 ~ 15行目です。
コンパイル結果として生成されたcssとjsに対して、「version」を行うと、

```
$ pwd
/home/hogehoge/vote/public/build
$ ls -ltr
合計 4
-rw-rw-r--. 1 vagrant vagrant 84 12月 17 16:25 rev-manifest.json
drwxrwxr-x. 2 vagrant vagrant 30 12月 17 16:25 js
drwxrwxr-x. 2 vagrant vagrant 31 12月 17 16:25 css
$ cat rev-manifest.json 
{
  "css/app.css": "css/app-bd1f596a0a.css",
  "js/app.js": "js/app-e839cee77f.js"
}
```

buildディレクトリが生成され、rev-manifest.jsonというマッピングファイルが生成されてる。
また、cssディレクトリとjsディレクトリを見ると、

```
$ cd css
$ ls -trl
合計 4
-rw-rw-r--. 1 vagrant vagrant 59 12月 17 16:25 app-bd1f596a0a.css
$ cat -n app-bd1f596a0a.css 
     1	body {
     2	  font: 100% Helvetica, sans-serif;
     3	  color: #333;
     4	}[vagrant@localhost css]
$ 
```

css名の後ろにハッシュ値が付与されていることがわかる。
たしかにversiongされているようです。
ちなみに、versioningされたファイルへのHTMLからの参照は

```
<link rel="stylesheet" href="{{ elixir('css/app.css') }}">
```

こう書くことで、先ほどのjsonファイルでマッピングを行ってくれるので、開発者は素直にapp.cssとかくだけで参照可能となる。
優しい世界。

以上。