BunとBiomeで開発環境を構築する

JavaScriptではなくTypeScriptで開発することが多く、そのためのセットアップの手間がそれなりに必要となります。BunというNode.jsランタイムがデフォルトでTypeScriptに対応しているので、環境構築してみました。

ついでにBiomeを使ってLinter、Formatterをセットしていきます。

Bunのインストール

macOSにBunをインストールをインストール方法はいくつかありますが、本記事ではHomebrewでインストールしていきます。

$ brew install oven-sh/bun/bun

それ以外のインストール方法については公式の記事を参照してください。

Biomeのインストール

macOSにBiomeをインストールするにはHomebrewを使います。

$ brew install biome

biomeコマンドが使用可能になるため、プロジェクト個別にBiomeパッケージをインストールしません。

プロジェクトの作成

Bunでプロジェクトを作成する方法にはbun initbun createの2つがあります。テンプレートを元にプロジェクトを作成する場合はbun createを使用し、空のプロジェクトを作成する場合はbun initを使用します。

今回は空のプロジェクトを作成するので、bun initを使用します。

$ mkdir bun-demo
$ cd bun-demo
$ bun init
bun init helps you get started with a minimal project and tries to guess sensible defaults. Press ^C anytime to quit

package name (bun-demo): 
entry point (index.ts): src/index.ts

Done! A package.json file was saved in the current directory.
 + index.ts
 + .gitignore
 + tsconfig.json (for editor auto-complete)
 + README.md

To get started, run:
  bun run index.ts

質問は2つで、パッケージ名(package name)とエントリーポイント(entry point)です。特に変更する必要がなければそのままエンターキーで進めます。

今回はテストケースも作成するので、エントリーポイントはsrc/index.tsにします。

Biomeをセットアップする

Biomeを使用可能にするためのセットアップを行います。Visual Studio Codeで開発する場合、Biomeプラグインを使うのが簡単です。

Preferences>Settingsで設定を開き、Workspaceを選択後に右上のOpen Settings (JSON)をクリックすると、プロジェクトルートに.vscode/settings.jsonが作成されます。

このファイルに以下のように記述します。

{
    "[typescript]": {
        "editor.defaultFormatter": "biomejs.biome",
        "editor.formatOnSave": true,
    },
    "editor.codeActionsOnSave": {
        "source.organizeImports.biome": "explicit"
    }
}

環境によっては一部の設定が不要となる場合がありますが、

        "editor.defaultFormatter": "biomejs.biome",

で、デフォルトのフォーマッターをBiome拡張機能に変更し、

        "editor.formatOnSave": true,

で、変更を保存するときにフォーマットするようにします。

これらの設定はTypeScriptのファイルだけに適用したいため、

    "[typescript]": {
        "editor.defaultFormatter": "biomejs.biome",
        "editor.formatOnSave": true,
    },

のように[typescript]内に書くようにしています。

また、変更を保存するときにインポートを再編成するため、

    "editor.codeActionsOnSave": {
        "source.organizeImports.biome": "explicit"
    }

の設定を行っています。

プログラムを作成して実行する

実際にプログラムを作成して実行してみます。

この後テストしやすいようにmain関数からロジックを分けておきます。

export function greet(name: string): string {
	return `Hello, ${name}!`;
}

greet関数をテストしておきます。Bunが提供するテスティングフレームワークを使ってテストします。

import { expect, test } from "bun:test";
import { greet } from "../src/greet";

test("should return hello world", () => {
	expect(greet("world")).toBe("Hello, world!");
});

テストはbun testコマンドで実行可能です。

$ bun test
bun test v1.1.7 (b0b7db5c)

test/greet.spec.ts:
✓ should return hello world [0.41ms]

 1 pass
 0 fail
 1 expect() calls
Ran 1 tests across 1 files. [57.00ms]

MochaやJestと遜色ない感じで使えます。モック機能もあるのでサードパーティ製パッケージを使う必要はなさそうです。

作成したgreet関数を使ってmain関数を書きます。

import { greet } from "./greet";

function main(args: string[] = process.argv.slice(2)): void {
	console.log(greet("world"));
}

main();

プログラムの実行はbun runコマンドを使用します。

$ bun run src/index.ts
Hello, world!

実行するエントリーポイントを指定して実行します。

Lintの実行

フォーマットは変更の保存時に自動で行われるため、Lintを使う必要はほぼないと思いますが、一応Lintコマンドも確認しておきます。

LintはBiomeを使用します。

$ biome lint src/**/*.ts
Checked 2 files in 4ms. No fixes needed.

Formatterでフォーマットしているので修正が必要な箇所はありませんでした。

まとめ

Bunを使えば、コマンドのインストールを除けばかなり簡単にプロジェクトをセットアップできます。Biomeもセットアップが簡単なので

速度をウリにしている部分もありますが、もう少し大規模なアプリケーションを使わないとなんとも言えないと思いますし、ネットワークなどの方が大きなボトルネックになるので、Node.jsやDenoなどとそれほど際はないかもしれません。

今回作成したプロジェクトは以下になります。

Biomeを使ってLintとFormatをおこなう

フロンドエンド向け垂直統合ツールチェーンRomeが開発終了となり、Rome開発チームのひとりが作成したのがBiomeです。

Rustで構築されたBiomeは既存のFormatter、Linterと比べ非常に高速に動作するように設計されています。設定も非常に簡単でエディタの拡張機能・プラグインも提供されていることから今後のデファクトスタンダードになりそうな予感があります。

本記事ではBiomeのインストールから基本的な使い方、エディタの統合について解説します。

Biomeをインストール

Biomeはグローバルインストールすることは可能ですが推奨されていないため、プロジェクトにインストールします。また、バージョン範囲演算子を使用しないでインストールすることを強く推奨しています。

$ mkdir biome-example
$ cd biome-example
$ npm init -y
$ npm install --save-dev --save-exact @biomejs/biome
$ npx @biomejs/biome init

Node.jsをインストールせずにBiomeを使用したい場合は、Homebrewなどを使ってインストールするスタンドアロン実行形式での利用も可能ですが、本記事では割愛します。

インストール後に初期化をおこなうとbiome.jsonが生成されます。

{
  "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}

基本的な設定は済んでいるので、すぐに使い始められます。

Biomeの使い方

Biomeの基本的な使い方を見ていきます。

Formatter

Prettierのようにソースコードを整形してくれます。指定したディレクトリ内のファイルに対してソースコードの整形をおこなうには次のようなコマンドを実行します。

$ npx @biomejs/biome format src --write

このコマンドではsrcディレクトリを指定してフォーマットを行っていますが、単一ファイルやワイルドカード指定も可能です。

Linter

こちらはESLintの置き換えになります。次のようなコマンドを実行します。

$ npx @biomejs/biome lint src

こちらも単一ファイルの指定やワイルドカードでの指定が可能です。

Formatter+Lint+α

前述のFormatterとLinterに加えて、インポート文の再構成をまとめて実行するには次のようなコマンドを実行します。

$ npx @biomejs/biome check --apply src

通常はこのコマンドを使うことになると思います。

package.jsonにスクリプトを設定する

コマンドが少し長いのでpackage.jsonにスクリプトとして定義しておきましょう。

{
  "name": "biome-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "format": "biome format src --write",
    "lint": "biome lint src",
    "check": "biome check --apply src"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@biomejs/biome": "1.5.3"
  }
}

Visual Studio Codeの拡張機能を使う

開発時に都度コマンド入力するのは手間ですので、エディタ向けの拡張機能を利用するのがよいでしょう。

まずはVisual Studio Codeの拡張機能を使ってみます。

