TypeScript + System.jsの構成におけるSystem.config()の基本パターン。そしてモダンWeb開発の環境をマッハで作る。
System.js, TypeScript, System.config()
前回こういう↓エントリーを書きましたが、System.jsについてよくわかっていなかったのでドキュメントを読んだりして調べました。
そういうわけで今回は前回と直接関連はありませんが、実質続編ということになります。
苦労したのは特にTypeScriptのコンパイラとの整合性。
例えばhoge.ts
ファイル内で同じフォルダにあるfoo.ts
のクラスをimportしようとするとき、
import {xxx} from './foo'
のように書きますが、
おそらく同じ場所に同じファイル名の.ts
ファイルと.js
ファイルが存在しているのが普通かと思います。
そうなるとTypeScriptのコンパイラはOKを出しても、ブラウザで実行するときにファイルが見つからないエラーになります。
これを解決するためには後述するpackages
のdefaultExtension
指定が必要です。
また、Lodashのようなライブラリをimportしようとするとき、
import * as _ from 'lodash'
のように書きますが、
後述するbaseURL
,paths
,map
をうまく組み合わせて実体ファイルまでのパスを正確に指定しておかないと、
ブラウザで実行するときにファイルが見つからないエラーになります。
これらを踏まえて TypeScript + System.js の構成でどのようにSystem.config()
を書けば良いか、
僕なりに調べた結果をメモとして残します。
この例ではconfig.js
ファイルにまとめて書いて、index.html
から<script>
タグで参照します。
ちなみにbower
やjspm
のようなフロントエンドライブラリ管理ツールは使いません。npm
だけです。それにgulp
やgrunt
のようなビルドツールも使いません。
とりあえず"何かを試したい、それもちょっとだけ"というとき、モダンWeb開発の環境をいちいち構築するのはめんどくさいじゃないですか。気軽にさくっとやりたいですよね。タイトルのようにマッハで、とはいきませんが本当に最低限のことしかやりません。
npmで必要なものをインストール
npm init -y npm install systemjs lodash babel babel-polyfill --save tsc --init
babel
とbabel-polyfill
は実行時に.js
ファイルをBabelでコンパイルするのに使うライブラリです。
詳しくはElectronでAngular2を動かすついでにasync/awaitも試してみた。を参照してください。
tsdで定義ファイルをインストール
tsd install lodash --save
フォルダを作ります
mkdir src
(root)/src/index.html の例 (angular2は今回のエントリーと直接関連はありません)
<head> <script src="../node_modules/systemjs/dist/system.js"></script> <script src="../node_modules/angular2/bundles/angular2.dev.js"></script> <script src="config.js"></script> <script> System.import('app/app'); </script> </head>
(root)/src/config.js の例 【今回のエントリーで一番書きたかった部分】
System.config({ baseURL: '.', transpiler: 'babel', paths: { 'node:*': '../node_modules/*' }, map: { 'babel-polyfill': 'node:babel-polyfill/dist/polyfill.min.js' }, packages: { 'app': { defaultExtension: 'js' } }, meta: { 'app/*.js': { deps: ['babel-polyfill'] } } });
baseURL
プロパティは何よりも優先される。'/'
を指定するとこの後の全てのパス指定はルートが基準となる。ただしElectronの場合はドライブのルートになる点に注意。ブラウザ環境でしか開発しない人は気にしないでください。baseURL
を省略するか'.'
とすると呼び出し元のindex.html
が存在するパス、今回の例では(root)/src/
がbaseURL
となる。transpiler
プロパティで実行時コンパイルに使いたいライブラリを指定する。特に指定しない場合はfalse
にする。paths
プロパティで'node:*': '../node_modules/*'
と指定すると、map
プロパティ内のnode:
を置き換えられる。- この場合
map
で'lodash': 'node:lodash/index.js'
と指定すると、System.import('lodash')
と書いたときに(root)/node_modules/lodash/index.js
を参照することになる。 packages
プロパティの'app'
は、baseURL
,paths
,map
の全てを使ってパスが解決される。 この場合はbaseURL
と結合して、(root)/src/app/
となる。defaultExtension: 'js'
と指定しているので、(root)/src/app/
フォルダにapp.ts
ファイルとapp.js
ファイル が両方存在する場合、指定と一致するapp.js
を参照する。- この場合
System.import('app/app')
と書いたら、 最初のapp
は(root)/src/app/
フォルダを意味し、次のapp
はapp.js
を意味する。よって(root)/src/app/app.js
を参照することになる。 meta
プロパティでは依存関係を記述できる。それ以外の使い方はわからない。'app/*.js'
とは(root)/src/app/*.js
を意味する。それらが読み込まれるとき、deps
で指定した'babel-polyfill'
を一緒に読み込む。つまり依存関係の解決をする。
.ts
ファイルのコンパイルやブラウザのオートリロードなんかはpackage.json
の"scripts"
を書くだけで最低限のことはできます。がっつりやるのでなければgulp
やgrunt
は要りません。その辺は前回のエントリーを参照してください。
以上です。ありがとうございました。