Created
March 25, 2020 17:33
-
-
Save okunokentaro/9e23e695d75affa8538174cd6de04fad to your computer and use it in GitHub Desktop.
Angular-CLIチートシート
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2016/12/30 にQiitaに投稿した記事のアーカイブです | |
--- | |
@armorik83です。今回は[`angular-cli`](https://github.com/angular/angular-cli)についてまとめます。 | |
# angular-cli | |
- https://cli.angular.io/ | |
> Prototype of a CLI for Angular 2 applications based on the ember-cli project. | |
`angular-cli`はAngularの2.x以上(本稿ではAngularと記述する)を用いたアプリケーションの開発を補助するCLIツールである。 | |
## インストール | |
インストールは至って簡単だ。 | |
``` | |
npm i -g angular-cli | |
``` | |
`node_modules`のグローバル空間にインストールするため抵抗がある人もいるかもしれないが、その場合適宜工夫してもらいたい。基本的にコマンドラインツールとして使うので、筆者はあまり問題ないと考えているが、バージョン違いによる挙動の差異があり得るため、チームで運用する際はメンバー間でバージョンについて注意されたい。 | |
## angular-cliの必然性 | |
拙記事に『[npm iしてAngualr 2のHello World!を書くところまで](http://qiita.com/armorik83/items/ae737ab584012a0f5876)』というものがあるが、現時点ではこの記事の内容より`angular-cli`によって生成された基礎の方が使いやすい。利点を挙げる。 | |
- Angular公式が良と考えているディレクトリ構成に従える | |
- [webpack](https://webpack.github.io/)などのバンドラーの環境構築を自動で行うため意識しなくてよい | |
- `ng serve`による開発中のブラウザ上でのプレビューが高速 | |
- [AoT](https://angular.io/docs/ts/latest/cookbook/aot-compiler.html)を前提としているビルド | |
- Lintやテストの環境構築が不要ですぐに利用可能 | |
一方で、これらはそのまま欠点にもなりうる。 | |
- 独自のドメインレイヤーが多い場合どこに置けばいいかの指標を`angular-cli`は提示しない | |
- Angularで完結しない場合、たとえばBabelのトランスパイルを別途挟む必要があるときなど、webpackの設定がブラックボックス化されているため拡張が面倒 | |
- Lintは[TSLint](https://palantir.github.io/tslint/)、テストフレームワークは[Jasmine](https://jasmine.github.io/)に固定される | |
ただし、JavaScriptやAngularの熟練者であれども`angular-cli`が提供するメリットがこれらの欠点を上回っている(と筆者は感じている)ため、多少の束縛を踏まえて`angular-cli`を前提とした開発フローを検討するほうがよい。 | |
## 新規作成 | |
`angular-cli`を用いたアプリケーションの新規作成はコマンドで行える。 | |
``` | |
ng new myapp | |
``` | |
`myapp`は任意のアプリケーション名だ。このコマンドを実行することでnpmによるインストールと各種ファイルの自動生成を行う。では、このときの生成結果をみてみよう。なお、本稿での`angular-cli`のバージョンは`1.0.0-beta.24`である。 | |
``` | |
. | |
├── README.md | |
├── angular-cli.json | |
├── e2e | |
│ ├── app.e2e-spec.ts | |
│ ├── app.po.ts | |
│ └── tsconfig.json | |
├── karma.conf.js | |
├── node_modules | |
│ ├── @angular | |
│ │ ├── common | |
│ │ ├── compiler | |
│ │ ├── compiler-cli | |
│ │ ├── core | |
│ │ ├── forms | |
│ │ ├── http | |
│ │ ├── platform-browser | |
│ │ ├── platform-browser-dynamic | |
│ │ ├── router | |
│ │ └── tsc-wrapped | |
│ ├── @angular-cli | |
│ │ ├── ast-tools | |
│ │ └── base-href-webpack | |
│ ├── @ngtools | |
│ │ └── webpack | |
│ ├── @types | |
│ │ ├── jasmine | |
│ │ ├── node | |
│ │ ├── q | |
│ │ └── selenium-webdriver | |
│ ├── abbrev | |
省略 | |
├── package.json | |
├── protractor.conf.js | |
├── src | |
│ ├── app | |
│ │ ├── app.component.css | |
│ │ ├── app.component.html | |
│ │ ├── app.component.spec.ts | |
│ │ ├── app.component.ts | |
│ │ └── app.module.ts | |
│ ├── assets | |
│ ├── environments | |
│ │ ├── environment.prod.ts | |
│ │ └── environment.ts | |
│ ├── favicon.ico | |
│ ├── index.html | |
│ ├── main.ts | |
│ ├── polyfills.ts | |
│ ├── styles.css | |
│ ├── test.ts | |
│ └── tsconfig.json | |
└── tslint.json | |
``` | |
- `angular-cli.json` | |
- `e2e/` | |
- `karma.conf.js` | |
- `protractor.conf.js` | |
- `tslint.json` | |
これらの自動生成が特に嬉しい。e2e周りは、環境構築を怠りそのまま実施しない例も多いと予想するので、最初から準備されているならば取り組みやすいだろう。`.gitignore`も生成されているのは地味に嬉しい点だ。 | |
次に`src/`内をみていく。 | |
``` | |
. | |
├── app | |
│ ├── app.component.css | |
│ ├── app.component.html | |
│ ├── app.component.spec.ts | |
│ ├── app.component.ts | |
│ └── app.module.ts | |
├── assets | |
├── environments | |
│ ├── environment.prod.ts | |
│ └── environment.ts | |
├── favicon.ico | |
├── index.html | |
├── main.ts | |
├── polyfills.ts | |
├── styles.css | |
├── test.ts | |
└── tsconfig.json | |
``` | |
基本的には`app/`以下にアプリケーションのコードが格納されるという認識でよい。 | |
- `assets/` | |
- 画像や、どのComponentにも紐つかないCSS、`i18n`言語ファイルなどを格納すればいいはず | |
- `index.html`, `main.ts`, `styles.css`, `test.ts` | |
- それぞれのエントリポイントとなるファイル | |
- 特に`test.ts`は自前で記述するとかなり面倒なので助かる | |
# 各種自動生成のチートシート | |
本稿の主題でもあるチートシートを記録する。`angular-cli`では`ng g component my-new-component`のようにコマンドを実行することで、そのAngularアプリケーションに新しくComponentやServiceを追加できる。そのときの生成先や生成ファイル数などを思い出すためのものだ。 | |
## `ng g component` | |
`ng g component [name]`はComponentを新規に作成する。 | |
``` | |
ng g component foo-bar-baz | |
installing component | |
create src/app/foo-bar-baz/foo-bar-baz.component.css | |
create src/app/foo-bar-baz/foo-bar-baz.component.html | |
create src/app/foo-bar-baz/foo-bar-baz.component.spec.ts | |
create src/app/foo-bar-baz/foo-bar-baz.component.ts | |
update src/app/app.module.ts | |
``` | |
標準では、常に`css`, `html`, テスト用`spec.ts`, `ts`の4つをセットで生成し、それらを1ディレクトリに格納する。`ng g component`似続けてキャメルケース`(CamelCase)`を入力しても自動的にケバブケース`(kebab-case)`に変換される。ここに`my-component`などと入力すれば`MyComponentComponent`というclassが出力されるため、`component`を名前に含む必要はない。 | |
```foo-bar-baz.component.ts | |
import { Component, OnInit } from '@angular/core'; | |
@Component({ | |
selector: 'app-foo-bar-baz', | |
templateUrl: './foo-bar-baz.component.html', | |
styleUrls: ['./foo-bar-baz.component.css'] | |
}) | |
export class FooBarBazComponent implements OnInit { | |
constructor() { } | |
ngOnInit() { | |
} | |
} | |
``` | |
`ts`では`selector`に常に`app-`接頭辞が付与される。`templateUrl`と`styleUrls`は自動的に記述されている。そして`app.module.ts`に自動的にこのComponentが読み込まれるようになっている。 | |
```app.module.ts | |
import { BrowserModule } from '@angular/platform-browser'; | |
import { NgModule } from '@angular/core'; | |
import { FormsModule } from '@angular/forms'; | |
import { HttpModule } from '@angular/http'; | |
import { AppComponent } from './app.component'; | |
import { FooBarBazComponent } from './foo-bar-baz/foo-bar-baz.component'; | |
@NgModule({ | |
declarations: [ | |
AppComponent, | |
FooBarBazComponent | |
], | |
imports: [ | |
BrowserModule, | |
FormsModule, | |
HttpModule | |
], | |
providers: [], | |
bootstrap: [AppComponent] | |
}) | |
export class AppModule { } | |
``` | |
## `ng g directive` | |
`ng g directive [name]`はDirectiveを新規に作成する。 | |
``` | |
ng g directive foo | |
installing directive | |
create src/app/foo.directive.spec.ts | |
create src/app/foo.directive.ts | |
update src/app/app.module.ts | |
``` | |
標準的には`app/`直下に配置されることに注意されたい。これを回避したい場合、例えば`app/directives/`下に配置したければ次のようにする。 | |
``` | |
mkdir ./src/app/directives && cd ./src/app/directives | |
ng g directive foo | |
installing directive | |
create src/app/directives/foo.directive.spec.ts | |
create src/app/directives/foo.directive.ts | |
update src/app/app.module.ts | |
``` | |
要するにCurrent Directoryを考慮して生成する。 | |
``` | |
pwd | |
/Users/armorik83/Desktop/myapp | |
ng g directive foo --flat false | |
installing directive | |
create src/app/foo/foo.directive.spec.ts | |
create src/app/foo/foo.directive.ts | |
update src/app/app.module.ts | |
``` | |
Rootで`--flat false`を付けることで`[name]/[name].directive.ts`を生成する。このオプションもCurrent Directoryを考慮する。オプションについては次節にてまとめる。 | |
``` | |
import { Directive } from '@angular/core'; | |
@Directive({ | |
selector: '[appFoo]' | |
}) | |
export class FooDirective { | |
constructor() { } | |
} | |
``` | |
`ts`側は`selector`が`[appFoo]`とキャメルケース指定になっている点に注意だ。 | |
## `ng g pipe` | |
`ng g pipe [name]`はPipeを新規に作成する。Directiveとほぼ同様である。 | |
``` | |
ng g pipe foo | |
installing pipe | |
create src/app/foo.pipe.spec.ts | |
create src/app/foo.pipe.ts | |
update src/app/app.module.ts | |
``` | |
```foo.pipe.ts | |
import { Pipe, PipeTransform } from '@angular/core'; | |
@Pipe({ | |
name: 'foo' | |
}) | |
export class FooPipe implements PipeTransform { | |
transform(value: any, args?: any): any { | |
return null; | |
} | |
} | |
``` | |
## `ng g service` | |
`ng g service [name]`は`Injectable`なclassを新規に作成する。 | |
``` | |
ng g service foo | |
installing service | |
create src/app/foo.service.spec.ts | |
create src/app/foo.service.ts | |
WARNING Service is generated but not provided, it must be provided to be used | |
``` | |
ディレクトリ構成だが、`app/`以下に直接配置するのは規模拡大時に大量に並ぶことが想定されるため避けたい。筆者の経験則としては`app/services/`とするか`app/foo/foo.component.ts`と同階層に`app/foo/foo.service.ts`としたい。この辺りは作成しようとするServiceの性質に合わせて考えればよいだろう。 | |
そして`WARNING Service is generated but not provided, it must be provided to be used`とあるように、`app.module.ts`に自動で追記**されない**点には注意すべきである。これはServiceを一律でprovideするかComponent単位でprovideするか開発者が判断せねばならないためで、自動化が困難であることに由来する。オプションで自動追記をしてくれないかと探したが、現時点ではそのようなオプションは用意されていなかった。 | |
```foo.service.ts | |
import { Injectable } from '@angular/core'; | |
@Injectable() | |
export class FooService { | |
constructor() { } | |
} | |
``` | |
`ts`出力側はシンプルだ。 | |
## `ng g class` | |
`ng g class [name]`はclassを新規に作成する。 | |
``` | |
ng g class foo | |
installing class | |
create src/app/foo.ts | |
``` | |
このコマンドの真価は`--spec`オプションにある。 | |
``` | |
ng g class bar --spec | |
installing class | |
create src/app/bar.spec.ts | |
create src/app/bar.ts | |
``` | |
`ng g class`においてはspecファイルの自動生成がオフのため、オプションを付与する必要がある(`angular-cli.json`の設定を変更することでも設定が可能)。 | |
```bar.ts | |
export class Bar { | |
} | |
``` | |
```bar.spec.ts | |
import {Bar} from './bar'; | |
describe('Bar', () => { | |
it('should create an instance', () => { | |
expect(new Bar()).toBeTruthy(); | |
}); | |
}); | |
``` | |
わずかこれだけだが、この手間すら面倒がる開発者はきっといるはずだ。 | |
## `ng g interface` | |
`ng g interface [name]`はTypeScriptの`interface`を新規に作成する。 | |
``` | |
ng g interface foo | |
installing interface | |
create src/app/foo.ts | |
``` | |
```foo.ts | |
export interface Foo { | |
} | |
``` | |
複数のコマンドを繋いで一気に生成したい場合などは使えるかもしれないが、単体で使うには結果が寂しい。なお、オプションは定義されていない。 | |
## `ng g enum` | |
`ng g enum [name]`はTypeScriptの`enum`を新規に作成する。 | |
``` | |
ng g enum foo | |
installing enum | |
create src/app/foo.enum.ts | |
``` | |
```foo.enum.ts | |
export enum Foo { | |
} | |
``` | |
TypeScriptのenum自体がいまいち扱いにくいため、個人的にはあまり使うことが無さそうだ。 | |
## `ng g module` | |
`ng g module [name]`は`NgModule`を新規に作成する。ECMAScriptやNode.jsの文脈でのmoduleではない点には気をつけておく。 | |
``` | |
ng g module foo | |
installing module | |
create src/app/foo/foo.module.ts | |
``` | |
```foo.module.ts | |
import { NgModule } from '@angular/core'; | |
import { CommonModule } from '@angular/common'; | |
@NgModule({ | |
imports: [ | |
CommonModule | |
], | |
declarations: [] | |
}) | |
export class FooModule { } | |
``` | |
あまり使うことはないが、覚えておいて損はない。 | |
以上が`ng g`による生成をまとめたものだ。 | |
# 生成オプションのチートシート | |
`ng g`ではオプションが利用できる。実例は先に`ng g directive`の項にて述べた。それぞれのオプションは`angular-cli/packages/angular-cli/blueprints`にて定義されている。該当箇所を下記にまとめる。 | |
- [Component](https://github.com/angular/angular-cli/blob/cdf1d08fdb7720afa05bfa837c380d6551fa782c/packages/angular-cli/blueprints/component/index.js#L14-L23) | |
- [Directive](https://github.com/angular/angular-cli/blob/cdf1d08fdb7720afa05bfa837c380d6551fa782c/packages/angular-cli/blueprints/directive/index.js#L14-L19) | |
- [Pipe](https://github.com/angular/angular-cli/blob/cdf1d08fdb7720afa05bfa837c380d6551fa782c/packages/angular-cli/blueprints/pipe/index.js#L14-L18) | |
- [Service](https://github.com/angular/angular-cli/blob/cdf1d08fdb7720afa05bfa837c380d6551fa782c/packages/angular-cli/blueprints/service/index.js#L10-L13) | |
- [Class](https://github.com/angular/angular-cli/blob/cdf1d08fdb7720afa05bfa837c380d6551fa782c/packages/angular-cli/blueprints/class/index.js#L10) | |
- Interface(定義なし) | |
- Enum(定義なし) | |
- [Module](https://github.com/angular/angular-cli/blob/cdf1d08fdb7720afa05bfa837c380d6551fa782c/packages/angular-cli/blueprints/module/index.js#L9-L12) | |
`--spec`のようにオプションの`name`をハイフン2つで追記すると有効になる。`false`の場合は`--flat false`のようにする。型が`String`ならば`ng g component foo --prefix my`のように直接指定すればよい(この場合`selector: 'my-foo'`となる)。オプション名は分かりやすく名付けられているので、一つ一つの説明は割愛する。 | |
# 特筆する事項 | |
## スタイルシートの言語選択 | |
- https://github.com/angular/angular-cli#global-styles | |
CSSではなくSassなどの言語を利用したい場合はオプションで切り替えが可能である。 | |
``` | |
ng new sassy-project --style=sass | |
``` | |
プロジェクトの途中で切り替えたい場合は設定ファイルを変更する。 | |
``` | |
ng set defaults.styleExt scss | |
``` | |
## 独自のテンプレートで出力したいとき | |
あまり推奨しないが、テンプレートを改変することも可能だ。たとえばComponentの`ts`ファイルの書式を改変したければ、以下のパスのファイルを変更すればよい。 | |
``` | |
./node_modules/angular-cli/blueprints/component/files/__path__/__name__.component.ts | |
``` | |
``` | |
import { Component, OnInit<% if(viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection) { %>, ChangeDetectionStrategy<% }%> } from '@angular/core'; | |
@Component({ | |
selector: '<%= selector %>',<% if(inlineTemplate) { %> | |
template: ` | |
<p> | |
<%= dasherizedModuleName %> Works! | |
</p> | |
`,<% } else { %> | |
templateUrl: './<%= dasherizedModuleName %>.component.html',<% } if(inlineStyle) { %> | |
styles: []<% } else { %> | |
styleUrls: ['./<%= dasherizedModuleName %>.component.<%= styleExt %>']<% } %><% if(viewEncapsulation) { %>, | |
encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection) { %>, | |
changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %> | |
}) | |
export class <%= classifiedModuleName %>Component implements OnInit { | |
constructor() { } | |
ngOnInit() { | |
} | |
} | |
``` | |
この1行目を次のように変更してみる。 | |
``` | |
import {Component, OnInit<% if(viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection) { %>, ChangeDetectionStrategy<% }%>} from '@angular/core' | |
``` | |
すると出力はこのようになる。 | |
```diff | |
- import { Component, OnInit } from '@angular/core'; | |
+ import {Component, OnInit} from '@angular/core' | |
``` | |
「俺にはセミコロンは不要だ」などという過激派は試してみてもいいだろう。くれぐれもチームで扱う場合は合意を取るように。 | |
# まとめ | |
このように、オプションの使い方を覚えると自動生成にも柔軟性が出てくるので、`angular-cli`の生成挙動が気に入らない場合も自分好みに対応できることが分かった。AoTコンパイルやテスト環境の構築など手間を省ける利点は多いので、`angular-cli`は引き続き推奨していきたい。 | |
それではよいお年を。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment