このエントリーをはてなブックマークに追加

私がよく Angular プロジェクトと一緒にセットアップしている、5 つのパッケージの導入手順を紹介します。

  1. Tailwind CSS
  2. Jest
  3. Angular Testing Library
  4. ESLint
  5. Prettier

動作検証したバージョンは以下の通りです。

  • 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.

おわりに

開発を便利にするパッケージは、日々バージョンアップを繰り返して、より便利なパッケージへと進化を遂げています。それと同時に、メモしておいたセットアップ手順が古くなり、新しい手順探しの旅に出ることがしばしばあります。

この記事もいずれ古い手順となりますが、少しの間でもみなさまのお役に立てれば幸いです。


このエントリーをはてなブックマークに追加

4/11(月)、PHPerKaigi2022 Day2にて、「PHPerでもできる!マイクロサービス」を発表します。
ニコニコ生放送の画面では一部ページが見づらい可能性があるため、スライドを事前に公開します。
Discordでたくさんの方とお話したいと思いますので、ぜひ感想をお聞かせください。
ココネリにいますので、パブリックビューイング参加の方は直接声をかけていただくのでも大丈夫です。
13:25〜TrackBでお待ちしています ☺️


このエントリーをはてなブックマークに追加

なんとPHPerKaigi2022の04/11(月)12:45〜 Track Aにてスポンサーセッション

「社内パッケージの再利用に #Satis を使っている話」というタイトルでLTをしました!!!

フィードバックいただけると嬉しいです :bow: