私がよく Angular プロジェクトと一緒にセットアップしている、5 つのパッケージの導入手順を紹介します。
動作検証したバージョンは以下の通りです。
- Angular v13.3
- Node v16.14
- Tailwind v3.0
- Jest v27.5
- Angular Testing Library v11.4
- ESLint v8.12
- Prettier v2.6
コードは GitHub リポジトリに保存しています。よければ参考にしてください。 https://github.com/ringtail003/angular13-scaffold
プロジェクトを作成する
それではプロジェクトを作成しましょう。 名前は仮で my-project としています。
npx @angular/cli new my-project
ルーティングとスタイルシートの記法は、お好みで選択します。
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? SCSS
Tailwind CSS を導入する
Tailwind CSS は膨大な CSS ユーティリティクラスの集合です。CLI でのビルドと、その設定が細やかに調整できるところが気に入って使っています。
関連パッケージをインストールします。
npm install --save-dev tailwindcss
ビルドの設定ファイルを作成します。
npx tailwindcss init
ビルドの設定ファイルを以下のように変更します。
// tailwind.config.js
module.exports = {
content: [
"./src/app/**/*.(ts|html)"
],
theme: {
extend: {},
},
plugins: [],
}
Angular のスタイル読み込みのエントリポイントに、ユーティリティクラスの読み込みを追加します。
// src/styles.scss
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
サンプルとして Tailwind CSS のユーティリティクラスを記述して、外観が変わることをブラウザで確認しておきましょう。使用できるユーティリティクラスは 公式ドキュメント をご確認ください。
<!-- src/app/app.component.html -->
<div class="content" role="main">
<div class="bg-red-300 text-red-700 rounded p-6 m-12">
<span>{{ title }} app is running!</span>
</div>
</div>
npm start -- --open
Jest を導入する
Jest は擬似的なブラウザの JSDOM とアサーションを一体化させた、テスティングフレームワークです。Angular にデフォルトで含まれる Karma / Jasmine に不満はありませんが、ここ最近は Jest を使っています。
関連パッケージをインストールします。
npm install --save-dev jest jest-preset-angular @angular-builders/jest @types/jest
npm test
で Jest が呼び出されるよう package.json
を変更します。
// package.json
"scripts": {
"test": "npm run jest", // <=== 追加
"jest": "jest" // <=== 追加
}
テスト環境の TypeScript の設定を以下のように変更します。
// tsconfig.spec.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"module": "CommonJs",
"esModuleInterop": true,
"types": [ "jest" ]
},
"files": [ "src/polyfills.ts" ],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
Jest の設定ファイルを追加します。
touch jest.config.js src/setup-jest.ts
設定ファイルを以下のように変更します。
// jest.config.js
module.exports = {
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['<rootDir>/src/setup-jest.ts'],
globalSetup: 'jest-preset-angular/global-setup',
moduleDirectories: ['node_modules', '<rootDir>'],
};
// src/setup-jest.ts
import 'jest-preset-angular/setup-jest';
angular.json
のテスト環境のアーキテクトを以下のように変更します。
// angular.json
"projects": {
"my-projects": {
"architect": {
"test": { // <=== 変更
"builder": "@angular-builders/jest:run",
"options": {
"configPath": "jest.config.js",
"tsConfig": "tsconfig.spec.json",
"globalMocks": ["getComputedStyle", "doctype"],
"no-cache": true,
"reporters": []
}
}
}
}
}
Karma の関連ファイルとパッケージを削除します。
rm src/test.ts karma.conf.js
npm uninstall karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter jasmine-core @types/jasmine
Jasmine と Jest には、共通した名前のグローバル関数やマッチャーが存在します。そのためプロジェクトのひな型に含まれるシンプルなテストは、Jest 用にシンタックスを書き換える必要がありません。
CLI でコマンドを叩いて、テストがパスすることを確認しておきましょう。
npm test
PASS src/app/app.component.spec.ts
AppComponent
✓ should create the app (114 ms)
✓ should have as title 'my-project' (32 ms)
✓ should render title (32 ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 4.78 s
Ran all test suites.
Angular Testing Library を導入する
Angular Testing Library は、テストのためのユーティリティ群です。UI テストをシンプルに書くための Testing Library の思想にもとづいた、グローバル関数やオブジェクトが提供されます。
関連パッケージをインストールします。
npm install --save-dev @testing-library/angular @testing-library/dom @testing-library/jest-dom
さきほど「Jest を導入する」で作成したファイルに、設定を追加します。
// src/setup-jest.ts
import 'jest-preset-angular/setup-jest';
import '@testing-library/jest-dom'; // <== 追加
テスト環境の TypeScript の設定を変更します。
// tsconfig.spec.json
{
"compilerOptions": {
"types": [
"jest",
"testing-library__jest-dom" // <=== 追加
]
}
}
【参考情報】Angular Testing Library のユーティリティを使って、サンプルのテストファイル app.component.spec.ts
を書き換えた例を掲載します。
// src/app/app.component.spec.ts
import { render, screen } from '@testing-library/angular';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
it(`should have as title 'my-project'`, async () => {
const { fixture } = await render(AppComponent);
expect(fixture.componentInstance.title).toBe('my-project');
});
it('should render title', async () => {
await render(AppComponent);
expect(screen.getByText('my-project app is running!')).toBeInTheDocument();
});
});
CLI でコマンドを叩いて、テストがパスすることを確認しておきましょう。
npm test
PASS src/app/app.component.spec.ts
AppComponent
✓ should create the app (114 ms)
✓ should have as title 'my-project' (32 ms)
✓ should render title (32 ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 4.78 s
Ran all test suites.
ESLint を導入する
Angular 13 系では Linter がデフォルトでインストールされていません。
npm run ng lint
Lint を実行すると ESLint のインストールを促されるので y キーで続けます。
Would you like to add ESLint now?
スキーマティクスでのインストール確認が表示されます。これも y キーで続けます。
The package @angular-eslint/schematics@13.2.1 will be installed and executed.
Would you like to proceed? (Y/n)
インストールが完了すると angular.json
が更新され ESLint の設定ファイルが作成されます。設定を何も変更しなければ、デフォルトのルール群が適用されます。
【参考情報】サンプルとして、公式ドキュメント を参考に追加のルール no-console
を適用してみましょう。
// eslintrc.json
{
"overrides": [
"rules": {
...
"no-console": "error" // <=== 追加
}
]
}
このルールは、ブラウザのデバッグコンソールへの出力をコミットしないことに役立ちます。Lint を実行すると、該当箇所がエラーとして検出されます。
npm run lint
Linting "my-project"...
/my-project/src/main.ts
error Unexpected console statement no-console
✖ 1 problem (1 error, 0 warnings)
// src/main.ts
...
platformBrowserDynamic()
.bootstrapModule(AppModule)
// 12行目:デバッグコンソールへの出力
.catch((err) => console.error(err));
エラーとして検出された main.ts
はプロジェクトのひな型として最初から存在しているファイルです。Lint のチェックから除外したいときは ESLint の設定にファイルパターンを追加します。
// eslintrc.json
{
"ignorePatterns": [
"src/*.ts" // <=== 追加
],
}
またはコメントを使って、ファイルの一部を Lint のチェックから除外することもできます。
// src/main.ts
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err)); // eslint-disable-line
除外の設定を加えると、テストは無事にパスします。
npm run lint
Linting "my-project"...
All files pass linting.
Prettier を導入する
Prettier は人気のコード整形ツールです。
関連パッケージをインストールします。
npm install --save-dev prettier
Prettier の設定ファイルを追加します。
touch prettier.config.js
かんたんに呼び出せるよう、お好みで npm scripts に追加します。
{
"scripts": {
"prettier": "prettier" // <=== 追加
}
}
設定ファイルの内容は 公式ドキュメント を参考にお好みでカスタマイズしましょう。
// prettier.config.js
module.exports = {
trailingComma: "es5",
tabWidth: 4,
semi: false,
singleQuote: true,
};
Prettier を実行すると、プロジェクトのファイルを一括で整形することができます。
npm run prettier -- --write ./src/app
src/app/app-routing.module.ts 290ms
src/app/app.component.html 35ms
src/app/app.component.scss 17ms
src/app/app.component.spec.ts 12ms
src/app/app.component.ts 9ms
src/app/app.module.ts 8ms
Prettier の整形ルールは、先に導入した ESLint のルールとコンフリクトすることがあります。例のひとつとして、インデントに関するルールがあげられます。
// Prettierの設定
// prettier.config.js
module.exports = {
// インデントはスペース 4 つ
tabWidth: 4,
...
};
// ESLintの設定
// .eslintrc.json
{
"overrides": [{
"rules": {
// インデントはスペース 2 つ
"indent": ["error", 2]
}
}]
}
この設定では、インデントの扱いが異なるため、Prettier がコード整形したファイルが ESLint のエラーとして検出されてしまいます。
npm run lint
/my-project/src/app/app.module.ts
8:1 error Expected indentation of 2 spaces but found 4 indent
9:1 error Expected indentation of 2 spaces but found 4 indent
10:1 error Expected indentation of 2 spaces but found 4 indent
11:1 error Expected indentation of 2 spaces but found 4 indent
eslint-config-prettier を使うと、コンフリクトする ESLint のルールをオフにできるため、こちらも導入します。
npm install --save-dev eslint-config-prettier
ESLint のルールに Prettier の整形ルールを追加します。
// .eslintrc.json
{
"overrides": [{
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates",
"prettier" // <=== 追加
]
}]
}
かんたんに呼び出せるよう、お好みで npm scripts に追加します。
{
"scripts": {
"eslint-config-prettier": "eslint-config-prettier" // <=== 追加
}
}
eslint-config-prettier を実行すると、不要なルールや、コンフリクトしているルールがリストアップされます。
npm run eslint-config-prettier src/app/*.ts
The following rules are unnecessary or might conflict with Prettier:
- indent
ESLint の設定からコンフリクトしているルール indent
を削除します。その後 Lint を実行すると、エラーは検出されません。
npm run lint
Linting "my-project"...
All files pass linting.
おわりに
開発を便利にするパッケージは、日々バージョンアップを繰り返して、より便利なパッケージへと進化を遂げています。それと同時に、メモしておいたセットアップ手順が古くなり、新しい手順探しの旅に出ることがしばしばあります。
この記事もいずれ古い手順となりますが、少しの間でもみなさまのお役に立てれば幸いです。