こんばんは。つい最近までコートを羽織っていたと思えば、もう随分暖かくなりましたね。
数日前から趣味で新しいウェブアプリを書いていて、折角なので勉強がてら新たにPHPフレームワークのLaravelを採用することにしました。噂には聞いていましたが確かに素晴らしい出来で、今後PHPのプロジェクトでは第一候補としたくなるようなものでした。
Contents
検証環境
- Laravel framework v5.2.31
- Elixir v3.x
次の3つはグローバルインストール済み
- TypeScript v1.9.0
- typings v0.8.1
- gulp v3.9.1
Elixir でも TypeScript 使いたい!
Laravel には、フロントエンドの開発を支援する Elixir という gulp のラッパーがあります。デフォルトでSassやLessのコンパイル、JSのcombine&minifyとかできるすごいやつ。でもTypeScriptはサポートしてくれないので、自力でがんばる必要があります。(CoffeeScriptは公式サポート対象なんてズルい!)
前提として、コンパイルしたいファイルは次の3つです。
- /resources/assets/sass/app.scss
→ /public/css/app.css -
/resources/assets/typescript/app.ts と sub.ts
→ subをrequireした単一ファイルで /public/js/app.js
TypeScriptファイルの中身は次の通りです。
|
1 2 3 4 5 |
console.log('running...'); import sub from './sub'; let msg = sub(); console.log('sub', msg); |
|
1 2 3 |
export default function message(word = "World") { return "Hello " + word; } |
まずはうまくいった方法を書いて、ダメだった方法も備忘録として後ろに書きます。
laravel-elixir-webpack を使う
またWebPackです、ごめんなさい。でもやっぱり自分に慣れてるものを使うのが一番ですよ・・・たぶん。
npmで、ElixirでWebPackを扱えるように laravel-elixir-webpack を、WebPackでTypeScriptを扱うために ts-loader をインストールします。(ts-loaderについは過去記事を参照)
|
1 |
$ npm install --save-dev laravel-elixir-webpack ts-loader |
次に gulpfile.js を編集して、Elixirで ts-loader のモジュールが入ったWebPackを呼び出します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var elixir = require('laravel-elixir'); require('laravel-elixir-webpack'); elixir(function(mix) { mix.sass('app.scss'); // Scssのコンパイル mix.webpack('../typescript/app.ts', { resolve: { // 書かないと拡張子なしの名前解決ができない extensions: ['', '.js', '.jsx', '.ts', '.tsx'] }, module: { loaders: [ { test: /\.tsx?$/, loader: "ts-loader" } ], }, }); }); |
mix.webpack の第一引数には /resources/assets/js からの相対パスを記載するため、上の書き方になっています。
これだけで実行すると、ビルドすべきでない所まで内部的に参照してエラーを出してくれるので、TypeScriptのコンパイル設定を変更して、ビルドしないディレクトリを明示的に指定するようにします。
プロジェクトルートに tsconfig.json が作られていない場合は tsc --init コマンドで作成してください。
tsconfig.json の exclude に3つルールを追加します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "compilerOptions": { "module": "commonjs", "target": "es5", "noImplicitAny": false, "sourceMap": false }, "exclude": [ "node_modules" + "typings/main.d.ts", + "typings/main", + "vendor" ] } |
typings は型定義マネージャーの typings を使っている場合のみ必要で、記述しないと大量の error TS2300: Duplicate identifier が出力されます。 typings/ 下にある main がサーバー側、 browser がブラウザ向けなので、今回はbrowserの方を読ませるように設定します。
gulp でうまくビルドできるか試してみます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ gulp [20:21:06] Using gulpfile /path/to/proj/gulpfile.js [20:21:06] Starting 'default'... [20:21:06] Starting 'sass'... Fetching Sass Source Files... - resources/assets/sass/app.scss Saving To... - public/css/app.css [20:21:07] Finished 'default' after 1.44 s [20:21:08] gulp-notify: [Laravel Elixir] Sass Compiled! [20:21:08] Finished 'sass' after 1.57 s [20:21:08] Starting 'webpack'... Fetching Webpack Source Files... - resources/assets/typescript/app.ts Saving To... - public/js/app.js ts-loader: Using typescript@1.8.9 and /path/to/proj/tsconfig.json [20:21:09] Version: webpack 1.13.0 Asset Size Chunks Chunk Names app.js 2.89 kB 0 [emitted] app app.js.map 3.29 kB 0 [emitted] app [20:21:09] gulp-notify: [Laravel Elixir] Webpack Compiled! [20:21:09] Finished 'webpack' after 1.78 s |
これで Laravel でも TypeScript 使って快適に開発を進められそうです!
失敗談: elixir-typescript
ググって最初に出てきたのがこの方法なので、これで試してみてました。
結果として、少し罠にハマりつつも、単一のTypeScriptをそのままビルドする目的は達成しました。
コードとしては、 elixier-typescript をnpmでインストールして、次のgulpfileで実行。
|
1 2 3 4 5 6 7 8 9 10 |
var elixir = require('laravel-elixir'); require('elixir-typescript'); elixir(function(mix) { mix.sass('app.scss'); mix.typescript('app.ts', 'public/js/'); // mix.typescript('app.ts', 'resources/assets/js/'); // mix.browserify('app.js'); }); |
結果、これでも正しくコンパイルされたjsが出力されます。ただし、これはrequire諸々の依存関係などを解決してくれておらず、ビルドされたjsには素の require が残ってしまい、ブラウザから実行すると怒られてしまいます。
こういったのを解決してくれるのが Browserify という認識で、コメントアウトした行のように 「JSにビルド」→「Browserifyでブラウザ向けに変換」 の手順でうまくいくんだろう…と試したところ全然ダメでした。ビルド自体はエラー無く通るのですが、結局ブラウザで実行するとエラーになるのです。
この辺、調べてもどうにも自力で解決するのが難しそうで(主に Browserify が難解で)、それならばと WebPack に逃げることにしました。Browserifyの達人にとっては余裕なのでしょうか・・・。
余談: Browsersync と連携する
以前 Browsersync については紹介しましたが、 Elixir ではデフォルトでサポートされています。 WebPackの中に書いてもうまく動きそうではあります(未検証)が、私はElixirの機能で呼び出すようにして使っています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var elixir = require('laravel-elixir'); require('laravel-elixir-webpack'); elixir(function(mix) { mix.sass('app.scss'); mix.webpack('../typescript/app.ts', { resolve: { extensions: ['', '.js', '.jsx', '.ts', '.tsx'] }, module: { loaders: [ { test: /\.tsx?$/, loader: "ts-loader" } ], }, }); mix.browserSync({ proxy: '192.168.33.10' }); }); |
前提として browser-sync をグローバルインストールしていて、今回は Vagrant 内で開発をしているため、 proxy にVagrantのネットワークアドレスを記載してプロキシさせています。
これで glup watch で起動しておけば、ファイル変更で自動的にブラウザがリロードされます。快適になりますよ!
所感
ご無沙汰してます。
最近、やるべきことも、勉強したいことも多くて、エントリを書く時間を捻出できずにいました。。書きたいネタはたくさんあるので、今月からリハビリがてら書いていきます。


