ヒトリ歩き

愚痴とかいろいろ書きます

フロントエンドのフの字も知らない私がwebpackを使うことになった

フロンドエンドの仕事をすることになりました。
過去の業務では、ほぼサーバサイドの仕事をしてまして初めてフロントエンドの仕事をすることになります。右も左も分かりません・・・。

そんなサーバサイドしかやったことない私ですが、プロジェクトでwebpackを使っているようなので、webpackに足を踏み入れてみようと思います。

webpackとは

webpackとは、JavaScriptアプリケーションのための静的モジュールハンドラーです。
アプリケーションを処理する際に、必要となるモジュールと1つまたは複数のハンドルを生成します。
複数のJSファイルなどを1つのバンドルファイルにするための、パッケージと覚えておけばいいと思います。

webpackのCore Concepts

webpackの公式ページにCore Concepsを理解しておく必要があるということなので、書き出しとく。
英語ダメダメなので、誤訳やら文章がおかしかったら、すみません。

Key 概要
Entry エントリーポイントとなるモジュールを定義する 
Output バンドルして作成されるファイル名と出力先フォルダを指定する
Loaders モジュールのソースコードの変換をする。TypeScriptであれば、JavaScriptに変換をする。
Plugins バンドルの最適化や環境変数の設定などのタスクの実行を拡張するためのプラグインを使用する。
Mode development,production,noneといった最適化するためのモードを設定する。デフォルトは、production
Browser Compatibility ES5-compliantにある全てのブラウザをサポートする

webpack.js.org

webpackを使用するための準備

webpackを使用するために、必要なパッケージをインストールする。

$ npm install webpack webpack-cli --save-dev

TypeScriptからバンドルしたJavaScriptを生成する

webpackの公式ページにあるTypeScriptでのwebpackの使い方の説明を少し変更してやってみます。
webpack.js.org

変更点は、srcフォルダにindex.tsだけ使用するところをindex.ts、member.tsの2つのファイルを使用します。
index.tsは、member.tsをインポートしており、依存関係があります。

上記の内容を踏まえて、ファイルやディレクトリの構成は次の通りとなります。

.
├── dist
│   └── index.html
├── node_modules
├── package-lock.json
├── package.json
├── src
│   ├── index.ts
│   └── member.ts
├── tsconfig.json
└── webpack.config.js

前準備

webpackで、ローダーを使用してTypeScriptを変換するためTypeScript用のローダーをインストールする。

$ npm install --save-dev typescript ts-loader

webpack.config.jsを作成する

webpack.config.jsを作成する。

const path = require('path');

module.exports = {
  entry: './src/index.ts',
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: [ '.tsx', '.ts', '.js' ],
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

バンドルファイルを生成する

webpackを実行する。

$ npx webpack --config webpack.config.js
Hash: 04f5b2971ebc3777a797
Version: webpack 4.42.1
Time: 1489ms
Built at: 2020-04-18 22:33:06
    Asset      Size  Chunks             Chunk Names
bundle.js  7.79 KiB       0  [emitted]  main
Entrypoint main = bundle.js
[0] ./src/index.ts + 1 modules 310 bytes {0} [built]
    | ./src/index.ts 77 bytes [built]
    | ./src/member.ts 233 bytes [built]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

dist 配下にbundle.jsが生成されました。

webpack.config.jsの内容を見ていく

const path = require('path');

pathモジュールの読み込みをします。 outputキーのところで出てきますが、resolve関数を使用してハンドルしたJSファイルの出力先の ディレクトリパスを作成するために使用します。

  entry: './src/index.ts',

バンドルするTypeScriptのエントリーポイントを指定します。 エントリーポイントが複数存在する場合は、配列で指定します。

  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },

testに指定した正規表現に一致するファイル名のものに対して、useに指定した ローダーを使って、ビルド処理を行う。 excludeにビルド処理から除外するものを指定する。 (node_modulesを指定することが多いと思う。)

  resolve: {
    extensions: [ '.tsx', '.ts', '.js' ],
  },

ビルド対象に含めたいファイルの拡張子を指定します。 (requireしているもの)

  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },

ビルドし、バンドルした成果物に関する設定をします。 __dirnameは、webpack.config.jsを配置しているディレクトリの絶対パスが設定されています。

key 内容
filename バンドルして作成されるファイル名を指定
path バンドルして作成されるファイルの配置先を指定

最後に

実際に調べながて手を動かしたことで、基本的な部分は理解できたと思う。 プラグインとかもあるようなので、もう少し使いながら理解していく必要がある。   デプロイとかリリースファイルの作成とかもwebpackでやるのかやらないのかは、これからまた、手を動かして理解していきます。

参考

最新版で学ぶwebpack 4入門 ics.media

最新版を追従しているので、手を動かす時間が取れない人は、このサイトを見ることをお勧めします。

手を動かした際に、使用したファイルを載せておきます。

tsconfig.json

{
  "compilerOptions": {
      "outDir": "./dist/",
      "sourceMap": true,
      "noImplicitAny": true,
      "module": "es6",
      "target": "es5",
      "jsx": "react",
      "allowJs": true
  }
}

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <div id="sample"></div>
        <script src="./bundle.js"></script>
    </body>
</html>

index.ts

import { Member } from "./member";

const mem = new Member("aaa");
mem.print();

member.ts

export class Member {

    private name:string;

    constructor(name: string) {
        this.name = name;
    }

    public print(): void {
        document.getElementById("sample").innerHTML = "SampleDesu!!!!";
    }
}