Typescriptでwebpackを使用する。

Typescriptでwebpackを使用する学習を行ったので、復習も兼ねて投稿します。

# 目次
**■Webpackとは**

**■環境構築**

**■実際に利用してみた**

**■参考文献**

# ■<font color="blue">webpack</font>　とは
**結論**　＝　**<font color="red">モジュールバンドラー<font>**

**■モジュール　→　ファイル・ファイル群**

**■バンドラー　→ 複数のものを１つにまとめるもの**

つまり、
<font color="red">**複数のファイルをぎゅっと１つにまとめることがwebpackの役割である。**</font>

## - なぜ１つにまとめる必要があるのか -

理由は主に２つ。

**<font color="blue">①リクエストの回数を減らすことで効率UP</font>**
→ファイルが複数あるとリクエスト回数がその分増えるので、サーバにも負荷がかかります。
　結果、読み込みの遅延やサーバーダウンなどにつながります。
　

**<font color="blue">②コードの最適化</font>**
→１つのファイルに小さくまとめることでファイルのサイズが小さくなり、パフォーマンスが向上します。

# ■環境構築

## ・ 事前準備
適当に下記のようなプロジェクトを作成します。

**※Node.js（npm）はインストール済であること**

![スクリーンショット 2022-09-27 19.52.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/6ff8b0c7-aa72-3c4a-d858-a392a527a94e.png)

## ・ package.jsonの作成
ターミナルを開き、package.jsonを作成。

**■コマンド**
```
npm init -y
```

**■package.json**
以下のようなものが作成されるはずです。
```javascript
{
  "name": "sample_typescript",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

```

## ・ webpackのインストール
■コマンド
```
npm install --save-dev webpack webpack-cli
```
**■webpack** → 今回の主役。

**■webpack-cli** → webpackコマンドをターミナル等で実行する際はこのwebpack-cliを見るので、合わせてインストールすることが必須。

**■--save-dev** → 開発環境(devdependencies)にインストールする際に必要なオプションコマンド。説明は長くなるので省略。

以下のように、node_modulesが追加され、package.jsonに追記されていればOKです。
![スクリーンショット 2022-09-27 20.07.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/7e9968dd-54c9-13ff-f2a0-cf177e961d22.png)

## ・ ts-loaderのインストール
ts-loaderをインストールすることで、webpackがTypescriptを理解できるようになります。

**■コマンド**
```
npm install --save-dev ts-loader typescript
```
**<font color="red">※注意</font>**
ts-loaderをインストールする際は、devdependenciesにTypescriptをインストールする必要があるので、ts-loaderを使用するときはTypescriptもセットでインストールすること。


## ・ 設定ファイル  （webpack.config.js） の作成・設定
webpack用の設定ファイルを作成する。
このファイルは名前を必ず、<font color="red">**webpack.config.js**</font>にしなければならない。
作成し、中身を記載。

**■webpack.config.js**
```javascript
/**
 * require → Node.js上で利用するimport文のこと
 * 
 * path → Node.jsがデフォルトで内蔵しているモジュール（ファイル）のこと。
 * デフォルトで存在するものなので、インポートだけすれば使える仕様。
 */
const path = require('path');

module.exports = {

 // どのソースからスタートするか
 entry:"./src/sample.ts",

 output: {
    // 出力するファイル名
    filename: "bundle.js",

    // 出力するファイルをどこに出力するか（絶対パスで書く）
    path: path.resolve(__dirname, "dist")
 },

 // ts-loaderの設定
 module: {
    rules:[{
        // どんなファイルに対して
        test: /\.ts$/,

        // 何をするのか
         use: 'ts-loader',

         // node_modulesから持ってきたtsファイルはts-loaderの対象から省く
         exclude: /node_modules/
    }]
 },
 resolve: {
    /**
     * import文で記載しているファイル名を拡張子をつけずに記載した場合、
     * extensions配列内に記載した拡張子がついた同名のファイルがあるか検索し、
     * あればそのファイルをimportする。
     * 
     * 検索は配列の左から順番に行う。
     */
    extensions: ['.ts', '.js']
 }
}
```
**< 補足説明 >**

**■module.exports**　→　Node.jsのエクスポート文。（ES6のexport文と意味は同じ）
webpackコマンドを打った時に、webpackが内部的にmodule.exportsでエクスポートしたオブジェクトを使用する。