settings.jsonに以下の設定を追加します。

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "editor.codeActionsOnSave": {
    "quickfix.biome": true,
    "source.organizeImports.biome": true
  }
}

以下の設定で、保存時にFormatterが実行されるように設定しています。

  "editor.formatOnSave": true,

デフォルトのFormatterはPrettierにしています。

  "editor.defaultFormatter": "esbenp.prettier-vscode",

言語モードがJavaScriptの場合、FormatterはBiomeになるよう設定しています。

  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },

保存時のアクションに、 Biomeによるフォーマット("quickfix.biome": true)とインポート文の再構成("source.organizeImports.biome": true)をおこなうように設定します。

この設定を行うことで、ファイルの保存時にソースコードの整形とインポート文の再構成をおこなってくれるようになります。

WebStormのプラグインを使う

IntelliJ向けのプラグインも提供されていますので、WebStormで使ってみます。

こちらは⌥⇧ ⌘ L or Ctrl+Alt+Lでファイルの整形ダイアログを表示して必要なオプションにチェックを入れて実行ボタンを押します。

まとめ

Biomeのインストール方法からエディタとの統合までを確認しました。 1つのパッケージで導入できてデフォルトで利用可能となっているだけでなく、エディタとの統合もサポートされているため、小さく始めて大きく育てるには非常に適したツールチェーンだといえます。

これまではPrettierとESLintを使っていましたが今後はBiomeを使ってみようと思います。

textlintで文章の校正を行う

文章を書く時、文法的な誤りや用語の揺らぎは避けたいものです。しかし、自分だけでは気づかないところがあったり、煩雑すぎたりする場合があります。そこで、textlintというツールを使えば、文章の校正を行うことができます。本記事では、textlintについて詳しく紹介し、文章の校正に役立てる方法を解説します。

今回試したコードはhttps://github.com/t0k0sh1/emendationにあります。

textlintがチェック対象としているのは、テキストファイルやマークダウンファイルなどのテキストファイルのみです。WordやExcelなどのファイルを処理する場合はテキストを抽出するなどの工夫をする必要があります。

textlintの導入

自然言語向けのLinterであるtextlintを導入します。

ここでは、校正チェックを行うプロジェクトemendationを作成します。textlintはNode.jsで利用可能はパッケージですので、npm initコマンドで初期化しておきます。

$ mkdir emendation
$ cd emendation
$ npm init -y

textlintのインストール

textlintをインストールします。特段前提条件となるパッケージやライブラリはなく、普通にインストール可能です。

$ npm install textlint

ルールプリセットのインストール

次にルールプリセットをインストールします。技術書や技術系の記事、設計書の執筆を行っている場合は、技術書向けのルールを使用するのがよいでしょう。

$ npm install textlint-rule-preset-ja-technical-writing

lintスクリプトの設定

package.jsonlintを実行できるスクリプトを追加します。filesディレクトリ内にあるテキストファイルを対象にするようにしています。

  "scripts": {
    "lint": "textlint ./files/*.txt"
  },

ルールの適用方法

textlintで使用するルールを適用する方法には、以下の2つの方法があります。

  1. textlintコマンドに—presetオプションで使いたいルールを指定する
  2. .textlintrc.jsonに適用するルールを記述する

実用上は細かいカスタマイズを必要とするため、後者の方法でルールを適用するようにします。

まずは、textlint --initコマンドで.textlintrc.jsonファイルを作成します。

$ textlint --init
.textlintrc.json is created.

コマンドを実行すると以下のようなファイルが生成されます。

{
  "plugins": {},
  "filters": {},
  "rules": {}
}

生成時点ではルールは何も設定されていません。先ほどインストールしたルールプリセットを適用する記述を追加します。

{
  "plugins": {},
  "filters": {},
  "rules": {
    "preset-ja-technical-writing": true
  }
}

動作を確認するために、filesディレクトリに以下のようなsample.txtを作成します。

Vueで作成した確認ダイアログを表示し、OKボタンをクリックしたときだけ処理を続行する方法をボタンクリックの場合とフォームを使ったサブミットの2パターンの実装方法を見ていきました
この考え方は他のフレームワークでも適用可能です。今回はVue 3.3.4で動作確認していますが、Vue 3で実装された機能を使っていないため、Vue 2でも動作すると思います。

このファイルは1行目の「。」が漏れているので、この点が検出されると思います。

では、実際に実行してみます。

$ npm run lint

