AI can fly !!

AI がやりたい Web エンジニアのアウトプット (AI の知識は無い)

【Angular】データバインディングを整理する

angular-logo

はじめに

Angular のデータバインディングにはいくつかの種類と書き方があり、未だに「この場合はどう書いたらいいんだっけ?」となることがあるので、今回はデータバインディングについて整理してみました。

当記事では Angular のデータバインディングを一通りまとめていますが、詳細な仕組みやすべての記法を網羅はしていません。

どういう時にどのデータバインディングを使うかを確認したら、必要に応じて Angular 公式ドキュメントの該当するバインディングの詳細を読みましょう。

angular.jp

もし Angular 公式ドキュメントを読んで難しいと感じる場合は、先に以下の書籍を一読することをお勧めします。

Angularアプリケーションプログラミング

Angularアプリケーションプログラミング

僕が初めて Angular を学んだのもこの本で、今となっては一部古い内容もありますが (2020/06/18 現在の Angular の最新バージョンは 9 、書籍の Angular のバージョンは 4) 、大半は今でもそのまま使えるものなので、一通り読んでからの方がすんなり Angular 公式ドキュメントの内容を理解することができると思います。

対象読者

  • Angular のデータバインディングを一通り学んだが、すべてを使いこなすレベルには至っていない方
  • Angular のデータバインディングは、とりあえずプロパティをブラケットで囲めば何とかなると思っている方

前提条件

  • Angular CLI がインストールされていて、アプリケーションを既に作成済み

動作環境

OS Version
Windows 10 Pro 1909
Environment Version
Node.js 12.18.0
npm 6.14.4
Package Version
@angular/cli 9.1.6

データバインディング

Angular のデータバインディングは、テンプレート (ビュー) とコンポーネント (クラス) 間で相互にデータをやり取りするための仕組みです。

片方向 (片方向バインディング) と双方向 (双方向バインディング) のデータフローが存在し、片方向バインディングにはデータタイプやターゲットによって複数の方法が用意されています。

Binding type Data flow
Interpolation (補間) コンポーネント → テンプレート
プロパティ コンポーネント → テンプレート
属性 コンポーネント → テンプレート
クラス コンポーネント → テンプレート
スタイル コンポーネント → テンプレート
イベント テンプレート → コンポーネント
双方向 コンポーネント ⇔ テンプレート

通常、データバインディングによってバインドできる値のコンテキストはコンポーネントインスタンスで、 windowdocument といったグローバル名前空間内のものは参照できません。

以降は、以下のコードをベースとして、各データバインディングについてまとめていきます。

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule, 
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {}

app.component.html

<h1 class="red">
  Hello Angular !!
</h1>

app.component.scss

.red {
  color: #ff0000;
}

Interpolation (補間) 構文

Data flow
Component → Template

Component

...
export class AppComponent {
  title = 'Angular';
}

Template

<h1 class="red">
  Hello {{ title }} !!
</h1>

コンポーネントクラスの Public プロパティを二重中括弧で囲んでテンプレートに記述すると、プロパティの値を文字列値としてテンプレート内に展開できます。

TypeScript のクラスのメンバのアクセス修飾子は、 public がデフォルトとなっているので省略可能です。

また、コンポーネントクラスのメソッドや一部制限はあるものの一般的な JavaScript 式も記述することができ、その場合は二重中括弧内の評価結果が文字列に変換され、テンプレート内に展開されます。

プロパティに対する Interpolation (補間)

Component

...
export class AppComponent {
  frameworkName = 'Angular';
}

Template

<input type="text" name="framework" value="{{ frameworkName }}">

多くの場合、後述するプロパティバインディングが主に使用されますが、 DOM プロパティに対して Interpolation (補間) 構文で値をバインドすることも可能です。

プロパティバインディング

Data flow
Component → Template

Component

...
export class AppComponent {
  imgSrc = '../assets/images/angular.png'
  isDisabled = true;
}

Template

<img [src]="imgSrc">
<button type="button" [disabled]="idDisabled">OK</button>

ターゲット要素の DOM プロパティをブラケット (角括弧) で囲み、バインドする値を指定します。

バインドする値は Interpolation (補間) 構文と同様に、コンポーネントクラスの Public メンバや式が記述できます。

注意として、バインディングの対象は DOM プロパティであって、 HTML 属性ではありません

たとえ同じ名前であっても、 DOM プロパティと HTML 属性は別物であることを理解しておきましょう。

ja.javascript.info

プロパティバインディングは DOM 要素のプロパティだけでなく、コンポーネントやディレクティブのプロパティに対して行うことも多いです。

属性バインディング

Data flow
Component → Template

Component

...
export class AppComponent {
  colSpan = 2;
}

Template

<table>
  <tr>
    <th [attr.colspan]="colSpan">Angular</th>
  </tr>
  <tr>
    <td>component</td>
    <td>template</td>
  </tr>
</table>

前述の通り、バインディングの対象は基本的にプロパティですが、 DOM プロパティが存在せず、 HTML 属性しか存在しない場合は属性バインディングを使用します。

ターゲット要素の HTML 属性をブラケット (角括弧) で囲み、属性名にドット (.) 付きの接頭辞 attr を付与して、バインドする属性値を指定します。

バインドした値が null の場合、その属性は削除されます。

クラスバインディング

Data flow
Component → Template

Component

...
export class AppComponent {
  bold = true;

  divClass = {
    bold: true,
    blue: false
  };
}

Template

<div class="red" [class.bold]="bold">
  Red and bold
</div>

<div class="red" [class]="divClass">
  Bold only
</div>

Style

.red {
  color: #ff0000;
}

.bold {
  font-weight: bold;
}

.blue {
  color: #0000ff;
}

ターゲット要素のクラス名をブラケット (角括弧) で囲み、ドット (.) 付きの接頭辞 class を付与して、バインドする値を指定します。

バインドされた値は論理型 (boolean 型)として評価され、真 (true) の場合はクラスを追加、偽 (false) の場合はクラスが削除されます。

前述のプロパティバインディングでも class 属性に値をバインドできますが、元々指定されている静的な値が存在した場合はバインドした値で上書きされてしまいます。

クラスバインディングを使用すれば、 class 属性に必ず設定したい静的な値はそのままに、クラスの追加・削除を行うことが可能です。

スタイルバインディング

Data flow
Component → Template

Component

...
export class AppComponent {
  divHeight = '150px';
  divWidth = 300;
  divBackgroundColor = '#ff0000';

  divStyle = {
    width: '200px',
    height: '200px',
    backgroundColor: '#0000ff'
  };
}

Template

<div 
  [style.height]="divHeight" 
  [style.width.px]="divWidth" 
  [style.background-color]="divBackgroundColor"
>
  Red rectangle
</div>

<div [style]="divStyle">
  Blue square
</div>

ターゲット要素のスタイルプロパティをブラケット (角括弧) で囲み、ドット (.) 付きの接頭辞 style を付与して、バインドする値を指定します。

通常はバインドする値は文字列ですが、単位を必要とするスタイルの場合、スタイル名の後ろにドット (.) 付きで単位を追加して数値をバインドすることも可能です。

また、スタイルプロパティは style.background-color のようなケバブケース (kebab-case) 以外に、 style.backgroundColor のようなキャメルケース (camelCase) でも記述できます。

クラスバインディングと同様に style プロパティへ複数のスタイルを一括でバインドすることができますが、適用されるスタイルの優先順位はより詳細なバインディングの方が上位となります。

<div [style]="divStyle" [style.height]="divHeight">
  This div's height is 150px.
</div>

イベントバインディング

Data flow
Template → Component

Template

<button type="button" (click)="showAlert($event)">表示</button>

Component

...
export class AppComponent {
  showAlert(e: MouseEvent): void {
    e.preventDefault();
    e.stopPropagation();

    alert((e.target as HTMLButtonElement).textContent + 'が押されました');
  }
}

ターゲット要素のイベントを丸括弧で囲み、バインドする文を指定します。

イベントが発生するとバインドされた文が実行され、 $event にはイベントに応じたオブジェクトが格納されます。

ターゲットが DOM 要素イベントの場合、 $event は DOM イベントオブジェクトになります。

developer.mozilla.org

また、一般的なイベントリスナーと同様に preventDefault()stopPropagation() を使用して、デフォルト動作やバブリングをキャンセルすることが可能です。

双方向バインディング

Data flow
Template ⇔ Component

双方向バインディングでは、バインドされた値に対し、コンポーネントクラスとテンプレートそれぞれで行った変更を相互に反映させることができます。

前述のプロパティバインディングとイベントバインディングの組み合わせと専用の構文を使用して、相互にデータの変更を共有します。

代表する書き方として、ターゲット要素のプロパティをブラケット (角括弧) と丸括弧で囲む構文 [(property)] がありますが、こう書きさえすれば双方向バインディングが実現できると誤解されがちなので注意してください。

よくある誤った書き方

Component

...
export class AppComponent {
  yourName = 'hrgm';
}

Template

<input type="text" name="your_name" [(value)]="yourName">
<span>Hello {{ yourName }} !!</span>

この場合、テキストボックスの valueyourName の値はバインドされますが、テキストボックスの値を変更しても yourName の値は変更されません。

双方向バインディングは、双方向に値を反映させるためのルールに則って書かれたコンポーネントのプロパティを、ブラケット (角括弧) と丸括弧 [(property)] で囲むことで初めて実現されます。

基本的な書き方

FeatureComponent

Template

<input type="text" [value]="name" (input)="inputName($event.target.value)">

Component

import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'app-child-comp',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent {
  @Input() name: string;
  @Output() nameChange = new EventEmitter<string>();

  inputName(_name: string) {
    this.name = _name;
    this.nameChange.emit(this.name);
  }
}

ターゲットとなるコンポーネントに、プロパティとそのプロパティ名に接尾語 Change を加えたイベントが存在する場合、双方向バインディングの構文が使用できます。

上記のコンポーネントには name プロパティと nameChange イベントが存在しているので、このコンポーネントname プロパティには双方向バインディング [(name)] が可能です。

Module

...
import { ChildComponent } from './child/child.component';

@NgModule({
  declarations: [
    AppComponent,
    ChildComponent
  ],
...

Template

<app-child-comp [(name)]="yourName"></app-child-comp>
{{ yourName }}

補足

つまるところ、双方向バインディングはプロパティバインディングとイベントバインディングシンタックスシュガー (糖衣構文) です。

<app-child-comp [name]="yourName" (nameChange)="yourName=$event"></app-child-comp>

Component

...
export class AppComponent {
  yourName = 'hrgm';
}

このように、双方向バインディングは使用できるプロパティが限定され、ネイティブな HTML 要素の属性やプロパティには使用することができません。

ネイティブな HTML のフォーム関連要素に対して双方向バインディングを行いたい場合は、 NgModel ディレクティブを使用することで双方向バインディングを実現することができます。

NgModel ディレクティブ (FormsModule) を使用する場合

Module

...
import { FormsModule } from '@angular/forms';

@NgModule({
  ...
  imports: [
    ...
    FormsModule
  ],
...

Component

...
export class AppComponent {
  yourName = 'hrgm';
}

Template

<input type="text" name="your_name" [(ngModel)]="yourName">
<span>Hello {{ yourName }} !!</span>

input 要素や select 要素などは NgModel ディレクティブを使用すると、簡単に双方向バインディングを実現することができます。

NgModel ディレクティブを使用するためには、 NgModule の imports リストに FormsModule を追加する必要があるので注意してください。

ngModel を含む Angular の組み込みディレクティブについては、また別記事でまとめる予定です。

おわりに

以上が Angular のデータバインディング全体の概要となります。

簡単にまとめたつもりでしたが、思った以上に長くなってしまいました…

当記事を書くにあたって Angular の公式ドキュメントを読み返しましたが、 Angular を使い始めた頃はあまり理解できていなかった内容や、既に忘れてしまっていることが多々あることに気付かされました。

普段当たり前のように書いているデータバインディングですが、実はもっと色々な書き方や使い方があり、それらを適切に使いこなすことができれば、さらにコーディングの幅を広げることができそうです。

JavaScript の三大フレームワークの一角とされる Angular ですが、素人目に見てもここ数年は React や Vue.js と比べて人気が下火になっている感は否めません。

しかし、フレームワークとしての機能が他よりも劣っていることは無いと信じているので、こういった振り返り学習をしながら、これからも Angular で開発を続けていきたいと思います。

と言いつつ、最近は Angular の前に使っていた Vue.js に戻ろうかと思ったりしてるんですけどねー!ww

【Git】ローカルで作成したリポジトリを GitHub に Push する【GitHub】

git

はじめに

開発で Git を使用する場合、既に GitHub などにあるリモートリポジトリをローカルにクローンするケースがほとんどではないでしょうか。

かくいう僕もその一人で、プロジェクトに参画したときには既にリモートリポジトリが存在し、クローンしてブランチを作成して開発を始める経験しかありませんでした。

しかし、例えば個人開発などでは、とりあえずローカルで開発を始めてみて、良さそうだったら GitHubリポジトリを管理するというケースもあると思います。

もちろん先に GitHubリポジトリを作って、それをクローンしてイチから開発を始める方法もありますが、継続して開発するかどうか分からない段階でリモートリポジトリを作るのはちょっと抵抗があります。

というわけで、今回はローカルで作成した Git リポジトリGitHub で管理し始める (初めて Push するまでの) 手順についてまとめました。

動作環境

OS Version
Windows 10 Pro 1909
Application Version
PowerShell 5.1.18362.752
Git 2.26.0
Hosting Service
GitHub

前提

  • ローカルマシンに Git をインストール済み
  • ローカルマシンに Git リポジトリ (ローカルリポジトリ) を作成済み
  • ローカルの Git リポジトリには master ブランチが存在する
  • GitHub にアカウントを作成済み
  • GitHub への SSH 接続が可能 (SSH 接続の設定済み)

Git のインストールや GitHub への SSH 接続については、別記事を参照ください。

ai-can-fly.hateblo.jp

ai-can-fly.hateblo.jp

ai-can-fly.hateblo.jp

リモートリポジトリ (GitHub)

今回はリモートリポジトリを GitHub に作成します。

Git リポジトリ作成

GitHub に新しいリポジトリを作成します。

リポジトリの作成については、 GitHub ヘルプに詳細な手順が記載されているので、そちらをご覧ください。

help.github.com

リポジトリ名はローカルリポジトリの名前と同じにする必要はありませんが、揃えておいた方が分かりやすいと思います。

作成時の注意

Notes when creating

リポジトリ作成画面に Skip this step if you’re importing an existing repository. とある通り、既に存在する Git リポジトリ をインポート (ローカルからの Push 含む) する場合は、赤枠内の各項目はいずれも作成しません。

  • Initialize this repository with a README
    • ここにチェックを入れると README.md が作成される
  • Add .gitignore
    • None 以外を選択した場合、 .gitignore ファイルが作成される
  • Add a license
    • None 以外を選択した場合、 LICENSE ファイルが作成される

一つでも作成すると、リポジトリ作成と同時に master ブランチが作成されてしまい、ローカルにある master ブランチとのマージが難しくなります。 (マージができないわけではありません)

リモート URL を確認

Check remote url

作成したリポジトリのページに記載されているリモート URL を確認します。

上の画像はデータ転送プロトコルSSH ですが、 HTTPS も使用できます。

ローカルリポジトリ

リモートリポジトリの作成を行ったら、次にローカルの Git リポジトリ内で以下の作業を行います。

リモートリポジトリを追加

ローカルリポジトリGitHub で作成したリモートリポジトリを追加します。

git remote add origin git@github.com:hrgm/about-hrgm.git

リモートリポジトリの追加については、こちらも GitHub ヘルプに詳細が記載されています。

help.github.com

git remote add コマンド

git remote add [remote_name] [remote_url]
Argument Description
[remote_name] リモートリポジトリ名 (一般的には origin がよくつかわれる)
[github_remote_url] リモート URL (GitHub の場合は SSHHTTPS の URL を使用する)

ローカルの Git の Config へ remote_name という名前で リモート URL (remote_url) を追加する。

リモートリポジトリへ Push

追加したリモートリポジトリへ、ローカルリポジトリのブランチを Push します。

git push origin master

Push 後に GitHubリポジトリを見ると、ブランチが登録されているのが確認できます。

GitHub Branch

リモートリポジトリへの Push についても、 GitHub ヘルプに詳しい記載があります。

help.github.com

リモートリポジトリへ Push を行うと、ローカルリポジトリにリモート追跡ブランチ (origin/[remote_branch_name]) が作成されます。

git push コマンド

git push [remote_name] [local_branch_name]:[remote_branch_name]
Argument Description
[remote_name] リモートリポジトリ名
[local_branch_name] ローカルブランチ名
[remote_branch_name] リモートブランチ名 (省略した場合、ローカルブランチ名と同じになる)

リモートリポジトリ (remote_name) のリモートブランチ (remote_branch_name) へ、ローカルブランチ (local_branch_name) を Push する。

上流ブランチの設定

リモートリポジトリへ Push しただけでは、リモート追跡ブランチが作成されても、ローカルリポジトリのブランチに上流ブランチとしては設定されません。

以下のコマンドで上流ブランチを設定する必要があります。

git branch master --set-upstream-to=origin/master

上流ブランチを設定することで、 git push, git merge, git pull を行う際の引数 (リモートリポジトリやブランチ名の指定) を省略できるようになります。

git branch コマンド (--set-upstream-to オプション)

git branch [local_branch_name] --set-upstream-to=[remote_name]/[remote_branch_name]
Argument Description
[local_branch_name] ローカルブランチ名
[remote_name] リモートリポジトリ名
[remote_branch_name] リモートブランチ名

ローカルブランチ (local_branch_name) に、リモート追跡ブランチ (remote_name/remote_branch_name) を上流ブランチとして設定する。

Push と上流ブランチの設定を同時に行う

上記では説明のために Push と上流ブランチの設定を順に分けて行いましたが、 git push コマンドの -u オプションを使用すると、ローカルブランチの Push を行うと同時に、リモート追跡ブランチをローカルブランチの上流ブランチとして設定することができます。

git push -u origin master

GitHub で新規に空のリポジトリを作成すると、リポジトリのページに簡単な説明とこのコマンドが記載されています。

Git に慣れてきたら、ローカルリポジトリ発のブランチをリモートリポジトリに Push する際は、こちらのコマンドを使用することが多くなると思います。

おわりに

今回は GitHub を使用したリモートリポジトリへの Push を説明しましたが、基本的な考え方は GitLab などの他の Git ホスティングサービスであっても変わりません。

Subversion と違って Git は初期の学習ハードルがやや高いところがありますが、この辺りは使っていくうちにどんどん理解が進んでいくはずなので、めげずに使い続ければ、いつか目の前がパァーっと開ける日がやってきます。

まぁ、僕は半年くらいかかりましたけどねー!

【Oracle Database 19c】データベース (CDB と PDB) への接続と各種操作【SQL*Plus】

ORACLE Database 19c

はじめに

自宅で Oracle Database 19c を使用していて、 SQL*Plus でのデータベース接続や起動と停止方法をいつも忘れてググっているので、せっかくなのでまとめて記事にしてみました。

EM Express (Oracle Enterprise Manager Database Express) を使用すれば GUI で各種操作を行うことができますが、今回は CLI (SQL*Plus) での操作に限定してまとめています。

動作環境

OS Version
Windows 10 Pro 1909
Application Version
PowerShell 5.1.18362.752
Database Version
Oracle Database 19c 19.3.0

SQL*Plus の起動

sqlplus /nolog

データベースには接続せず、 SQL*Plus のみを起動します。

SQLPlus の起動と同時にデータベースへ接続することも可能ですが、 CLI のコマンド履歴にユーザとパスワードが残る可能性があるので、セキュリティの観点から言えば、 SQLPlus 起動後に CONNECT コマンドでデータベース接続することをお勧めします。

データベース接続

SQL*Plus 起動後、 CONNECT コマンドでデータベースへ接続します。

ローカル接続

-- ユーザ権限
CONNECT [username]/[password]

-- SYSDBA 権限
CONNECT [username]/[password] AS SYSDBA

ローカル接続では、 OS の環境変数 (ORACLE_SID) に登録されているデータベースに接続されます。

簡易接続ネーミング・メソッド

-- ユーザ権限
CONNECT [username]/[password]@[host]:[port]/[service_name]

-- SYSDBA 権限
CONNECT [username]/[password]@[host]:[port]/[service_name] AS SYSDBA

サービス名 (service_name) には、初期化パラメータ・ファイルの SERVICE_NAMES (= DB_UNIQUE_NAME.DB_DOMAIN) を入力します。

PDB に接続する場合のサービス名 (service_name) は、 pdb_name.DB_DOMAIN になります。

ローカル・ネーミング・メソッド

-- ユーザ権限
CONNECT [username]/[password]@[net_service_name]

-- SYSDBA 権限
CONNECT [username]/[password]@[net_service_name] AS SYSDBA

ローカル・ネーミング・メソッドを使用する場合、ネットワーク・サービス名 (net_service_name) を tnsnames.ora ファイルに追加する必要があります。

データベース起動

CDB

CDB の起動は SYSDBA または SYSOPER 権限を持つユーザで行う必要があります。

STARTUP [OPEN [db_name] | MOUNT [db_name] | NOMOUNT]

STARTUPSTARTUP MOUNT コマンドで [db_name] を省略した場合、初期化パラメータ・ファイルの DB_NAME のデータベース名が使用されます。

  • OPNE
    • Oracle インスタンスを起動し、データベースをマウントして、オープンする
    • オンライン REDO ログ・ファイル、およびデータファイルが開かれ、データへのアクセスが可能になる
  • MOUNT
    • Oracle インスタンスを起動し、データベースをマウントするが、オープンはしない
    • Oracle インスタンスによってデータベースの制御ファイルが開かれるが、データファイルは開かない
  • NOMOUNT

PDB

PDB の起動は SYSDBASYSOPERSYSBACKUPSYSDG 権限のいずれかを持つユーザが、 CDB に接続した状態で行う必要があります。

ALTER PLUGGABLE DATABASE [ALL | [pdb_name]] OPEN [READ WRITE | READ ONLY];

-- または

STARTUP PLUGGABLE DATABASE [pdb_name] OPEN [READ WRITE | READ ONLY]
  • READ WRITE
    • 読取り/書込みモードで PDB をオープンする
  • READ ONRY
    • 読取り専用モードで PDB をオープンする

オープン・モードを省略した場合は、 READ WRITE が指定されます。

STARTUP PLUGGABLE DATABASE コマンドは、単一の PDB をオープンすることができます。

PDB自動起動 (CDB 再起動時の PDB の オープン・モード の保持)

ALTER PLUGGABLE DATABASE [ALL | [pdb_name]] SAVE STATE;

通常、 CDB 再起動 (通常起動) 時の PDBOPEN_MODE (オープン・モード) は MOUNTED (マウント・モード) ですが、 OPEN_MODE を保持させると、次回 CDB 起動時の PDBOPEN_MODE を CDB 再起動前と同じ状態にすることができます。

つまり、 PDBOPEN_MODEREAD WRITE (読取り/書込みモード) で上記 SQL を実行すると、次回 CDB 起動時も PDBOPEN_MODEREAD WRITE となり、 CDB の起動の度に PDB をオープンする必要が無くなります。

ちなみに、オープン・モードの保持をやめる場合は、 SAVE STATE ではなく DISCARD STATE を指定します。

データベース停止

CDB

CDB の停止は SYSDBA または SYSOPER 権限を持つユーザで行う必要があります。

SHUTDOWN [NORMAL | IMMEDIATE | TRANSACTIONAL | ABORT]
  • NORMAL (通常停止)
    • データベースへの新規接続はできないが、接続中の全ユーザーがセッションを終了するまで待機する
  • IMMEDIATE (即時停止)
  • TRANSACTIONAL
    • アクティブなトランザクションすべてが完了後、接続中の全ユーザのセッションを切断してデータベースを停止する
  • 'ABORT' (緊急停止)

PDB

PDB の停止は、マウント・モードへのオープン・モードの変更を意味します。

ALTER PLUGGABLE DATABASE [ALL | [pdb_name]] CLOSE [IMMEDIATE | ABORT];

IMMEDIATE または ABORT を指定しない場合、通常停止 (NORMAL) となります。

停止モードの詳細は、 CDB の SHUTDOWN コマンドでの停止と同様です。

おわりに

今回は「Oracle Database に接続して CDB や PDB を起動・停止する」という簡単な操作についてまとめました。

記事をまとめる中で、なるべく正確な情報を記載するため Oracle 公式ドキュメントを読みましたが、同じ結果が得られる別の方法や細かいオプションなど、取り上げていない内容が沢山あります。

ORACLE MASTER などの資格を取得するためにはそういった詳細な理解も必要ですが、プライベートでの利用程度であれば、とりあえず一つの方法が分かっていれば実用上は問題ありません。

最近は MySQLPostgreSQL などの OSS-DB や NoSQL などの利用が広がり、データベースとしての Oracle は下火になりつつあると言われていますが、個人的には Oracle Database が好きなので、次は Oracle Cloud に手を出そうかと思っています。

仕事でしかデータベースを触っていない方は、ぜひ一家に一データベースを Oracle Database で構築してみてはいかがでしょうか。

PC が重くなるという方は Oracle Cloud もありますよw

【Django3.0】TypeScript と Sass でフロントエンドを書く【webpack4】

django-logo

はじめに

Django で Web アプリケーションを開発する際、フロントエンドを TypeScript と Sass で書いて webpack でトランスパイル & バンドルする方法をまとめました。

ここでのフロントエンドとは、 Angular や React といったフレームワークを使わずに、 TypeScript と Sass で書いたファイルを webpack で JavaScriptCSS にトランスパイルして、静的ファイルとして Django テンプレートで読み込むことを指しています。

前提条件

  • Django がインストールされており、プロジェクトとアプリケーションの作成・設定が完了している
  • Node.js がインストールされており、npm init を行い package.json が作成されている

Django のインストールと初期設定については、以下の記事を参考にしてください。

ai-can-fly.hateblo.jp

動作環境

OS Version
Windows 10 Pro 1909
Application Version
PowerShell 5.1.18362.752
Environment Version
Node.js 12.16.2
npm 6.14.4
Language Version
Python 3.8.1
Package Version
Django 3.0.4
webpack 4.43.3
webpack-cli 3.3.11
typescript 3.8.3
ts-loader 7.0.1
sass 1.26.5
sass-loader 8.0.2
css-loader 3.5.3
mini-css-extract-plugin 0.9.0
postcss-loader 3.0.0
autoprefixer 9.7.6

最終的にやりたいこと

  • Django のアプリケーション毎に static ディレクトリを作り、その中に TypeScript と Sass のファイルを置く
  • webpack の entry (エントリーポイント) と output (出力先ディレクトリ) を、 Django のアプリケーション単位に設定にする
  • webpack で TypeScript と Sass を、それぞれ JavaScriptCSS にトランスパイルする
  • Django のテンプレートで、トランスパイルされた JavaScriptCSS を読み込む

Django プロジェクトの構成

[django_project]
├ [django_application_a]
│ ├ static
│ │ └ [django_application_a]
│ │   ├ css
│ │   │ ├ index.scss
│ │   │ └ main.bundle.css      ← [application_a] のバンドルファイル
│ │   └ js
│ │     ├ index.ts             ← [application_a] のエントリーポイント
│ │     └ main.bundle.js       ← [application_a] のバンドルファイル
│ └ templates
│   └ [django_application_a]
│     └ index.html             ← main.bundle.js と main.bundle.css を読み込むテンプレートファイル
└ [django_application_b]
  ├ static
  │ └ [django_application_b]
  │   ├ css
  │   │ ├ index.scss
  │   │ └ main.bundle.css      ← [application_b] のバンドルファイル
  │   └ js
  │     ├ index.ts             ← [application_b] のエントリーポイント
  │     └ main.bundle.js       ← [application_b] のバンドルファイル
  └ templates
    └ [django_application_b]
      └ index.html             ← main.bundle.js と main.bundle.css を読み込むテンプレートファイル

エントリーポイント

index.ts

import '../css/index.scss'

console.log('Hello TypeScript and Sass !!');

Django アプリケーションのエントリーポイントの TypeScript ファイルで、 Sass ファイルをインポートします。

パッケージインストール

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

npm ではなく Yarn でも可です。

webpack

npm install --save-dev webpack webpack-cli

webpackCLI で webpack を操作するために webpack-cli をインストールします。

TypeScript

npm install --save-dev typescript ts-loader

typescript と webpack で TypeScript を読み込むために ts-loader をインストールします。

Sass

npm install --save-dev sass sass-loader

sass と webpack で Sass を読み込むために sass-loader をインストールします。

CSS

npm install --save-dev css-loader mini-css-extract-plugin postcss-loader autoprefixer

@import などの依存関係の解決に css-loaderCSS ファイルを出力するために mini-css-extract-plugin 、ベンダープレフィックスを付与するために postcss-loaderautoprefixer をインストールします。

ちなみに、ベンダープレフィックスの付与は必須ではありません。

設定ファイル

TypeScript

tsc コマンドで tsconfig.json を作成し、トランスパイルの設定を記述します。

npx tsc --init

tsconfig.json

{
  "compilerOptions": {
    "module": "es2015",  // モジュール出力
    "sourceMap": true,  // ソースマップ出力
    "target": "es5",  // 変換先 ECMAScript バージョン
    "strict": true,  // 以下のオプションを一括で有効化
                     // --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictBindCallApply, 
                     // --strictNullChecks, --strictFunctionTypes, --strictPropertyInitialization
    "forceConsistentCasingInFileNames": true  // ファイル名の大文字小文字を区別する
  }
}

webpack

webpack の設定ファイルは CLI コマンドからの生成は出来ないので、ファイルを手動で作成します。

webpack.config.js

const path = require('path');
const autoprefixer = require('autoprefixer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  // モード
  mode: 'development',

  // エントリーポイント
  entry: {
    '[application_a]/static/[application_a]/js/main': path.resolve(
      __dirname,
      '[application_a]/static/[application_a]/js/index.ts'
    ),
    '[application_b]/static/[application_b]/js/main': path.resolve(
      __dirname,
      '[application_b]/static/[application_b]/js/index.ts'
    )
  },

  // ファイル出力先
  output: {
    // 出力先ディレクトリ
    path: __dirname,
    // 出力ファイル名
    filename: '[name].bundle.js',
  },

  // ソースマップ
  devtool: 'cheap-module-eval-source-map',

  // ローダー
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
      },
      {
        test: /\.scss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              esModule: true,
            },
          },
          {
            loader: 'css-loader',
            options: {
              url: false,
              sourceMap: true,
              importLoaders: 2,
            },
          },
          {
            loader: 'postcss-loader',
            options: {
              plugins: () => [autoprefixer()],
            },
          },
          {
            loader: 'sass-loader',
            options: {
              implementation: require('sass'),
              sassOptions: {
                includePaths: ['./node_modules'],
              },
              sourceMap: true,
            },
          },
        ],
      },
    ],
  },

  // モジュール解決
  resolve: {
    extensions: ['.ts', '.js'],
  },

  // プラグイン
  plugins: [
    new MiniCssExtractPlugin({
      moduleFilename: ({ name }) =>
        `${name.replace('/js/', '/css/')}.bundle.css`,
    }),
  ],
};

Django アプリケーション毎に JavaScript ファイルと CSS ファイルを出力するために、以下の点を考慮します。

  • entry には Django アプリケーション単位でエントリーポイントを指定する
  • entry に指定するオブジェクトのキーに出力先パスとファイル名の一部を指定する
  • outputJavaScript の出力ファイル名を指定する
  • pluginsMiniCssExtractPluginCSS の出力ファイル名を指定する

ポイントは entry で指定したオブジェクトのキーが、 output[name]pluginsMiniCssExtractPluginname に代入されるということです。

entry のキーにはファイル名だけでなく、パスを含む文字列が指定できるので、 Django アプリケーション毎のエントリーポイントまでのパスをキーとすることで、結果的にバンドルファイルも Django アプリケーション毎に出力することができます。

package.json

webpack を使用する上で必ず必要なものではありませんが、 npm-script によく使うコマンドを登録しておくと便利です。

{
  "name": "django-project",
  "version": "0.0.1",
  "main": "index.js",
  "private": true,
  "devDependencies": {
    "autoprefixer": "^9.7.6",
    "css-loader": "^3.5.3",
    "mini-css-extract-plugin": "^0.9.0",
    "postcss-loader": "^3.0.0",
    "sass": "^1.26.5",
    "sass-loader": "^8.0.2",
    "ts-loader": "^7.0.1",
    "typescript": "^3.8.3",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.11"
  },
  "scripts": {
    "build": "webpack",
    "watch": "webpack --watch",
    "prod": "webpack --mode=production"
  }
}

ここでは通常の webpack コマンドに加え、開発時によく使う watch オプションと、本番用の production モードの三種類を npm-script に追加しました。

テンプレートファイル

Django のテンプレートファイルには、 webpack でコンパイルされた JavaScript ファイルと CSS ファイルを読み込むように記述します。

{% load static %}
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="{% static "[application_name]/css/main.bundle.css" %}">
    <title>Django</title>
  </head>
  <body>
    Hello Django !!
    <script src="{% static "[application_name]/js/main.bundle.js" %}"></script>
  </body>
</html>

webpack の実行

package.jsonnpm-script として webpack のコマンドを登録している場合は、 npm run コマンドで webpack を実行します。

npm-script ではなく、直接 webpack コマンドで実行しても同様なので、この辺りはお好みで。

開発用

# npm-script
npm run watch

# npx
npx webpack --watch

watch オプションを付けて webpack コマンドを実行すれば、コードを変更する度に再コンパイルされるので、開発時に都度 webpack コマンドを実行する必要が無くなります。

Web 上で、「watch オプションを使用した場合、変更したコードの差分のみのコンパイルとなるので処理が高速化する」という記事をいくつか目にしましたが、 webpack 公式ドキュメントでは同様の記述を見付けられなかったので、真偽のほどは不明です…