**■__dirname**　→　Node.js上にあるグローバル変数。今いるディレクトリの絶対パスがこの変数に格納されている。
```
例） 今回であれば、

Users/${プロジェクトまでのパス}/SAMPLE_TYPESCRIPT
```

**■path.resolve(__dirname, "dist")**　→　第一引数に与えたパスに、第二引数以降の文字列を連結し、新たなパスとして返す。
```
例） 今回であれば、

Users/${プロジェクトまでのパス}/SAMPLE_TYPESCRIPT/dist
```

ここまでで準備は完了です。

# ■実際に利用してみた
今回は以下のファイルを分割し、webpackでバンドリングしてみます。

```javascript
// interface
interface Humans {
  name: string;
  age: number;
  gender: string;
  country: string;
}

// クラス①
class Man implements Humans {
  name = "michael";
  age = 25;
  gender = "male";
  country = "america";
}

// クラス②
class Woman implements Humans {
  name = "Catherine";
  age = 20;
  gender = "female";
  country = "america";
}

// クラス③
class Caller {
  public woman: Woman;

  public man: Man;

  constructor() {
    this.man = new Man();
    this.woman = new Woman();
  }

  call() {
    console.log(
      `My name is ${this.man.name}. ${this.man.age} years old from ${this.man.country}.`
    );
    console.log(
      `My name is ${this.woman.name}. ${this.woman.age} years old from ${this.woman.country}.`
    );
  }
}

const caller = new Caller();

caller.call();

```
型となるインターフェースと、
継承した２つのクラスとそのプロパティをよぶメソッドを持つクラスという簡単なものです。

## ■ESモジュールを利用して分割
### ・ interface.ts
```javascript
export interface Humans {
  name: string;
  age: number;
  gender: string;
  country: string;
}
```

### ・ Man.ts
```javascript
import { Humans } from "./interface";

export class Man implements Humans {
  name = "michael";
  age = 25;
  gender = "male";
  country = "america";
}
```

### ・ Woman.ts
```javascript
import { Humans } from "./interface";

export class Woman implements Humans {
  name = "Catherine";
  age = 20;
  gender = "female";
  country = "america";
}
```

### ・ Caller.ts
```javascript
import { Woman } from "./Woman";
import { Man } from "./Man";

export class Caller {
  public woman: Woman;

  public man: Man;

  constructor() {
    this.man = new Man();
    this.woman = new Woman();
  }

  call() {
    console.log(
      `My name is ${this.man.name}. ${this.man.age} years old from ${this.man.country}.`
    );
    console.log(
      `My name is ${this.woman.name}. ${this.woman.age} years old from ${this.woman.country}.`
    );
  }
}
```

### ・ sample.ts
```javascript
import { Caller } from "./Caller";

const caller = new Caller();

caller.call();
```

これで分割は完了です。

**< 補足説明 >**
各tsファイルにESモジュールによるimportが書かれていますが、
importするファイル名に拡張子の記載がありません。

それでもimportできるのは、webpack.config.tsで設定をしたからです。

**■webpack.config.js**
```javascript
resolve: {
    extensions: ['.ts', '.js']
 }
```

この設定がないと、構文エラーとなります。

## ■バンドリングに向けて追加修正

### ・ distフォルダを追加
出力先パスが
```javascript
path: path.resolve(__dirname, "dist")

// Users/${プロジェクトまでのパス}/SAMPLE_TYPESCRIPT/dist
```
なので、distフォルダを追加します。

![スクリーンショット 2022-09-29 19.18.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/8bee364e-33ee-a786-b2a2-1206bdcbfcaa.png)

### ・ package.jsonにエイリアス（別名）を追加
package.json内に、webpackを実行するようのエイリアスを追加。

**■package.json**
```javascript
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    // 追加
    "build": "webpack"
  },
```
これで環境構築は完了です。

## ■実行
ターミナルを開き、下記コマンドを実行します。
```
npm run build
```
![スクリーンショット 2022-09-29 19.35.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/90cd1195-6265-6d72-3f46-e63fd2378f3f.png)

コマンドが実行され、bundle.jsがdist内に出力されました。

これでバンドリング完了です。
完成したjsファイルを実行すると、

![スクリーンショット 2022-09-29 19.38.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/7466e874-10ce-9a92-bae1-bd8fbc132cdf.png)

しっかり出力されました。

今回はconsoleで出力するだけでしたが、
ブラウザ上で表示させたりしたい場合は他にも設定が必要になります。

# ■参考文献
https://www.udemy.com/course/typescript-complete/