> emendation@1.0.0 lint
> textlint ./files/*.txt


/Users/t0k0sh1/Workspace/emendation/files/sample.txt
  1:89  error  文末が"。"で終わっていません。           ja-technical-writing/ja-no-mixed-period
  2:84  error  弱い表現: "思います" が使われています。  ja-technical-writing/ja-no-weak-phrase

✖ 2 problems (2 errors, 0 warnings)

2つのエラーが検出されました。

1つは想定どおり「。」が漏れていることを検出していますが、もう1つは想定していなかったエラーです。このエラーは「〜だと思う」という弱い言い回しを検出しているようです。

ルールのカスタマイズ①不要なルールの抑止

不要なルールの抑止の説明を行うためにja-no-weak-phraseのルールを無効化してみます。以下のように記述することでルールを無効化できます。

{
  "plugins": {},
  "filters": {},
  "rules": {
    "preset-ja-technical-writing": {
      "ja-no-weak-phrase": false
    }
  }
}

では、再度実行してルールが抑止されていることを確認します。

$ npm run lint

> emendation@1.0.0 lint
> textlint ./files/*.txt


/Users/t0k0sh1/Workspace/emendation/files/sample.txt
  1:89  error  文末が"。"で終わっていません。  ja-technical-writing/ja-no-mixed-period

✖ 1 problem (1 error, 0 warnings)

先ほどまで検知されていたja-no-weak-phraseのルールが検知されなくなっていることが確認できました。

ルールのカスタマイズ②独自の辞書ルールの追加

辞書ルールを定義するファイルを作成することで、独自の辞書ルールを追加することが可能です。

ファイル名に制約はないですが、ここではprh.yamlファイルを作成します。

まずはルールを使用するように定義を修正します。

{
  "plugins": {},
  "filters": {},
  "rules": {
    "preset-ja-technical-writing": {
      "ja-no-weak-phrase": false
    },
    "prh": {
      "rulePaths": ["./prh.yml"]
    }
  }
}

次に辞書ルールを定義します。

version: 1
rules:
  - expected: View
    patterns:
      - Vue

ここでは動作を確認するために、ViewVueとタイポする想定でルールを作成しています。expectedに正しい書き方、patternsに誤った書き方を記述します。

$ npm run lint

> emendation@1.0.0 lint
> textlint ./files/*.txt


/Users/t0k0sh1/Workspace/emendation/files/sample.txt
  1:1   ✓ error  Vue => View                     prh
  1:89  error    文末が"。"で終わっていません。  ja-technical-writing/ja-no-mixed-period
  2:28  ✓ error  Vue => View                     prh
  2:49  ✓ error  Vue => View                     prh
  2:72  ✓ error  Vue => View                     prh

✖ 5 problems (5 errors, 0 warnings)
✓ 4 fixable problems.
Try to run: $ textlint --fix [file]

Vueがエラーとして検出できることを確認しました。

辞書ルールを定義することで、固有名詞の揺らぎや言い回しの不統一などを検知することが可能になります。

辞書ルール定義の発展した方法

辞書ルールが増えたときに管理が煩雑になりがちです。これを解消するために辞書ルールを分割することを考えます。

以下のように記述することで、ルールを外出しすることが可能です。

version: 1

imports:
  - ./rules/すでに.yml
  - ./rules/かつ.yml
  - ./rules/また.yml

さらに各ルールを指定パスに定義しておきます。

version: 1
rules:
  - expected: すでに
    patterns:
      - 既に
version: 1
rules:
  - expected: かつ
    patterns:
      - /且つ|且/
version: 1
rules:
  - expected: また$1
    patterns:
      - /又(、|は|は、)/
specs:
  - from: 又
  - to: また

この例は、副詞をひらく書き方を正として、ひらいていない書き方を検出するルールとなります。

以下のように例文を用意して動作確認します。

既に会議は始まっており、私たちは遅れている。且つ、プレゼンテーション資料もまだ完成していない。又は、次の会議までに資料を仕上げ、改めて説明することも一つの選択肢だ。

以下が実行結果です。

$ npm run lint

> emendation@1.0.0 lint
> textlint ./files/*.txt


/Users/t0k0sh1/Workspace/emendation/files/sample.txt
  1:1   ✓ error  既に => すでに                                                                                                  prh
  1:23  ✓ error  且つ => かつ                                                                                                      prh
  1:48  ✓ error  又は => または                                                                                                  prh
  1:75  ✓ error  一つ => 1つ
数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。  ja-technical-writing/arabic-kanji-numbers

✖ 4 problems (4 errors, 0 warnings)
✓ 4 fixable problems.
Try to run: $ textlint --fix [file]

辞書ルールで定義した箇所が検出されることが確認できます。

自動訂正を行う

textlintにはルールによって自動訂正を行うことができます。–fixオプションを使うことで、訂正可能なルールについて自動的に訂正を行うことが可能です。

package.jsonlint:fixスクリプトを追加します。

  "scripts": {
    "lint": "textlint ./files/*.txt",
    "lint:fix": "textlint --fix ./files/*.txt"
  },

先ほどチェックしたテキストに対して、lint:fixコマンドを実行することで、自動訂正されることを確認します。

まずは、修正前のテキストを再掲します。

既に会議は始まっており、私たちは遅れている。且つ、プレゼンテーション資料もまだ完成していない。又は、次の会議までに資料を仕上げ、改めて説明することも一つの選択肢だ。

再度、チェックのみを行います。

$ npm run lint

> emendation@1.0.0 lint
> textlint ./files/*.txt


/Users/t0k0sh1/Workspace/emendation/files/sample.txt
  1:1   ✓ error  既に => すでに                                                                                                  prh
  1:23  ✓ error  且つ => かつ                                                                                                      prh
  1:48  ✓ error  又は => または                                                                                                  prh
  1:75  ✓ error  一つ => 1つ
数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。  ja-technical-writing/arabic-kanji-numbers

✖ 4 problems (4 errors, 0 warnings)
✓ 4 fixable problems.
Try to run: $ textlint --fix [file]

検出したエラーのうち、チェックマークがついているものが自動訂正可能なものです。できないものもありますが、今回検出したエラーはすべて自動訂正可能です。

では、lint:fixコマンドを実行して自動訂正します。

$ npm run lint:fix

> emendation@1.0.0 lint:fix
> textlint --fix ./files/*.txt


/Users/t0k0sh1/Workspace/emendation/files/sample.txt
  1:75  ✔   一つ => 1つ
数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。  ja-technical-writing/arabic-kanji-numbers
  1:1   ✔   既に => すでに                                                                                                  prh
  1:23  ✔   且つ => かつ                                                                                                      prh
  1:48  ✔   又は => または                                                                                                  prh

✔ Fixed 4 problems

メッセージからも訂正されたことが確認できますが、修正後のテキストも確認しておきます。

すでに会議は始まっており、私たちは遅れている。かつ、プレゼンテーション資料もまだ完成していない。または、次の会議までに資料を仕上げ、改めて説明することも1つの選択肢だ。

検知された点が修正されていることが確認できました。

ルールを書くときの注意点(正規表現)

「かつ」が正しい書き方だとした場合、誤った書き方は「且つ」または「且」となります。このような場合、正規表現で長い方を先に書くようにすることで、「且つ」を「かつつ」に訂正しないようにできます。

version: 1
rules:
  - expected: かつ
    patterns:
      - /且つ|且/

また、「又」が誤った書き方で「また」に訂正したい場合、「又」が別の単語で使われていてそちらを訂正しないようにするためには、正規表現で接続詞としての「又」のみを検知しつつ、適切に訂正できるようになります。この例では、正規表現(、|は|は、)部分は$1で充当されるため、「又は」は「または」に訂正されるようになります。

version: 1
rules:
  - expected: また$1
    patterns:
      - /又(、|は|は、)/

正規表現の設定ミスなどにより思わぬ訂正が行われる可能性もあります。必ずチェックで正しく検出できているかを確認のうえ、訂正するようにしてください。

まとめ

textlintは、文章の自動校正ツールとして非常に優れています。自己チェックと併用してtextlintを使うことで、より良い文章を効率的に作成することができるようになるでしょう。ぜひ、textlintを使ってみてください。

Angular CLIのインストールとプロジェクトの作成

AngularはGoogleによって開発され、維持されているオープンソースのJavaScriptフレームワークであり、主にSingle Page Application(SPA)の開発に使用されます。AngularはTypeScriptで書かれており、高度なツールやエディタのサポートを享受できます。

Angularの特徴

以下がAngularの主な特徴です。

  1. コンポーネントベースのアーキテクチャ: Angularはコンポーネントベースのアーキテクチャを採用しており、アプリケーションは再利用可能なコンポーネントに分割されます。これにより、コードの管理が容易になり、再利用性と可読性が向上します。
  2. 依存性注入: Angularは依存性注入パターンを採用しており、依存オブジェクトをコンポーネントに提供します。これにより、コードの再利用性とテストのしやすさが向上します。
  3. データバインディング: Angularは双方向データバインディングをサポートしており、モデルとビュー間の同期を自動的に保つことができます。
  4. ルーティング: Angularのルーティング機能により、アプリケーション内でのページ間の移動が容易になります。
  5. Angular CLI: Angular Command Line Interface(CLI)を使用すると、プロジェクトの作成、開発、テスト、ビルドが容易になります。
  6. テスト容易性: Angularは単体テストからエンドツーエンド(E2E)テストまで、テストを容易にするツールとライブラリを提供します。

他の主要なJavaScriptフレームワーク、特にReactやVue.jsと比較した場合、Angularはフルスタックなフレームワークで、多くの機能を提供します。一方で、ReactやVue.jsはライブラリとしてスタートし、他のライブラリやツールと組み合わせて使用することでフレームワークのような機能を達成します。そのため、ReactやVue.jsはより柔軟性がありますが、セットアップや学習曲線が少し複雑になる可能性があります。

また、AngularはTypeScriptを使用しますが、ReactやVue.jsはJavaScriptを使用します(ただし、TypeScriptのサポートもあります)。TypeScriptは静的型付けを提供し、大規模なプロジェクトでは開発効率やコードの品質を向上させますが、一方で学習コストがかかることも事実です。

Angularは日本国内においてはReactやVue.jsと比べるとメジャーではありませんが、まったく使われていないというわけではありません。主に企業向けシステムを中心に利用されています。

Angular CLIのセットアップとプロジェクトの作成

Angularのプロジェクト作成およびコードのひな形の生成にはAngular CLIを使用します。

本記事では、執筆時点で最新版の16.1.6を使用します。基本的にAngularで使用するNode.jsは同時期の安定版をサポートしているため、ここではNode.jsは18.17.0、npmは9.8.1を使用します。また、全体を通してパッケージマネージャーはnpmを使用します。

$ node -v
v18.17.0
$ npm -v
9.8.1

以下のコマンドを入力してAngular CLIをインストールします。

$ npm install -g @angular/cli

added 240 packages in 13s

36 packages are looking for funding
  run `npm fund` for details

Angular CLIのインストール成功すると、ngコマンドが使用可能になります。versionサブコマンドでインストールしたAngular CLIのバージョンを確認してみましょう。

$ ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 16.1.6
Node: 18.17.0
Package Manager: npm 9.8.1
OS: darwin arm64

Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1601.6 (cli-only)
@angular-devkit/core         16.1.6 (cli-only)
@angular-devkit/schematics   16.1.6 (cli-only)
@schematics/angular          16.1.6 (cli-only)

Angular CLI、Node.js、パッケージマネージャー(npm)およびインストールしたパッケージのバージョンを確認することができます。

開発者全員で同じバージョンのAngular CLIを使用する場合は、latestの部分を指定のバージョンに変更します。

$ npm install -g @angular/cli@16.1.6

added 240 packages in 15s

36 packages are looking for funding
  run `npm fund` for details

システム開発においてはバージョンを明示的に指定するこちらの方法でインストールしてください。

Angularプロジェクトの作成

Angular CLIのインストールが完了したら、Angularプロジェクトを作成します。

プロジェクト名は任意の名前で構いませんが、本記事ではangular-tutorialというプロジェクト名にします。

Angular CLIでAngularプロジェクトを作成するには、newサブコマンドを使用します。

$ ng new angular-tutorial

使用するAngular CLIのバージョンによって変わる場合がありますが、コマンド実行後にいくつか質問が表示されます。ここではすべてデフォルト値のまま進めることにします。

$ ng new angular-tutorial
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS
CREATE angular-tutorial/README.md (1069 bytes)
CREATE angular-tutorial/.editorconfig (274 bytes)
CREATE angular-tutorial/.gitignore (548 bytes)
CREATE angular-tutorial/angular.json (2750 bytes)
CREATE angular-tutorial/package.json (1047 bytes)
CREATE angular-tutorial/tsconfig.json (901 bytes)
CREATE angular-tutorial/tsconfig.app.json (263 bytes)
CREATE angular-tutorial/tsconfig.spec.json (273 bytes)
CREATE angular-tutorial/.vscode/extensions.json (130 bytes)
CREATE angular-tutorial/.vscode/launch.json (470 bytes)
CREATE angular-tutorial/.vscode/tasks.json (938 bytes)
CREATE angular-tutorial/src/main.ts (214 bytes)
CREATE angular-tutorial/src/favicon.ico (948 bytes)
CREATE angular-tutorial/src/index.html (301 bytes)
CREATE angular-tutorial/src/styles.css (80 bytes)
CREATE angular-tutorial/src/app/app.module.ts (314 bytes)
CREATE angular-tutorial/src/app/app.component.css (0 bytes)
CREATE angular-tutorial/src/app/app.component.html (23083 bytes)
CREATE angular-tutorial/src/app/app.component.spec.ts (922 bytes)
CREATE angular-tutorial/src/app/app.component.ts (220 bytes)
CREATE angular-tutorial/src/assets/.gitkeep (0 bytes)
✔ Packages installed successfully.
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: 	git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: 	git branch -m <name>
    Successfully initialized git.

質問は2つありますので、1つずつ見ていきましょう。

Would you like to add Angular routing?

ルーティングモジュールを追加するかについて訪ねられています。ルーティングモジュールを使用しないことはほとんどないので、yを回答しても構いませんが、後で追加するのでここではデフォルト値のままにしておきます。

Which stylesheet format would you like to use?

スタイルシートのフォーマットを選択することができます。デフォルトはCSSですが、SCSSやSASS、LESSなどを選択できます。UIをどのように開発するか決まっていればそれに合わせて選択していただくのがよいと思います。本記事執筆時点ではいくつかのCSSフレームワークを試そうと思っていますので、デフォルトのCSSのままにしておきます。

hint: Using ‘master’ as the name for the initial branch. This default branch name

プロジェクトの作成が成功したあと、いくつかhint:で始まるメッセージが表示されています。

私の環境では最初に作成されるGitのブランチがmasterになっているため、このメッセージが表示されています。変更しなくても動作には支障はありませんが、不適切なブランチ名であるというのが業界における共通認識になっていると思いますので、GitHubの方針に合わせてmainブランチに変更しておきましょう。

また、git config --global init.defaultBranch <name>でデフォルトのブランチ名を変更しておくことも可能です。毎回変更するのが面倒な場合はこちらでデフォルトブランチを変更してください。ただし、次回以降の作成で有効になる点にはご注意ください。(すでに作成済みのGitリポジトリは変更されません)

これ以降ではVisual Studio Codeを使って開発を進めていきますので、作成したプロジェクトをcodeコマンドで表示し、ターミナルを開きます。

$ code angular-tutorial

Visual Studio CodeでAngularプロジェクトを開くと、拡張機能をインストールを勧めるメッセージが表示されますが、あとでインストールするので、ここでは閉じておいてください。

$ git branch
* master

ブランチを確認すると、masterブランチになっています。これをgit branch -mコマンドでmainに変更します。

$ git branch -m main
$ git branch
* main

ブランチ名がmainに変わったことを確認できました。

まとめ

Angular CLIのインストールとAngularプロジェクトの作成までを行いました。

次回はVisual Studio CodeでのAngularの開発を円滑に進めるための拡張機能をインストールしていきます。

Yarnをインストールする(v3系)

過去にYarnを使っていましたが、最近は全然使用していませんでした。ふと使おうかと思ったのですが、インストール方法がだいぶ変わっており、初めてインストールを行う人やしばらくぶりにインストールをしようとすると手順に戸惑いそうだったので、基本的なインストール手順をまとめました。

前提条件

まずは記事執筆時点でのLTSバージョンである18.16.0を使用してインストールを行います。

$ node -v
v18.16.0
$ npm -v
9.6.6

npmについても執筆時点の最新バージョンにアップデートしています。

手順はmacOS上で確認していますが、特にシェルコマンドなどは使っていないので、どの環境でも同様の手順でインストール可能です。

また、インストール手順は公式の手順に準じて進めます。

公式の手順で十分な方はそちらを参照してください。

corepackを有効化する

corepacknpmyarnなどのパッケージマネージャを管理するツールです。デフォルトでは有効になっていないため有効します。

$ corepack enable

以前はnpmコマンドでインストールしていましたが、今はcorepackでインストールします。npm install yarnでもインストールできるのですが、v1系がインストールされるため、最新バージョンをインストールしたい場合はcorepackコマンドを使用する必要があります。

yarnをインストールする

次にcorepack を使ってyarnをインストールします。執筆時点では3.5.1が最新版のようですので、3.5.1をインストールすることにします。

yarnリポジトリはv1系のリポジトリとなっているのでご注意ください。

corepack prepareコマンドでインストールと有効化を行います。

$ corepack prepare yarn@3.5.1 --activate
Preparing yarn@3.5.1 for immediate activation...

Node.jsをasdfでインストールしている場合は、追加で以下のコマンドを実行してyarnコマンドを使用できるようにします。

$ asdf reshim

指定したバージョンがインストールできていることを確認します。

$ yarn -v
3.5.1

これでインストールが完了しました。

package.jsonを作成する

ついでにyarnコマンドを使ってpackage.jsonを作成してみましょう。

$ yarn init -y
{
  name: 'test',
  packageManager: 'yarn@3.5.1'
}

corepackの管理下にあるパッケージマネージャを使ってpackage.jsonを作成すると、packageManagerというプロパティが追加されるようになります。これがあるとyarn以外のパッケージマネージャを使用するとエラーが出るようになります。

TypeScriptでJestを使ったテスト環境を構築する

TypeScriptでJestを使ったテスト環境を構築します。

パッケージのインストール

必要なパッケージをインストールします。

$ npm install -D jest ts-jest @types/jest ts-node

ts-nodeはTypeScriptの環境構築の過程ですでインストールしている場合があります。インストールしていない場合はts-nodeもインストールしてください。

設定ファイルを作成する

設定ファイルを作成します。本手順でインストールしたバージョンは29.3.1ですが、バージョンによって挙動や質問の内容が変更になっている場合があるのでご注意ください。

$ npx jest --init

The following questions will help Jest to create a suitable configuration for your project

✔ Would you like to use Jest when running "test" script in "package.json"? … yes
✔ Would you like to use Typescript for the configuration file? … yes
✔ Choose the test environment that will be used for testing › node
✔ Do you want Jest to add coverage reports? … yes
✔ Which provider should be used to instrument code for coverage? › v8
✔ Automatically clear mock calls, instances, contexts and results before every test? … yes

✏️  Modified /Users/t0k0sh1/Workspace/honeycomb/packages/cli/package.json

📝  Configuration file created at /Users/t0k0sh1/Workspace/honeycomb/packages/cli/jest.config.ts

ここでは、TypeScriptで設定ファイルを書く設定(2つ目の質問)にしています。ただ、実際に設定ファイルを出力してみると、JavaScriptで書かれた設定ファイルjest.config.jsも出力されました。これが正しい挙動かは不明ですが、複数の設定ファイルがあるとjestコマンドが実行できないため、以下のいずれかの対応を行なってください。

  • TypeScriptで設定ファイルを定義したい場合はjest.config.jsjest.config.js.mapを削除する
  • JavaScriptで設定ファイルを定義したい場合は2つ目の質問でnoを選択する

設定ファイルの出力後、jest.config.tsに1箇所修正を加えます。

export default {
  // A map from regular expressions to paths to transformers
- // transform: undefined,
+ transform: {
+   "^.+\\.(ts|tsx)$": "ts-jest",
+ },
}

この設定はテストコードを書いた時にimport/exportが使用できるようにするための設定です。

テストコードを書く

実際にテストコードを書いてみましょう。

まずはテスト対象のコードです。

export function greet(name: string): string {
  return `Hello ${name}`;
}

次にテストコードです。前述で設定を行なっているため、テストコード内でimportが使用可能です。

import { greet } from "./greeting";

test("Greeting is", () => {
  expect(greet("John")).toBe("Hello John");
});

テストを実行すると以下のようになります。

$ npm run test

> example@.1.0 test
> jest

 PASS  src/greeting.spec.ts
 PASS  dist/greeting.spec.js
-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |     100 |      100 |     100 |     100 |                   
 greeting.ts |     100 |      100 |     100 |     100 |                   
-------------|---------|----------|---------|---------|-------------------

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.866 s, estimated 1 s
Ran all test suites.

Node.jsでTypeScriptの環境を構築する

Node.jsでTypeScriptの環境を構築します。

構築する環境について

本記事では、以下のバージョンで構築しています。

$ node -v
v18.12.1
$ npm -v
9.1.2

以降の手順で、 Node.jsのバージョンが必要となりますので、必ず確認してください。

TypeScriptをインストールする

TypeScriptをインストールしていきます。

$ npm install -D typescript @types/node@18

使用しているバージョンがv18.12.1ですので、@typesパッケージも同じバージョンのものを指定します。

インストールできたらインストールされているバージョンを確認します。

$ npx tsc --version
Version 4.9.4

上記のようにtscコマンドを使ってバージョンが表示できればインストールは完了しています。

tsconfig.jsonを作成する

次にTypeScriptの設定ファイルのtsconfig.jsonを作成します。まずは、以下のコマンドを実行してファイルを作成します。

$ npx tsc --init

このままでも動作しますが、一部設定を変更しておきます。

{
  "compilerOptions": {
-   // "outDir": "./",               /* Specify an output folder for all emitted files. */
+   "outDir": "./dist",              /* Specify an output folder for all emitted files. */
- }
+ },
+ "include": [
+   "src/**/*"
+ ]
}