本番用

# npm-script
npm run prod

# npx
npx webpack --mode=production

modeproduction に設定すると、 minimizetrue になるなど、本番環境での使用を想定したコンパイルが行われます。

出力ファイル

コンパイルされたファイルは、各 Django アプリケーション毎に static ディレクトリの js / css ディレクトリ内にそれぞれ出力されます。

[django_project]/[django_application]/static/[django_application]/js/main.bundle.js
[django_project]/[django_application]/static/[django_application]/css/main.bundle.css

テンプレートファイルには、出力された JavaScript ファイルと CSS ファイルを読み込むように記述します。 (テンプレートファイル を参照)

おわりに

今回紹介した内容は、単純に Django で TypeScript と Sass が使えるようになっただけではなく、 npm で配布されている様々なパッケージが使用できるようになったことを意味します。

例えば、マテリアルデザインを手軽に実装できる Material Components や 老舗の Bootstrap 、 JavaScript でグリッドを出力できる ag-Grid など、 npm でパッケージをインストールして使用すれば、 webpack がまとめてコンパイルしてくれます。

CDN から読み込んで使用する方法もありますが、ローカルにソースがあれば IDE の自動補完や定義への移動が使えるので、個人的には npm でインストールしてコンパイルする方をお勧めします。

条件を満たしていれば、 Tree Shaking によるデッドコード除去や、 Code Splitting での遅延ロードの実現など、一概に webpack より CDN の方が良いとは言い切れないと思いますので、まずはローカルインストールでもいいのではないでしょうか。

これで TypeScript + Sass + Django の組み合わせで Web アプリが作れるようになりました。

もうコードを書かない理由は無くなりましたね _(┐「ε:)_

【Prettier】「なんとなく使う」から「分かって使う」へ【Visual Studio Code】

Prettier-logo

はじめに

皆さん、 Prettier は使っていますか?

フロントエンドのコードフォーマッターのデファクトスタンダード、もはや使っていない人はいないと言っても過言ではないでしょう。(過言です)

僕も普段は Visual Studio Code (以降、 VSCode) でコードを書いていますが、 Prettier は VSCode拡張機能をインストールして使用しています。

そんな Prettier ですが、 VSCode で使用するにあたって、どこまで理解して使っているでしょうか?

VSCode で Prettier 拡張機能をインストールしたら動いたから、あとは設定を適当にいじって使っている。

そんな人はいませんか?(ちょっと前の僕です)

今回はそんな「なんとなく使う」から「分かって使う」ために、 VSCode 上での使い方を含めて Prettier についてまとめてみました。

Prettier の細かい設定については当記事では触れませんので、公式ドキュメントの Options をご覧ください。

