TailwindCSS+TypeScript+Webpack5の開発環境を整える

# 目的
キャンペーンのランディングページのような簡単なHTMLを作成したいです。Javascriptフレームワークのような大きなライブラリはいらないけど、TailwindCSS、TypeScriptは使いたいです。

## TailwindCSS
多くのユーティリティクラスを提供してくれるCSSライブラリです。HTMLの見栄えをこうしたいと思ったときに素直にクラスを選択できるのが良いと思っています。ただしビルド環境が必要なるので始めるのには準備が必要です。この記事はまさにその準備に焦点をあてています。

## TypeScript
せっかくビルド環境があるので、TypeScriptも導入します。ちいさなWebを書くのにもTypeScriptが無いとつらいです。

## Webpack5
最新のWebpackとWebpackDevServerを利用します。ぐぐっても昔の記事しかでなくて苦労します。この記事も1年くらいの賞味期限でしょうか。

# コード
## 必要なライブラリをインストール
```
yarn add --dev autoprefixer css-loader postcss postcss-loader style-loader tailwindcss ts-loader typescript webpack webpack-cli webpack-dev-server
```

## ディレクトリ構成
```
node-modules
public
 |-index.html
 |-js
    |-main.js(wabpackにより生成)
src
 |-index.ts
 |-style.css
package.json
postcss.config.js
tailwind.config.js
tsconfig.json
webpack.config.js
yarn.lock
```

## 各種設定ファイル

```json:package.json
{
  "devDependencies": {
    "@webpack-cli/generators": "^2.3.0",
    "autoprefixer": "^10.3.5",
    "css-loader": "^6.3.0",
    "postcss": "^8.3.7",
    "postcss-loader": "^6.1.1",
    "style-loader": "^3.3.0",
    "tailwindcss": "^2.2.15",
    "ts-loader": "^9.2.6",
    "typescript": "^4.4.3",
    "webpack": "^5.53.0",
    "webpack-cli": "^4.8.0",
    "webpack-dev-server": "^4.2.1"
  },
  "scripts": {
    "dev": "webpack serve",
    "build": "webpack"
  }
}
```

```javascript:webpack.config.js
const webpack = require('webpack');

module.exports = {
    // モード値を production に設定すると最適化された状態で、
    // development に設定するとソースマップ有効でJSファイルが出力される
    mode: 'development',

    target: 'web',

    // メインとなるJavaScriptファイル（エントリーポイント）
    entry: './src/index.ts',

    output: {
        // バンドルしてmain.jsとして出力
        filename: 'main.js',
        path: `${__dirname}/public/js`,

        // webpack-dev-serverに書き換わるファイルを教える
        publicPath: '/js/'
    },

    module: {
      rules: [
        {
          // 拡張子 .ts の場合
          test: /\.ts$/,
          // TypeScript をコンパイルする
          use: 'ts-loader',
        },
        {
          test: /\.css$/i,
          use: ['style-loader', 'css-loader', 'postcss-loader'],
        },
      ],
    },
    // import 文で .ts ファイルを解決するため
    // これを定義しないと import 文で拡張子を書く必要が生まれる。
    // フロントエンドの開発では拡張子を省略することが多いので、
    // 記載したほうがトラブルに巻き込まれにくい。
    resolve: {
      // 拡張子を配列で指定
      extensions: [
        '.ts', '.js',
      ],
      fallback: {
        fs: false,
        path: false,
        http: false,
        https: false,
        zlib: false,
        util: false,
        stream: false,
        assert: false,
        process: false,
        events: false,
        querystring: false,
        url: false
      }
    },

    devServer: {
      static: {
        directory: `${__dirname}/public`
      },

      // 変更時リロードする
      hot: true,

      // 監視するファイルを指定する
      watchFiles: ['src/**/*.ts', 'public/**/*'],
    },

    // 変更時にコンパイルする指定
    watch: true,

    plugins: [
      new webpack.ProvidePlugin({
        process: 'process/browser',
        Buffer: ['buffer', 'Buffer']
      }),
    ]
  };
```

```json:tsconfig.json
{
  "include": ["src/**/*"],
  "compilerOptions": {
    "sourceMap": false,
    "target": "es5",
    "module": "commonjs",
    "lib": ["es2017", "dom"],
    "moduleResolution": "node",
    "esModuleInterop": true
  }
}
```

```javascript:postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}
```

```javascript:tailwind.config.js
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
```

## ソース
```typescript:index.ts
import "./style.css"

var callback = function(){
  console.log("ready");
};

if (
  document.readyState === "complete" || document.readyState !== "loading"
) {
  callback();
} else {
  document.addEventListener("DOMContentLoaded", callback);
}
```

```css:style.css
@tailwind base;
@tailwind utilities;

@import url('https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap');

/* フォント */
html, body {
  font-family: 'Noto Sans CJK JP', sans-serif;
}
```

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>テスト</title>
  <script src="./js/main.js"></script>
</head>
<body>
  <p class="bg-red-300">あいうえお</p>
</body>
</html>
```