ここでは、TypeScriptファイルの格納先(include)とコンパイルして作成されるJavaScriptファイルの出力先(outDir)を追加・変更しています。

環境の構築時期やTypeScriptのバージョン、プロジェクトの都合によっては他の設定も変更することがありますが、ここでは省略します。

動作確認

実際に動作確認をしてみましょう。まずはsrc/index.tsを作成し、ファイルの中身は以下のようにします。

function greet(name: string): string {
  return `Hello, ${name}!`;
}

console.log(greet("John"));

以下のコマンドを実行し、src/index.tsをコンパイルします。

$ npx tsc

ファイルはdist/index.jsにされ、設定の違いで多少異なるかもしれませんが、以下のように出力されます。

"use strict";
function greet(name) {
    return `Hello, ${name}!`;
}
console.log(greet("John"));

実行にはJavaScriptファイルを使用します。

$ node dist/index.js
Hello, John!

エラーなくメッセージが表示されれば正しくコンパイルされています。

package.jsonにスクリプトを追加する

package.jsonにスクリプトを追加してnpmコマンドでビルドできるようにします。

{
  "scripts": {
-   "test": "echo \"Error: no test specified\" && exit 1"
+   "build": "tsc",
+   "watch": "tsc --watch"
  },
}

ここでは2つのスクリプトを追加しています。ひとつはビルドを行うスクリプト(build)で、もう一つは変更を監視して変更があればビルドを行うスクリプトです(watch)。

