自分用ダッシュボード、My Todo NoteのWebpack設定
この記事は下記のシリーズの記事の 1 つです。
関連シリーズ:自分用の Dashboard サービスを作成する
注意:Webpack の設定構築、学習は時間がかかります
Webpack 設定を自分で書く場合、設定やデバッグにかなり時間をとられます。目的が React の使い方を学ぶことなら、自身で作成せずに CreateReactApp を使用して設定済みの環境をベースに開発するか、この記事で紹介するブランチのものをそのまま使用することをお勧めします。
My-Todo-Note では Webpack 設定を自分で書く予定なので記事にしていますが、これはわたしが Webpack 設定と慣れ親しんでおきたい、設定を色々実験したいのが理由であり、CreateReactApp と比較して特段良いことはありません。多分。
開発用リポジトリ
My-Todo-Note は次のリポジトリで管理しています。
この記事の最終結果は次のブランチで確認できます。
それでは、長く恐ろしい開発環境の構築を始めます。
package.json の作成
まずは package.json の準備。手動で作成しても良いです。
yarn init -y
React と使用予定のライブラリの追加
必要になった段階で随時追加すれば良いため、まずは思いついたもののみ追加します。
yarn add react react-dom react-router-dom axios classnames dotenv formik yup firebase
TypeScript 用に型定義のライブラリを追加。
yarn add -D @types/react @types/react-dom @types/classnames @types/react-router-dom
Webpack の追加
Webpack と関連ライブラリを追加します。やや手探りに進めているため必要なものは随時追加し、必要のないものは随時削除します。
Webpack 周りは何が最低限必要かを把握するのに毎回苦労し、設定含めスムーズに終わったことがありません。CreateReactApp の凄さを感じる部分です。
Webpack 本体
yarn add -D webpack webpack-cli webpack-dev-server webpack-merge dotenv-webpack html-webpack-plugin clean-webpack-plugin
JavaScript、TypeScript 関連
yarn add -D @babel/cli @babel/core @babel/preset-env @babel/preset-typescript @babel/preset-react @babel/plugin-transform-async-to-generator babel-loader typescript core-js regenerator-runtime fork-ts-checker-webpack-plugin @typescript-eslint/eslint-plugin @typescript-eslint/parser
css 関連
yarn add -D sass sass-loader sass-resources-loader css-loader style-loader
Webpack の設定ファイルの追加
開発用 と 本番用(build 設定)、共通設定の 3 ファイル作成します。build が必要になった段階で production を作る想定で、ひとまず開発ができるところを目指します。
エントリーファイルの追加
public/index.html を作成します
<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My ToDo Note</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
webpack 設定ファイルの追加
webpack.dev.js、webpack.prod.js、webpack.common.js を追加します。
現在のファイル構成
.
├── LICENSE
├── package.json
├── public
│ └── index.html
├── webpack.common.js
├── webpack.dev.js
├── webpack.prod.js
└── yarn.lock
webpack.common.js の修正
色々と調べながら、下記のように作成しました。これも修正の必要性を感じた段階でブラッシュアップします。ひとまず動けば良いと考えています。
css は通常の css、scss、css-modules の 3 種を扱えるように設定しました。*.module.scss でファイルを作成すれば css-module となります。共通の style は src/styles/shared/*.scss に設定します。
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const Dotenv = require("dotenv-webpack");
module.exports = {
mode: "development",
entry: {
app: "./src/index.tsx",
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
new ForkTsCheckerWebpackPlugin(),
new Dotenv(),
],
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.(j|t)sx?$/,
loader: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.scss$/,
exclude: /\.module\.scss$/,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
options: {
importLoaders: 1,
modules: {
compileType: "icss",
},
},
},
{
loader: "sass-loader",
},
],
},
{
test: /\.module\.scss$/,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
options: {
importLoaders: 1,
modules: {
compileType: "module",
},
},
},
{
loader: "sass-loader",
},
{
loader: "sass-resources-loader",
options: {
resources: "src/styles/shared/*.scss",
},
},
],
},
],
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"],
},
};
webpack.dev.js の編集
開発時の dev-server 設定を書きます。
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
module.exports = merge(common, {
mode: "development",
devtool: "inline-source-map",
devServer: {
contentBase: "./dist",
hot: true,
open: true,
historyApiFallback: true,
},
});
webpack.prod.js の編集
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
module.exports = merge(common, {
mode: "production",
});
babel 用設定ファイルの追加
package.json と同じ階層に babel.config.json を作成します。
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3"
}
],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": ["@babel/plugin-transform-async-to-generator"]
}
tsconfig.json の追加
同様に tsconfig.json を作成し、TypeScript 用の設定ファイルを作成してざっくりとルール追加します。
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true,
"sourceMap": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"exclude": ["node_modules"]
}
package.json に script を追加
"scripts": {
"start": "webpack serve --config webpack.dev.js "
}
src/index.tsx の追加
ここまでの設定で Webpack が上手く動作するかを確認します。index.tsx ファイルを作成し、React で Hello World!!!を表示させます。
import "core-js/stable";
import "regenerator-runtime/runtime";
import React from "react";
import ReactDOM from "react-dom";
ReactDOM.render(<div>Hello World!!!</div>, document.getElementById("root"));
yarn start
エラーなく dev-server が起動した場合、localhost:8080 で Hello World が表示されます。
css のチェック
次に css 関連が正しく動作しているかを確認します。scss を import できるよう型定義ファイルを作成しておきます。
- styles.d.ts
declare module "*.scss" {
interface IClassNames {
[className: string]: string;
}
const classNames: IClassNames;
export = classNames;
}
index.tsx を次のように修正します。
import "core-js/stable";
import "regenerator-runtime/runtime";
import React from "react";
import ReactDOM from "react-dom";
import { App } from "./App";
import "./styles/index.scss";
ReactDOM.render(<App />, document.getElementById("root"));
次のファイルを作成します。
- src/App.tsx
- src/styles/index.scss
- src/styles/shared/colors.scss
- src/styles/app.module.scss
App.tsx
import React from "react";
import styles from "./styles/app.module.scss";
export const App = () => {
return <div className={styles.appTxt}>App!!!</div>;
};
colors.scss
$blue: blue;
app.module.scss
.appTxt {
color: $blue;
}
実際の画面
スタイルが正しく変更されていれば OK です。
ESLint、Prettier の追加
これらも後で設定を詰めていけば良いので、ざっくりと設定します。
yarn add -D eslint eslint-plugin-react eslint-plugin-react-hooks prettier
新規で設定ファイルを作成
Webpack との連動は後回しで、vscode でシンタックスが出る程度で良しとします。
- .eslintrc.json
- .prettierrc.json
// .eslintrc.json
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended"
],
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"babelOptions": {
"configFile": "./babel.config.json"
}
},
"env": {
"browser": true,
"commonjs": true
},
"rules": {
"react/prop-types": "off"
}
}
// .prettierrc.json
{
"arrowParens": "always",
"bracketSpacing": true,
"embeddedLanguageFormatting": "auto",
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"jsxBracketSameLine": false,
"jsxSingleQuote": false,
"printWidth": 80,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": false
}
lint-staged の追加
lint-staged を使用すると、git にファイルを commit する度に eslint と prettier を自動で動作させる設定を追加できます。
npx mrm lint-staged
package.json を修正し、対象ファイルを変更します
"lint-staged": {
"src/*.{js,ts,tsx}": "eslint --fix",
"src/*.{js,ts,tsx,css,scss,md}": "prettier --write"
}
ignore 系ファイルの追加
eslint や prettier、git などの ignore ファイルを追加します。node_modules を前提に、他は必要なものを適時追加します。
最終:ファイル構成
ここまでの作業で次のようになります。
.
├── LICENSE
├── package.json
├── public
│ └── index.html
├── src
│ ├── App.tsx
│ ├── index.tsx
│ └── styles
│ ├── app.module.scss
│ ├── index.scss
│ └── shared
│ └── color.scss
├── styles.d.ts
├── tsconfig.json
├── babel.config.json
├── webpack.common.js
├── webpack.dev.js
├── webpack.prod.js
└── yarn.lock
最低限の開発環境は整いました。次回はトップページとルーティングを作成します。