はじめに
現在ベータ版の Angular2 を少し触ってみたい、ということで公式サイトにのっている QuickStart を読み進めてみました。
Angular1.x の経験があったので理解にはあまり困らずに進めることができたのと、TypeScript が思ったより書いていて楽しい言語だったので、QuickStart から一歩足をだして、Angular2 のライブラリ作成に挑戦してみました。あまりフロントエンドすることなかったので npm パッケージの作り方を調べながら、なんとなくそれっぽくなったのでまとめてみようと思います。
記事の最後に作ったものと、参考にしたサイトを書いておくので、そちらも参考にしていただければと思います。
ゴール
Angular2 のライブラリを作って公開できる
3行まとめ
- Git では .ts のみ管理 (.js や .d.ts ファイルは管理しない)
-
TypeScript のコンパイルは es5、
moduleResolution
をnode
に指定する - 作ったライブラリをインポートする際に SystemJS の map でパスの指定が必要
備考1: 現在の自分の理解ではこうなっていますが、ベストプラクティス的なものではないです。(Angular2 の QuickStart がターゲットになってます)
備考2: SystemJS でインポートする際に map の指定を不要にするための方法がありそうな気がしてます。気がしているだけかもしれませんが。
方針
ディレクトリ構成
-
lib
ディレクトリを作成してそこにコードを書く -
lib/components
など、機能ごとにディレクトリを作成してまとめる -
lib/components.ts
で必要に応じてexport
する - (もしかしたら
/
においた方がいいのかも)
src
ディレクトリと dest
ディレクトリを作成して、ts
ファイルを src
において、コンパイル結果を dest
においたりする例もあり、このへんは好みなのかなと。
angular2-example-library
├── lib
│ ├── components
│ │ ├── example.component.ts
│ │ └── sample.component.ts
│ ...
│ └── components.ts
...
├── .gitignore
├── .npmignore
├── package.json
├── tsconfig.json
├── tslint.json
└── typings.json
// 公開したいものを export
export * from './components/example.component';
export * from './components/sample.component';
import {Component} from 'angular2/core';
@Component({
selector: 'example',
template: '<p>example!</p>'
})
export class ExampleComponent {}
# TypeScript
*.js
*.map
*.d.ts
# DO NOT IGNORE TYPESCRIPT FILES FOR NPM
# TypeScript
# *.js
# *.map
# *.d.ts
.gitignore
で .js
ファイルなどを指定しているのですが、パッケージ公開の時に TypeScript のコンパイルを行って js
ファイルなどを生成する 設定を package.json に記述するので、実際の npm パッケージには .js
ファイルも含まれます。
設定ファイル
{
"name": "angular2-example-library",
"version": "0.1.0",
"description": "Angular 2 Example Library",
"homepage": "https://github.com/example/example.git",
"author": "Mr. Example <example@example.com>",
"dependencies": {
"angular2": "^2.0.0-beta.9",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.3",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.2",
"zone.js": "0.5.15"
},
"scripts": {
"test": "tslint ./lib/*.ts ./lib/**/*.ts",
"prepublish": "tsc",
"typings": "typings"
},
"typings": "./lib/components.d.ts",
"repository": {
"type": "git",
"url": "git://github.com/example/example.git"
},
"devDependencies": {
"tslint": ">=3.5.0",
"typings": ">=0.6.8",
"typescript": "^1.8.7"
}
}
直接依存しているのが angular2
のみの場合は, dependencies
は angular2
ののみを記述し、それ以外は angular2
が依存している(孫依存)ものなので、記述せずに利用者に委ねる方がいいのかもしれません。
script
の prepublish
で npm パッケージ公開時に TypeScript のコンパイルをするように指定しています。 TypeScript のコンパイル設定は下記の tsconfig
に記述。
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": true,
"noImplicitAny": false,
"declaration": true,
"moduleResolution": "node",
"rootDir": "lib"
},
"files": [
"node_modules/angular2/typings/browser.d.ts",
"lib/components.ts",
"lib/components/fa-stack.component.ts",
"lib/components/fa.component.ts"
],
"exclude": [
"node_modules"
]
}
Angualr2 の Quickstart の例でインポートできるようにしてたらこうなりました。もっといい書き方があるのかもしれません。
パッケージを公開する
省略。公開前にローカルで試すのに npm link
というコマンドが便利でした。
作ったものを使ってみる
- angular2-example-library をインポートするときのパスを指定する(SystemJS)
- angular2-example-library インポート時に拡張子(js)を補完するようにする (SystemJS)
- 実際に使うファイルで import する
サンプルコードの例は Angular2 の QuickStart のものです。
<script>
System.config({
defaultExtension: 'js',
packages: {
app: {
format: 'register',
defaultExtension: 'js'
},
// これを書かないとロードするときに .js 拡張子が補完されなかった
"angular2-example-library": {"defaultExtension": 'js'}
},
map: {
// 実際のファイルのパスを指定する。
'angular2-example-library': 'node_modules/angular2-example-library/lib'
}
});
System.import('app/main').then(null, console.error.bind(console));
</script>
// インポートする
import {ExampleComponent} from 'angular2-example-library/components';
@Component({
selector: 'my-app',
template: '<example></example>',
directives: [ExampleComponent], // 利用可能
})
export class AppComponent {}
ブラウザを開いたときに、<example></example>
が変換されていれば成功!
おわりに
以上で Angular2 のライブラリを作成してみました。
npm パッケージ作成のベストプラクティス 的なものを調べている最中であり、ディレクトリ構造や設定ファイルなどは改善の余地がありそうでした。
ちなみに自分が作っていて出来上がったものは angular2-fontawesome (作成途中) で、Angular1.x の directive には存在する replace: true
でタグを書き換える挙動がないっぽい( 議論中? )ので実装を待つため一時終了となっています。
現在 Angular2 は ベータ版 なので、挙動が今後変わる可能性がある点に注意です。
最後まで読んでいただきありがとうございました。