prettier.io

前提条件

動作環境

OS Version
Windows 10 Pro 1909
Application Version
Visual Studio Code 1.44.2
PowerShell 5.1.18362.752
Node.js 12.16.2
npm 6.14.4
Yarn 1.22.4
Package Version
Prettier 2.0.5
esbenp.prettier-vscode 4.5.0

大事なことを最初に

VSCode で初めて Prettier を使用するときに、何も知らない人 (当時の僕のような) が躓くであろうポイントを最初に書いておきます。

僕ははじめ、 VSCode で Prettier 拡張機能をインストールして、設定を適当にいじったらコードがフォーマットされたため、これで Prettier が使えるものだと思っていました。

たしかに上記の方法でも Prettier は使えるのですが、厳密には Prettier と VSCode の Prettier 拡張機能は別物で、しかも Prettier 拡張機能の公式が推奨している使用方法ではありません。

当記事ではその辺りの整理をしつつ、 Prettier 拡張機能の公式ドキュメントで推奨されている使い方について記載しています。

ざっくり Q&A

とりあえず目を通しておくと、この先の話が理解しやすいかもしれないことを Q&A 形式でまとめました。

Question Answer
Prettier is 何? Prettier はコードフォーマッターです。
Prettier はどうやってインストールするの? Prettier は npm や Yarn などのパッケージマネージャーでインストールします。
Prettier はどうやって実行するの? Prettier は CLI や Git Hooks など様々な方法で実行することができます。
Prettier と VSCode の Prettier 拡張機能は違うものなの? VSCode の Prettier 拡張機能には Prettier がバンドルされていますが、とりあえずここでは違うものとしておきます。
VSCode の Prettier 拡張機能は何をするものなの? VSCode 上で Prettier を実行してくれるプラグインみたいなものです。
Prettier の設定はどうやってするの? Prettier の設定は設定ファイル (.prettierrc) で行います。
VSCode の設定 (settings.json) に Prettier の項目があるけど? それは VSCode の Prettier 拡張機能の設定です。

Prettier

それでは、さっそく Prettier の使い方について書いていきます。

いったん VSCode の Prettier 拡張機能のことは忘れましょう。

インストール

まずは、お好みのパッケージマネージャーで Prettier をインストールします。

# npm
npm install --save-dev prettier

# Yarn
yarn add prettier --dev

そう、 Prettier は npm パッケージとして提供されていて、 Node.js 上で実行されるものなのです!

ここでは、とあるプロジェクトにローカルインストールしていますが、グローバルインストールも可能です。

※ npm や Yarn についての詳細は、当記事では扱いません。

設定ファイル (.prettierrc)

次に Prettier の設定ファイルを作成します。

設定は様々な拡張子で書くことができますが、今回は package.json の次に優先度の高い「.prettierrc (拡張子無し)」で設定ファイルを作成しましょう。

ローカルインストールした場合は、プロジェクトルートに設定ファイルを配置します。

[project_root]/.prettierrc

ちなみに、 Prettier はフォーマットするファイルを起点にファイルツリーを遡って設定ファイルを検索するので、プロジェクトルートやユーザのホームディレクトリなど、任意の場所に設定ファイルを置いてスコープを管理することができます。

詳細な設定は Prettier 公式ドキュメントを参照するとして、例として僕が使用している Prettier の設定を JSON 形式で書いてみました。

{
  "arrowParens": "always",
  "bracketSpacing": true,
  "endOfLine": "lf",
  "htmlWhitespaceSensitivity": "css",
  "insertPragma": false,
  "jsxBracketSameLine": false,
  "jsxSingleQuote": false,
  "printWidth": 80,
  "proseWrap": "preserve",
  "quoteProps": "as-needed",
  "requirePragma": false,
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "useTabs": false,
  "vueIndentScriptAndStyle": false
}

prettier.io

フォーマット実行 (CLI)

設定ファイルを作成したら、 Prettier を実行してファイルをフォーマットしてみましょう。

Prettier には様々な実行方法がありますが、今回は CLI での実行例を示します。

まずは、フォーマット対象の JavaScript ファイル (dirty.js) を以下の内容で作成し、 Prettier をローカルインストールしたプロジェクト内に保存します。

function    hello  (  )
{
      console.log('Hello Prettier !!');
}

保存したらファイルを閉じて、 CLIprettier コマンドを実行します。

npx prettier --write dirty.js

実行後、ファイルを再度開いてみましょう。

function hello() {
  console.log('Hello Prettier !!');
}

きれいにフォーマットされていたら、無事 Prettier は実行されています。

これで今日から (見た目だけは) きれいなコードを書くことができますね!

prettier コマンド

prettier [options] [file/dir/glob ...]
Options Description
--check フォーマット済みかどうかをチェックする
--write フォーマットを実行して保存する

フォーマット対象はファイル単位の他に、ディレクトリ単位や glob (ワイルドカード) で複数のファイルをまとめて指定することが可能です。

まとめ

Prettier の基本的な使い方をまとめると、

  • Prettier をパッケージマネージャーでインストールする
  • 設定ファイルを作る
  • CLIprettier コマンドを実行してフォーマットする

となります。

思ったより単純でしたよね?

でも、例えば開発時を想定した時、エディタでコードを編集した後に毎回 prettier コマンドを実行するのってめちゃくちゃ面倒じゃないですか?

そんな怠惰 (誉め言葉) なエンジニアさんは、 VSCode で Prettier 拡張機能を使いましょう。

※ 他のエディタ (例えば Atom など) でも Prettier を自動実行する方法はありますが、今回は VSCode だけを取り上げます。

Visual Studio Code の Prettier 拡張機能

さて、記憶から抹消していた VSCode の Prettier 拡張機能について触れる時がやってきました。

何ができるのか

Prettier の使い方は説明してきた通りですが、 CLI でいちいちコマンドを実行するのは手間がかかるので、自動化できたら便利ですよね。

VSCode の Prettier 拡張機能は、まさに上記を体現したかのような拡張機能で、 VSCode 上で Prettier を自動で実行してくれるスーパー便利なやつなのです。

コードの保存時やペースト時に自動実行させたり、キーボードのショートカットで実行できたりと、実行方法も様々あります。

それでは Prettier 拡張機能を使用して、先程プロジェクトにローカルインストールした Prettier を実行してみましょう。