追加したコマンドは以下のように実行します。

$ npm run build
$ npm run watch

[Node.js][npm]ローカルパッケージを更新する

ローカルパッケージを更新する手順について説明します。

本記事では、複数のパッケージを一気にバージョンアップする方法については解説しません。ライブラリやフレームワークによっては公式でバージョンアップデート方法やマイグレーション方法を説明している場合があります。そのような場合は本手順ではなく、公式の手順に従うようにしてください。

また、パッケージのバージョンアップは十分注意して行うようにしてください。バグフィックスであっても意図しない動作をする可能性がありますので、十分テストした上でバージョンアップすることが大切です。

手順

sassパッケージをアップデートする例で手順を説明します。

{
  ...
  "devDependencies": {
    "sass": "^1.56.1"
  }
}

執筆時点では、sassパッケージの最新バージョンは1.56.2ですので、1.56.1から1.56.2へのバージョンアップを試みます。

アップデートの有無を確認する

エディタの機能等で最新バージョンを確認できる方は必要ありませんが、コマンドで最新バージョンが存在するかを確認することができます。

$ npm outdated
Package  Current  Wanted  Latest  Location           Depended by
sass      1.56.1  1.56.2  1.56.2  node_modules/sass  npm-update-sample

前述のとおり、現在バージョン(Current)は1.56.1で最新バージョン(Latest)は1.56.2であることがわかります。

各項目の意味は以下のとおりです。

  • Package:最新バージョンがあるパッケージ(現在のバージョンが最新バージョンの場合は表示されない)
  • Current:現在インストールされているバージョン
  • Wanted:package.jsonに記載されたセマンティックバージョンの条件を満たす最新バージョン
  • Latest:最新バージョン
  • Location:インストール先
  • Depended by:このパッケージに依存しているパッケージ

パッケージをアップデートする

アップデートを確認できましたので、実際にアップデートを行っていきます。

