この記事は Angular Advent Calendar 2019 の 1 日目の記事です。
今年も 1 日目に飛び込みました @kasaharu です。
今年はなんと Angular #2 Advent Calendar 2019 もあるみたいですよ。
Angular アプリケーションのための GitHub template を作る
Angular アプリケーションを new したあとにやったほうがいいことを詰め込んで GitHub Pages にデプロイまでできる GitHub template を作ったお話です。
Angular アプリケーション以外でも役に立つことがある(?)かもしれません
完成品はこちら
使い方
テンプレートからリポジトリを作成する に書かれている手順で GitHub template からリポジトリを作成します。
リポジトリが作成されたら以下の手順で clone から deploy までを実施します。
$ git clone [the-repositoryname]
$ cd [the-repositoryname]
$ yarn
$ yarn ng deploy --base-href=/[the-repositoryname]/
デプロイ完了後 https://[your-username].github.io/[the-repositoryname]
にアクセスするとページが表示されます
何が盛り込まれているか?
ここから先は kasaharu/ng-basis の作り方です。
kasaharu/ng-basis を template として GitHub リポジトリを作れば以下の作業が必要なくなります!
準備
まずは Angular アプリケーションを準備。今回は Angular CLI v9.0.0-rc.3 を使用しており Routing はありで stylesheet format は SCSS を選択して開始しています。
$ npx @angular/cli@next new ng-basis
// ※ 作成したタイミングの @next が v9.0.0-rc.3 だっただけで @next をつけると v9.0.0-rc.3 になるわけではないです
生成されたら以下のコマンドを実行。
$ cd ng-basis
$ yarn start
たったこれだけで Angular アプリケーションが起動します
準備ができたのでここから ng-basis を使うと設定済みの を紹介します。
Formatter & Linter の導入
なぜ?
チームで開発をすると考え方や経験の差で書き方がバラけて全体の可読性が下がるという問題が出てきがちです。
スペースや改行位置が統一されていない、という粒度のものから循環的複雑度が上がりメンテナンスが困難という問題まで起こる可能性があります。
小さな書き方の差分が議論のもとになってしまうことがあるのでそれらを Formatter & Linter に任せておけば悩みが少なくなると思います。
手順
Formatter にはすっかりデファクトになった Prettier を Linter には TSLint と stylelint を採用しました。
Prettier
$ yarn add prettier --dev --exact
フォーマットルールを書くための設定ファイル .prettierrc.json
とフォーマットしたくないファイルの一覧を書く .prettierignore
を用意します。
それぞれ下記のような感じで書いています。
npm scripts でも実行できるように package.json に下記を追加します。
"scripts": {
...,
"prettier": "prettier --write './**/*.{ts,html,scss}'",
"prettier:check": "prettier --check './**/*.{ts,html,scss}'"
},
デフォルトのコードに Formatter する余地があるので $ yarn prettier
を実行しておきます。
TSLint
TypeScript でも Linter は ESLint に移行していく流れですが Angular CLI が TSLint を使っているのでまだ Angular way に乗っておきます。
Angular CLI でアプリケーションを作成した場合 TSLint はインストール済みなのでルールの更新をします。
更新後は tslint.json のようにしました。
チームごとにこだわりポイントは異なると思うので改善の余地はあります。
ルールを変更すると既存のコードが lint error になるので $ yarn lint --fix
で修正しておきます。
src/test.ts
は import 順に意味があるので /* tslint:disable:ordered-imports */
をして TSLint のルールを無効化しておきます
stylelint
SCSS のための Linter には stylelint を導入します。
すぐに使えるようにおすすめの standard ルールもあるのでそれも一緒にインストールします。
$ yarn add stylelint stylelint-config-standard -D
.stylelintrc
を用意して下記の設定をします。
Angular CLI を使って component を作成するとデフォルトで空のスタイルファイルが生成されるので空のスタイルファイルがあっても許容するように今回は no-empty-source
のルールを無効化しました。
{
"extends": "stylelint-config-standard",
"rules": {
"no-empty-source": null
}
}
CompilerOptions の見直し
Angular アプリケーションには 2 つの CompilerOptions があり、一つは TypeScript CompilerOptions でもう一つは Angular CompilerOptions です。
どちらも tsconfig.json
に書くので必要なルールを追記します。
TypeScript CompilerOptions
TypeScript の CompilerOptions は ここ で見ることができます。
strict
TypeScript のルールを一気に厳格にするルールです。以下のルールが有効になります。
ルール名 | ルール |
---|---|
noImplicitAny | 暗黙の any を許可しない |
noImplicitThis | 暗黙の any を返す this 式を許可しない |
alwaysStrict | use strict をつける |
strictBindCallApply | 関数の bind, call, apply メソッドのチェックが厳格になる |
strictNullChecks | null チェックが厳格になる |
strictFunctionTypes | 関数型のチェックが厳格になる |
strictPropertyInitialization | class プロパティの初期値のチェックが厳格になる |
Angular CLI の v9 からはアプリケーションを ng new
する際に --strict
オプションが指定できるようになるので strict な設定が求められているのがわかります。
ref. https://github.com/angular/angular-cli/pull/14905#issuecomment-531896302
noUnusedLocals / noUnusedParameters
未使用のローカル変数やパラメータがある場合にエラーになるルールが有効になる。
noImplicitReturns
関数内のすべての条件が返り値を返さないとエラーになるルールが有効になる。
Angular CompilerOptions
Angular の CompilerOptions は ここ で見ることができます。
今回取り上げる 2 つは v9 でデフォルト true に設定されるオプションになります。
fullTemplateTypeCheck
テンプレートファイル(*.html)のバインディング式の検証が有効になるルールです。
テストの設定
unit test 時のオプション
デフォルトでは npm scripts で test
は ng test
を実行するようになっているが、ここでは ng test
の 3 つのオプションを紹介します。
オプション名 | 説明 | 設定値 |
---|---|---|
code-coverage | コードカバレッジのレポート | true |
watch | 監視モード | false |
progress | ビルド中のログ出力 | false |
angular.json で test architect のオプションを変更することで設定可能だが、今回は npm scripts でオプションを指定しています。
package.json を以下のように変更します。
- "test": "ng test",
+ "test": "ng test --code-coverage --watch false --progress false",
コードカバレッジ
上の設定で test 実行後にコードカバレッジが表示されるようになるので、続けて karma.conf.js を下記のように変更してコードカバレッジの閾値を設定します。
test 実行後にコードカバレッジが閾値を下回るとエラー(または警告)を出すようになります。
coverageIstanbulReporter:
dir: require('path').join(__dirname, './coverage/ng-basis'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true,
+ thresholds: {
+ emitWarning: false, // true にすると閾値に届いていなくてもエラーにならない
+ global: {
+ statements: 100,
+ lines: 100,
+ branches: 100,
+ functions: 100,
+ },
+ },
},
CI 用の設定
CI 用に HeadlessChrome で動作するように設定を追加します。
設定方法は Configure CLI for CI testing in Chrome にも記載されています。
unit test
unit test は Karma で実行されるので karma.config.js に設定を追加します。
@@ -35,6 +35,12 @@ module.exports = function(config) {
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
+ customLaunchers: {
+ ChromeHeadlessCI: {
+ base: 'ChromeHeadless',
+ flags: ['--no-sandbox'],
+ },
+ },
singleRun: false,
restartOnFileChange: true,
});
また専用の実行コマンドを npm scripts に追加します。
"start": "ng serve",
"build": "ng build",
"test": "ng test --code-coverage --watch false --progress false",
+ "test:ci": "yarn test --browsers=ChromeHeadlessCI",
"lint": "ng lint",
"e2e": "ng e2e",
"stylelint": "stylelint './**/*.scss'",
E2E test
E2E test は Protractor で実行されるので専用の protractor-ci.conf.js を用意します。
const config = require('./protractor.conf').config;
config.capabilities = {
browserName: 'chrome',
chromeOptions: {
args: ['--headless', '--no-sandbox']
}
};
exports.config = config;
generate command のオプション設定
Angular CLI を使っていると component や service の作成に CLI の generate command を使うのが一般的になります。そのため generate 後に行いたい lint fix などがある程度自動でできると DX の向上が見込まれます。
@schematics/angular:component
プロパティ | 説明 | 設定可能な値 | デフォルト値 |
---|---|---|---|
style | CSS プリプロセッサの指定 | css, scss, sass, less, styl | css |
changeDetection | change detection strategy の指定 | Default, OnPush | Default |
lintFix | lint --fix の指定 | true / false | false |
component 以外にも class, directive, module, pipe, service にも lintFix
は必要なので設定します。
@@ -2,6 +2,28 @@
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
+ "schematics": {
+ "@schematics/angular:class": {
+ "lintFix": true
+ },
+ "@schematics/angular:component": {
+ "style": "scss",
+ "changeDetection": "OnPush",
+ "lintFix": true
+ },
+ "@schematics/angular:directive": {
+ "lintFix": true
+ },
+ "@schematics/angular:module": {
+ "lintFix": true
+ },
+ "@schematics/angular:pipe": {
+ "lintFix": true
+ },
+ "@schematics/angular:service": {
+ "lintFix": true
+ }
+ },
"projects": {
"ng-basis": {
"projectType": "application",
デフォルトでは projects
-> ng-basis
(プロジェクト名) 配下に設定されているが Multiple projects などで複数のプロジェクト管理している場合にすべてのプロジェクトに同じ schematics のルールを適用するには今回のようにトップレベルで指定するのが楽です。
Production build の source map configuration
デフォルトでは source map が出力しない設定になっているが、バンドルはしたくないが出力だけしたいケースがあります。
Optimization and source map configuration にあるように下記のような設定をすることが可能です。
"build": {
...
"configurations": {
"production": {
...
"sourceMap": { "scripts": true, "styles": false, "hidden": true, "vendor": true },
}
}
}
Reset CSS
Reset CSS として HTML5 Doctor Reset CSS を使用します。
Reset CSS を src/assets/styles/reset.css
として配置し angular.json の build と test architect の styles で読み込みます。
Node.js のバージョン管理
フロントエンド開発をやっていると開発環境で使用する Node.js のバージョン管理も重要になります。
asdf や nodenv を使っていると .node-version
があると自動的に Node.js のバージョンが切り替わり便利なので .node-version
を配置します。
12.13.0
Renovate
フロントエンド開発はパッケージアップデートととの戦いにもなります。
継続的なパッケージアップデートのためにも Renovate を導入します。
Renovate の使い方は https://qiita.com/kasaharu/items/1af74b49e98658cf9a8e にも書いています!
Angular CLI で最初にインストールされているパッケージは Agnular のバージョンアップするさいに ng update
で上げるほうが Angular way から外れないのでここでは自分で追加でインストールしたもののみを enable にします。
※ GitHub template をもとに作ったリポジトリに適用するには ここ から設定をする必要があります。
CI
format, lint, build, test のチェックが自動でできるように CI を導入します。
今回は CircleCI を選択しています。
※ GitHub template をもとに作ったリポジトリに適用するには CircleCI - dashboard から Add Projects をする必要があったので、設定無しで使用できる GitHub Actions に変更しました。
CircleCI を使う場合は .circleci/config.yml が参考になると思います。
GitHub Actions の設定は以下
name: Node CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Get yarn cache
uses: actions/cache@v1
with:
path: node_modules
key: ${{ runner.OS }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.OS }}-yarn-
- name: yarn install
run: |
yarn
env:
CI: true
- name: TSLint
run: |
yarn lint
env:
CI: true
- name: stylelint
run: |
yarn stylelint
env:
CI: true
- name: format
run: |
yarn prettier:check
env:
CI: true
- name: build
run: |
yarn build --prod
env:
CI: true
- name: unit test
run: |
yarn test:ci
env:
CI: true
- name: Archive code coverage results
uses: actions/upload-artifact@v1
with:
name: code-coverage-report
path: coverage
- name: e2e test
run: |
yarn e2e:ci
env:
CI: true
Deploy
アプリケーションは最終的にデプロイが必要になります。
今回は GitHub Pages にデプロイをすることにします。
GitHub Pages にデプロイするために angular-cli-ghpages というパッケージを使用します。
このパッケージは下記のように $ ng add
でインストールが可能です。
$ yarn ng add angular-cli-ghpages
さらにデプロイも簡単で下記のコマンドを実行すると https://kasaharu.github.io/ng-basis にデプロイされます。
$ yarn ng deploy --base-href=/ng-basis/
まとめ
今回はコードを書かずにデプロイまでできる Angular アプリケーション用の GitHub template を作った話をしました。
その過程でフロントエンド開発をする上で最初にやっておきたいこと、Angular アプリケーションを作っていく上で設定してあると楽になることを盛り込みました。
Angular や各種パッケージは継続的にアップデートしていく予定です。
おわり
明日は @ver1000000 さんです。