インストール

インストールは非常に簡単で、サイドバーの拡張機能から Prettier を検索して「インストール」ボタンをクリックするだけです。

Visual Studio Code - Prettier

設定 (settings.json)

VSCode の設定は、 GUI で行う方法と設定ファイル (settings.json) を直接編集する方法があり、どちらの方法でも行うことができます。

ただし、今回紹介するように言語単位で設定を行う場合は、設定ファイル (settings.json) を直接編集することになります。

今回はすべて設定ファイル (settings.json) で設定していきます。

既定のフォーマッター (Default Formatter)

VSCode には VSCode 標準フォーマッター (vscode.***-language-features) が付属しているため、既定のフォーマッターを Prettier (esbenp.prettier-vscode) に変更する必要があります。

// すべての言語を対象に既定のフォーマッターを設定する場合
"editor.defaultFormatter": "esbenp.prettier-vscode",

// 言語単位で既定のフォーマッターを設定する場合
"[javascript]": {
  "editor.defaultFormatter": "esbenp.prettier-vscode"
},

Prettier がサポートする言語については、 Prettier 公式ドキュメントを確認してください。

prettier.io

保存時にフォーマット (Format On Save)

VSCode でファイルを保存した時に、フォーマットを行うかどうかを設定します。

// すべての言語で保存時にフォーマットを行う
"editor.formatOnSave": true,

// 言語単位で保存時にフォーマットを行うか設定する
"[javascript]": {
    "editor.formatOnSave": true
},

貼り付け時にフォーマット (Format On Paste)

コードを貼り付ける際にフォーマットを行うかどうかを設定します。

// すべての言語で貼り付け時にフォーマットを行う
"editor.formatOnPaste": true,

// 言語単位で貼り付け時にフォーマットを行うか設定する
"[javascript]": {
  "editor.formatOnPaste": true
},

入力時にフォーマット (Format On Type)

コード入力時にフォーマットを行うかどうかを設定します。

// すべての言語でコード入力時にフォーマットを行う
"editor.formatOnType": true,

// 言語単位でコード入力時にフォーマットを行うか設定する
"[javascript]": {
  "editor.formatOnType": true
},

※ コード入力時というのは、一文字ずつ入力する度にフォーマットが実行されるのではなく、改行入力時や JavaScript であれば文末のセミコロン入力時にフォーマットが実行されます。入力した行単位でフォーマットが実行される感じです。

使い方

VSCode では、設定ファイル (settings.json) に基づき、既定のフォーマッターが設定されたタイミングで実行されます。

Prettier を既定のフォーマッターにし、任意のタイミングでフォーマットを行う設定にすることで、 Prettier の自動実行を実現させているというわけです。

例えば、保存時にフォーマットを行う設定にするだけで、ファイルを編集する度に Prettier を手動で実行する手間から完全に解放されるのです!

ためしに、先程作成した JavaScript ファイル (dirty.js) をもう一度開いて、インデントや半角スペースをぐちゃぐちゃにしてみましょう。

そして、おもむろに Ctrl + S で保存すると…

きれいにフォーマットされました!よね!?

VSCode ではキーボードショートカット (Shift + Alt + F) でフォーマットを実行することができるので、コードの入力中に好きなタイミングで Prettier を実行することもできます。

Prettier 拡張機能マジ便利!

これで今日から VSCode で (見た目だけは) きれいなコードを書きまくれるぞ!

まとめ

いやー、 VSCode の Prettier 拡張機能ってめちゃくちゃ便利ですねー。

それでは以上で Prettier 拡張機能の使い方を終わります…って、あれ?

はじめに」でも書いた通り、何も分からずに使っていた頃はプロジェクトに Prettier なんてインストールしてないし、もちろん設定ファイル (.prettierrc) も作ってないし、 VSCode の Prettier 拡張機能をインストールして設定 (settings.json) をいじっただけでフォーマットできていたような?

そう、これが僕のような初心者が陥る罠なのですが、なんと VSCode の Prettier 拡張機能には Prettier 本体がバンドルされて (含まれて) いるのです!

つまり、 Prettier 拡張機能さえインストールしていれば、 VSCode では Prettier が使えるということなんです!

設定 (settings.json) に Prettier の細かい設定があるのも、そこで設定された内容で Prettier のフォーマットを実行するためなのです。

えー、じゃあ別に Prettier 本体をインストールする必要は無いし、設定ファイル (.prettierrc) も作らなくていいんじゃないの?と思ってしまいそうですが、 Prettier 拡張機能の公式ドキュメントにはプロジェクトのローカルにインストールされている Prettier と設定ファイルを使用することを推奨する旨がしっかり記載されています。

marketplace.visualstudio.com

これは当然といえば当然ですが、チームで開発する場合はパッケージのバージョンや設定を揃えないといけないですし、そもそも VSCode 以外のエディタを使っている人もいるかもしれないので、設定の統一が難しくなってしまいます。

Prettier 拡張機能にバンドルされている Prettier や VSCode の設定は、あくまでもフォールバック的な位置付けで、優先される設定もローカルの Prettier 設定ファイル (.prettierrc) が上位になっています。

ローカルに Prettier 設定ファイル (.prettierrc) が存在し、一つでも設定項目が書かれている場合、 VSCode の Prettier の設定はすべて適用されません。

Prettier 拡張機能は、ローカルにインストールされている Prettier を VSCode 上で実行するための補助機能として使うことをお勧めします。

おわりに

だいぶ長くなりましたが、これで Prettier について何となくは理解できたでしょうか。

「なんか知らんけどフォーマットはできている」状態から「Prettier 完全に理解した」レベルにはなれたんじゃないかと思います。

ただ、一般的に Prettier を使うプロジェクトの場合、リンターに ESLint を使用しているケースが大半で、僕も ESLint を併用していたりします。

Prettier と ESLint はフロントエンドではセットで使用するのがデファクトスタンダードになっており、これらの知識は必須と言えます。

セットで使用するのが当たり前と言いつつ、素直にそのまま併用すると問題が出たりするので、この辺りもフロントエンドがややこしいと言われる一端…は言い過ぎでしょうか…

ということで、 ESLint についてはまた別記事でまとめたいと思います。

最後までお読みいただき、ありがとうございました!