ここでは、すべてのパッケージをアップデートするのではなく、バージョンアップしたいsassパッケージだけをアップデートし、1.56.2へ狙い撃ちでバージョンアップする方法を説明します。

パッケージのアップデートはnpm updateコマンドで行いますが、このコマンドでは対象パッケージを指定することまではできますが、特定のバージョンを指定してアップデートすることはできません。最新バージョンではなく、特定のバージョンを指定してアップデートしたい場合はnpm installコマンドを用います。

$ npm install sass@1.56.2

changed 1 package, and audited 39 packages in 669ms

4 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

sassパッケージはdevDependenciesにありますが、バージョンアップするときはオプションなしでアップデートできます。

{
  ...
  "devDependencies": {
    "sass": "^1.56.2"
  }
}

package.jsonを確認するとバージョンアップしていることが確認できます。

GruntでSASS/SCSSをビルドする

GruntでSASS/SCSSをビルドする方法について解説します。

パッケージのインストール

まずはNodeプロジェクトを作成します。

$ npm init -y

必要なパッケージをインストールしていきます。

$ npm install -D grunt grunt-sass node-sass grunt-postcss autoprefixer@^9 grunt-contrib-watch load-grunt-tasks

インストールするパッケージは以下のとおりです。実際に使用したバージョンも併記しておきます。

  • grunt 1.5.3
  • grunt-sass 3.1.0
  • node-sass 7.0.1
  • grunt-postcss 0.9.0
  • autoprefixer 9.8.8
  • grunt-contrib-watch 1.1.0
  • load-grunt-tasks 5.1.0

また、Node.jsのバージョンは16.14.2、npmのバージョンは8.10.0を使用しています。

執筆時点(2022/05/17)では、autoprefixerはバージョン指定なしでインストールするとv10系がインストールされます。
grunt-postcss v0.9系と組み合わせると、
Warning: [object Object] is not a PostCSS plugin Use --force to continue.
という警告が発生して実行に失敗(Aborted)します。そのため、バージョン指定なしで上記エラーが発生する場合は、npm install -D autoprefixer@^9のようにv9系を指定してインストールしてください。

grunt-sass

GruntでSASS/SCSSをビルドするパッケージにはgrunt-sassgrunt-contrib-sassがありますが、grunt-contrib-sassの方はRubyのsassを使用しています。
実際にインストールするとわかりますが、インストール時に以下のメッセージが出力され、Rubyのsassは非推奨に なっていることがわかります。

Ruby Sass has reached end-of-life and should no longer be used.

このため、grunt-contrib-sassではなく、node-sassが使用できるgrunt-sassを使用しています。

grunt-postcss、autoprefixer

ベンダープリフィックスを自動で付与するために使用します。

grunt-contrib-watch

SASS/SCSSを開発環境でビルドするときは都度コマンドを打ってビルドするのではなく、自動でビルドする方が楽だと思いますので、変更監視用のgrunt-contrib-watchを使用します。

load-grunt-tasks

インストールしたgrunt-*パッケージを使用するためには、Gruntfile.js内

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-sass');

のようにロードする必要があります。少ないうちは特に問題になりませんが、ロードするパッケージが多くなると管理が煩雑になるため、以下のように書くだけでロードできるload-grunt-tasksを使用しています。

  require("load-grunt-tasks")(grunt);

SASS/SCSSをビルドする

ではGruntfile.jsを作成していきます。

本例では、以下のような構造のプロジェクトになっており、sass/main.scssをビルドしてdist/css/main.cssとして出力するGruntfile.jsを作成しています。

.
├── dist/
│   └── css/
│       └── main.css
├── sass/
│   └── main.scss
├── Gruntfile.js
├── node_modules/
├── package-lock.json
└── package.json

動作確認のために用意したsass/main.scssは以下のようになっています。

.button {
  border: 1px;
  background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%);
  &:hover {
    border: 2px;
  }
}

これをビルドするGruntfile.jsは以下のとおりです。

const sass = require("node-sass");

module.exports = function (grunt) {
  grunt.initConfig({
    // Sassタスク
    sass: {
      options: {
        implementation: sass,
        style: "expanded",
      },
      dist: {
        files: {
          "dist/css/main.css": "sass/main.scss",
        },
      },
    },
  });

  require("load-grunt-tasks")(grunt);

  grunt.registerTask("build", ["sass"]);
};

sassタスク

sassタスクでは実装(implementation)にnode-sassを指定しています。その他のオプションは自由ですが、ビルドされたCSSファイルを確認したかったので、style: "expanded"を指定しています。

タスクの定義(build)

本例では、buildタスクを定義しています。

package.jsonbuildタスクを実行するスクリプトを作成し、

{
  ・・・
  "scripts": {
    "build": "grunt build",
    ・・・
  },
}

実行してみましょう。

$ npm run build

> example@1.0.0 build
> grunt build

Running "sass:dist" (sass) task

Done.

エラーなく実行され、dist/css/main.cssに以下の内容が出力されました。

.button {
  border: 1px;
  background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%); }
  .button:hover {
    border: 2px; }

Autoprefixerを使用する

次にベンダープリフィックスが自動付与されるようにGruntfile.jsを修正します。

const sass = require("node-sass");
const autoprefixer = require("autoprefixer"); // 追加

module.exports = function (grunt) {
  grunt.initConfig({
    // Sass
    sass: {
      options: {
        implementation: sass,
        style: "expanded",
      },
      dist: {
        files: {
          "dist/css/main.css": "sass/main.scss",
        },
      },
    },
    // <- ここから
    // PostCSS
    postcss: {
      options: {
        processors: [autoprefixer()],
      },
      dist: {
        src: "dist/css/main.css",
      },
    },
    // ここまでを追加 ->
  });

  require("load-grunt-tasks")(grunt);

  grunt.registerTask("build", ["sass", "postcss"]); // <- "postcss"を追加
};

sassタスクで出力されたdist/css/main.cssに対してベンダープリフィックスを付与するようにしています。SASS/SCSSファイルではなくCSSファイルに対して実行する点に注意してください。

次にAutoprefixerがCSSにどのベンダープリフィックスをつけるかなど決めるために使用する.browserslistrcを作成します。

last 1 versions
ie >= 11

設定値自体はベンダープリフィックスがつくのを確認するために設定しているものですので、推奨設定とかそういうものではありません。

こちらも同様に実行してみます。

$ npm run build

> example@1.0.0 build
> grunt build

Running "sass:dist" (sass) task

Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.

Done.

sassタスクの後にpostcssタスクが実行されていることがわかります。

出力されたdist/css/main.cssを見てみると、linear-gradientにベンダープリフィックスがついた行が出力されていることがわかります。

.button {
  border: 1px;
  background-image: -webkit-linear-gradient(top, #8bcc8e 0%, #a7f5ab 100%);
  background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%); }
  .button:hover {
    border: 2px; }

Autoprefixerを書き方について注意事項

Autoprefixerの使用方法を調べると以下のような書き方をしているサイトもあります。

    postcss: {
      options: {
        processors: [
          autoprefixer({
            browsers: ["last 1 versions", "ie >= 11"],
          }),
        ],
      },
      dist: {
        src: "dist/css/prime.css",
      },
    },

本記事の執筆時点(2022/05/17)では、この書き方をして実行してみると以下のようなメッセージが出力されます。

$ npm run build

> primecss@1.0.0 build
> grunt build


  Replace Autoprefixer browsers option to Browserslist config.
  Use browserslist key in package.json or .browserslistrc file.

  Using browsers option can cause errors. Browserslist config 
  can be used for Babel, Autoprefixer, postcss-normalize and other tools.

  If you really need to use option, rename it to overrideBrowserslist.

  Learn more at:
  https://github.com/browserslist/browserslist#readme
  


Running "sass:dist" (sass) task

Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.

Done.

この例では正しく動作しているものの、説明では、

  • browsersオプションではなくpackage.jsonまたは.browserslistrcを使用すること
  • browsersオプションを使うとエラーが発生することがある
  • どうしても使いたい場合はoverrideBrowserslistオプションを使用すること

となっています。毎回赤い文字でメッセージが表示されるのも困りますので、本記事では.browserslistrcを使用しています。

SASS/SCSSファイルを監視する

最後にファイルの変更を監視するように変更し、都度ビルドコマンドを実行しなくても済むようにしましょう。

const sass = require("node-sass");
const autoprefixer = require("autoprefixer");

module.exports = function (grunt) {
  grunt.initConfig({
    // <- ここから
    // Watch
    watch: {
      target: {
        files: ["sass/**/*"],
        tasks: ["sass", "postcss"],
      },
    },
    // ここまでを追加 ->
    // Sass
    sass: {
      options: {
        implementation: sass,
        style: "expanded",
      },
      dist: {
        files: {
          "dist/css/main.css": "sass/main.scss",
        },
      },
    },
    // PostCSS
    postcss: {
      options: {
        processors: [autoprefixer()],
      },
      dist: {
        src: "dist/css/main.css",
      },
    },
  });

  require("load-grunt-tasks")(grunt);

  grunt.registerTask("build", ["sass", "postcss"]);
  grunt.registerTask("build:watch", ["sass", "postcss", "watch"]); // <- build:watchタスクを追加
};

タスクの実行時に一度SASS/SCSSをビルドし、以降は変更されるたびにSASS/SCSSをビルドしたいので、["sass", "postcss", "watch"]のように指定しています。
最初の"sass", "postcss"がないと、何かしら変更を加えないと初回のビルドが行われないのでご注意ください。

本記事では、監視を行うタスクはwatchタスクとし、実行するために定義するタスクをbuild:watchタスクとしています。仮に、
grunt.registerTask("watch", ["sass", "postcss", "watch"]);
のようにしてしまうと、["sass", "postcss", "watch"]"watch"が自分自身を呼び出してしますため、無限ループに陥ってしまいます。
initConfigで定義しているタスクもregisterTaskで定義しているタスクも同じタスクですので、タスク名の重複にはご注意ください。

package.jsonwatchスクリプトを追加し、作成したbuild:watchタスクを呼び出すように修正します。

 {
  ・・・
  "scripts": {
    "build": "grunt build",
    "watch": "grunt build:watch",
    ・・・
  },
}

では、実行してみます。

$ npm run watch

> primecss@1.0.0 watch
> grunt build:watch

Running "sass:dist" (sass) task

Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.

Running "watch" task
Waiting...

実行後、sassタスク、postcssタスクの順に実行し、最後にwatchタスクを実行して監視状態になったことがわかります。

では、監視しているsass/main.scssを更新してみましょう。使用しているエディタによって異なりますが、ファイル自体変更しなくても保存するだけでタイムスタンプが変わるので、変更を検知してくれます。

>> File "sass/main.scss" changed.

Running "sass:dist" (sass) task

Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.

Running "watch" task
Completed in 0.017s at Sat May 21 2022 23:27:13 GMT+0900 (日本標準時) - Waiting...

監視対象の指定について

sass/main.scssをビルド対象としているため、sass/**/*を監視対象としています。sass/*ではなくsass/**/*を監視対象としているのは、今後サブディレクトリを作成した場合でも、きちんと変更が検知されるようにするためです。

Node.jsで開発環境をセットアップする(ESLint、Prettier、husky)

Node.jsの開発環境で、以下の機能をセットアップする方法について解説します。

  • ESLintによるlint
  • Prettierによるコードフォーマット
  • huskyによるpre-commit git hooks

開発環境を作成する

最初に構築対象となる開発環境を用意します。

$ npm init -y
Wrote to /Users/t0k0sh1/workspace/node_lint/package.json:

{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

今回の説明とは関係ないため、デフォルトのままで進めます。

パッケージをインストールする

次に必要なパッケージをインストールします。

  • eslint – lintツール
  • prettier – formatterツール
  • eslint-config-prettier – eslintのフォーマットがprettierと競合する場合はeslint側をOFFにする
  • husky – pre-commit git hooksツール
$ npm i -D eslint eslint-config-prettier prettier husky

added 85 packages, and audited 86 packages in 4s

15 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

eslint-plugin-prettierは非推奨になっているため、eslint-config-prettierを使用しています。

インストール後のpackage.jsonは以下のようになっています。

// package.json
{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.13.0",
    "eslint-config-prettier": "^8.5.0",
    "husky": "^7.0.4",
    "prettier": "^2.6.2"
  }
}

lintの設定を行う

まずはESLintの設定を行います。ここでは必要最低限の設定にしています。prettiereslint:recommendの後に書いてください。

// .eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "prettier"
  ]
}

次にeslintでのlint(修正あり)とprettierでのフォーマットを行うスクリプトを追加します。

// package.json
{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint --cache --fix . && prettier --write ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.13.0",
    "eslint-config-prettier": "^8.5.0",
    "husky": "^7.0.4",
    "prettier": "^2.6.2"
  }
}

コードを作成して動作確認を行う

実際のコードを作成して動作確認をしておきましょう。

// index.js
function hello(name) {
  return 'Hello, ' + name;
}

console.log(hello("John"));

簡単なプログラムを書きました。動作確認ができるようにlintでエラーになるコードになっています。

では動作確認します。

$ node index.js
Hello, John

エラーにならず動作していることを確認できました。

では、このコードに対してlintprettierを実行します。

$ npm run lint

> node_lint@1.0.0 lint
> eslint --cache --fix . && prettier --write .


/Users/t0k0sh1/workspace/node_lint/index.js
  6:1  error  'console' is not defined  no-undef

✖ 1 problem (1 error, 0 warnings)

consoleが未定義であるとエラーになりました。これは後で修正(除去)しますが、今はこのままにしておきます。

ここまでに作成したコードをコミットしておきます。

git initコマンドでgitリポジトリを初期化します。

$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint:   git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint:   git branch -m <name>
Initialized empty Git repository in /Users/t0k0sh1/workspace/node_lint/.git/

コミットするにあたり、node_modules.eslintcacheは対象から外したいので、.gitignoreを作成しておきます。

// .gitignore
node_modules/
.eslintcache

作成したファイルをステージングエリアに追加します。

$ git add .

ローカルリポジトリにコミットしておきます。

$ git commit -m 'first commit'
[master (root-commit) ec47452] first commit
 5 files changed, 1682 insertions(+)
 create mode 100644 .eslintrc.json
 create mode 100644 .gitignore
 create mode 100644 index.js
 create mode 100644 package-lock.json
 create mode 100644 package.json

pre-commit git hooksを設定する

huskyを使ってpre-commit git hooksを設定していきます。手順は公式の手順(https://github.com/typicode/husky)に従いますが、pre-commitに追加するコマンドがnpm run lintになっている点にだけ注意してください(公式の手順ではnpm test

$ npm set-script prepare "husky install"
$ npm run prepare

> node_lint@1.0.0 prepare
> husky install

husky - Git hooks installed
$ npx husky add .husky/pre-commit "npm run lint"
husky - created .husky/pre-commit
$ git add .husky/pre-commit

手順どおりに進めると、package.jsonがステージングエリアに追加されていないため、これを追加してローカルリポジトリにコミットします。

$ git add package.json
$ git commit -m 'setup husky'

> node_lint@1.0.0 lint
> prettier --write '**/*.js' && eslint .

index.js 25ms

/Users/t0k0sh1/workspace/node_lint/index.js
  6:1  error  'console' is not defined  no-undef

✖ 1 problem (1 error, 0 warnings)

husky - pre-commit hook exited with code 1 (error)

先ほどコマンド実行で確認した時と同じようにconsoleが未定義であるとエラーになりました。

pre-commitが機能していることを確認できましたが、念のためコミットされていないかを確認しておきます。

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   .husky/pre-commit
        modified:   package.json

コミットが行われておらず、pre-commitが正しく動作していることを確認できました。

コードを修正して再度コミットする

コードを修正して再度コミットしましょう。

ここでは単純にconsole.log関数を削除しておきます。

// index.js
function hello(name) {
  return "Hello, " + name;
}

hello("John");

念のため、コマンドで確認しておきます。

$ npm run lint

> node_lint@1.0.0 lint
> eslint --cache --fix . && prettier --write .

.eslintrc.json 20ms
index.js 7ms
package-lock.json 30ms
package.json 6ms

エラーにならないことを確認できましたので、ステージングエリアに追加します。

$ git add index.js

では、再度コミットしましょう。

$ git commit -m 'setup husky'
> node_lint@1.0.0 lint
> prettier --write '**/*.js' && eslint .

index.js 25ms
[master ed5dcae] setup husky
 3 files changed, 7 insertions(+), 2 deletions(-)
 create mode 100755 .husky/pre-commit

今度はエラーが表示されず、コミットが実行されました。

git statusgit logでもコミットされていることを確認します。

git status
On branch master
nothing to commit, working tree clean
$ git log
commit ed5dcae1e5e2487854e78e0d388a2f503324231d (HEAD -> master)
Author: Takashi Yamashina <takashi.yamashina@gmail.com>
Date:   Sat Apr 9 12:51:04 2022 +0900

    setup husky

commit 15186ea9211ed9d5ee4de9aa7dab7e2e04bac9de
Author: Takashi Yamashina <takashi.yamashina@gmail.com>
Date:   Sat Apr 9 12:37:45 2022 +0900

    first commit

問題なくコミットできていることが確認できました。

Prettierで特定のファイル、フォルダを対象から除外する(.prettierignore)

Prettierで特定のファイルやフォルダを対象から除外する方法について解説します。

.prettierignoreを作成する

.prettierignoreを作成し、そこに対象から除外したいファイルやフォルダを書きます。

config.js
test/

上記の例では、config.jsというファイルと、testフォルダを対象から除外しています。

実際に試してみる

実際にどう動くのか確認しましょう。

package.json

package.jsonは次のとおりです。prettierをインストールし、prettierコマンドを実行するスクリプトを追加しています。

{
  "name": "node_prettier",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "format": "prettier --write '**/*.js'"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "prettier": "^2.6.2"
  }
}

Prettierは設定ファイルがなくても実行可能なため、ここでは設定ファイルは作成せずに進めます。

プロジェクトの構造

プロジェクトの構造は以下のようになっており、用意した4つのJSファイルはすべてフォーマットされる書き方になっています。

$ tree
.
├── file1.js
├── file2.js
├── dir3
│   └── file3.js
├── dir4
│   └── file4.js
├── package-lock.json
└── package.json

各ファイルの中身は若干の違いはありますが、以下のような内容になっています。

function file1() {
console.log('file1');
}

関数内のインデントがない点と、文字列の囲み文字がダブルクォーテーションではなくシングルクォーテーションになっている点がフォーマットの対象となる箇所です。

Prettierを実行する

最初に.prettierignoreを用意せずに実行します。

$ npm run format

> node_prettier@1.0.0 format
> prettier --write '**/*.js'

dir3/file3.js 22ms
dir4/file4.js 2ms
file1.js 2ms
file2.js 1ms

プロジェクト直下の2ファイル、2つのフォルダ内のそれぞれのファイルが対象になっていることがわかります。

function file1() {
  console.log("file1");
}

実際にファイルを見てみると、インデントおよび文字列の囲み文字が修正されていることが確認できました。

次に.prettierignoreを作成し、プロジェクト直下の1ファイルと2つのファイルのうちの1つを除外してから再度実行してみましょう。

file2.js
dir4/

先ほどと同様に実行してみると、除外したファイルとフォルダ内のファイルが表示されなくなりました。

$ npm run format

> node_prettier@1.0.0 format
> prettier --write '**/*.js'

dir3/file3.js 23ms
file1.js 2ms

ファイルも確認してみると、

ファイル名が表示されたファイルは、先ほどと同様にフォーマットされていますが、

function file1() {
  console.log("file1");
}

ファイル名が表示されなかった(除外された)ファイルはフォーマットされていません。

function file2() {
console.log('file2');
}

node_modulesの除外は不要

実行してみるとわかりますが、node_modulesの除外は不要です。

そのため、対象としたいフォルダ内に除外したいファイルやフォルダがない場合は.prettierignoreを作成する必要はありません。

ESLintで特定のファイル、フォルダを対象から除外する(.eslintignore)

ESLintで特定のファイルやフォルダを対象から除外する方法について解説します。

.eslintignoreを作成する

.eslintignoreを作成し、そこに対象から除外したいファイルやフォルダを書きます。

config.js
test/

上記の例では、config.jsというファイルと、testフォルダを対象から除外しています。

実際に試してみる

実際にどう動くのか確認しましょう。

package.json

package.jsonは次のとおりです。eslintをインストールし、eslintコマンドを実行するスクリプトを追加しています。

{
  "name": "node_eslint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint ./"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.12.0"
  }
}

.eslintrc.json

.eslintrc.jsonは必要最小限にしています。

{
    "extends": [
      "eslint:recommended"
    ]
}

プロジェクトの構造

プロジェクトの構造は以下のようになっており、用意した4つのJSファイルはすべてLintでエラーが検出されます。

$ tree
.
├── file1.js
├── file2.js
├── dir3
│   └── file3.js
├── dir4
│   └── file4.js
├── .eslintrc.json
├── package-lock.json
└── package.json

ESLintを実行する

最初に.eslintignoreを用意せずに実行してみます。

$ npm run lint                                                                                                                     

> node_eslint@1.0.0 lint
> eslint ./


/Users/t0k0sh1/workspace/node_eslint/dir3/file3.js
  1:10  error  'file3' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/dir4/file4.js
  1:10  error  'file4' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file1.js
  1:10  error  'file1' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file2.js
  1:10  error  'file2' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

✖ 8 problems (8 errors, 0 warnings)

プロジェクト直下の2ファイルもフォルダ内の2ファイルもエラーになっていることがわかります。

次に.eslintignoreを作成し、プロジェクト直下の1ファイルと2つのファイルのうちの1つを除外してから再度実行してみましょう。

file2.js
dir4/

先ほどと同様に実行してみると、除外したファイルとフォルダ内のファイルがエラーに表示されなくなりました。

$ npm run lint

> node_eslint@1.0.0 lint
> eslint ./


/Users/t0k0sh1/workspace/node_eslint/dir3/file3.js
  1:10  error  'file3' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file1.js
  1:10  error  'file1' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

✖ 4 problems (4 errors, 0 warnings)

node_modulesの除外は不要

実行してみるとわかりますが、node_modulesの除外は不要です。

そのため、対象としたいフォルダ内に除外したいファイルやフォルダがない場合は.eslintignoreを作成する必要はありません。

モバイルバージョンを終了