React × Reduxの連載記事の5回目です。
前回はMaterial-uiの実装を行い、デザインの変更を行いました。
今回もデザイン関連の設定になりますが、cssファイルを作成して、webpackで読み込んで反映させる方法を書きたいと思います。
複数のcssファイルが作成されたときのことを考慮して、bundle時に1つのcssにまとめて出力するようにしてみたいと思います。
- webpackでのcssの読み込み方法
- cssを結合してbundleする方法
- cssを圧縮して最小化させる方法
この記事のターゲットとなる環境
現在の環境状況や前提条件を書いておきます。
- Mac OS Catalina ver 10.15.3
- 4日目の記事内容まで理解している
- 環境ターゲット(2020-03-12現在最新)
- React16.13
- Redux7.2
- webpack4.42
- babel7.8.7
- eslint6.8
- Material-UI4.9.5
これまでのReact × Reduxの連載記事はこちらからどうぞ
http://hirooooo-lab.com/react-redux/必要なnodeモジュールをインストールする
cssを反映させるために、以下のモジュールをインストールします。
- css-loader
- mini-css-extract-plugin
- optimize-css-assets-webpack-plugin
- terser-webpack-plugin
css-loader
cssをjavascriptで読み込めるようにするローダーです。
以下のコマンドでインストールしてください。
$ npm install --save-dev css-loader
mini-css-extract-plugin
mini-css-extract-pluginはcssを1つのファイルにまとめて出力するためのモジュールです。
以下のコマンドでインストールしてください。
$ npm install --save-dev mini-css-extract-plugin
webpack v3まではextract-text-webpack-pluginというモジュールを使っていましたがv4からはmini-css-extract-pluginになりました。
optimize-css-assets-webpack-plugin
OptimizeCSSAssetsPluginはCSSを最小化させるためのプラグインです。
$ npm install --save-dev optimize-css-assets-webpack-plugin
terser-webpack-plugin
TerserPluginはJSファイルを圧縮して最小化させるためのプラグインです。
後述するwebpack.config.jsで、cssのminimizerを記述するのですが、同時にjsのminimizerもさせる必要があるため、今回一緒にインストールしておきます。
$ npm install --save-dev terser-webpack-plugin
これで必要なモジュールのインストールは完了です。
bundle.js内に<style>
タグとして読み込ませてしまい、cssファイルを別に出力しないようにするのが主流かもしれませんが、今回はあえてcssファイルを別で出力するようにしたいと思います。
webpackのcss周りについてはいろんなpluginがあり、各プラグインでもオプションが多く存在して様々な機能があるので、一度ちゃんと調べてみることをオススメします。
cssファイルを作成する
src/css/main.cssファイルを作成します。
ブラウザの規定でbodyに余分なmarginがあったりしたので、そのあたりを削除してみます。
また、スタイルとしてdiv用のセンタリングスタイルとしてcenterTableというスタイルを作ってみましょう。
html {
font-size: 13px;
line-height: 20px;
color: #5b5b5b;
min-height: 100%;
position: relative;
}
body {
margin: 0px;
min-height: 100%;
background-color: #FAFAFA
}
.centerTable {
margin: 0 auto 0 auto;
display: table;
}
cssファイルを反映させる
src/index.jsxの修正
index.jsxでcssファイルをインポートしておきます。
// cssインポート
import './css/main.css';
全体像はこちら
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
// cssインポート
import './css/main.css';
import stores from '../stores';
import App from '../container/AppContainer';
const render = () => {
ReactDOM.render(
<Provider store={stores}>
<div>
<App />
</div>
</Provider>,
document.getElementById('root'),
);
};
render();
components/CounterComponent.jsxの修正
Counter.jsxのカウント値が表示されるところと、ボタンのところをセンタリングさせたいと思います。
対象箇所をdivでくくり、作成したcssのcenterTableスタイルを当てます。
components/CounterComponent.jsx
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import AddIcon from '@material-ui/icons/AddCircle';
import RemoveIcon from '@material-ui/icons/RemoveCircle';
const useStyles = makeStyles((theme) => ({
button: {
margin: theme.spacing(1),
},
}));
const CounterComponent = (props) => {
const { counter, counterActions } = props;
const classes = useStyles();
return (
<div style={{ width: '100%' }}>
<div className="centerTable">
<h2>
count={counter.value}
</h2>
<Button
className={classes.button}
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={() => counterActions.increment()}
>
増加
</Button>
<Button
className={classes.button}
variant="contained"
color="secondary"
startIcon={<RemoveIcon />}
onClick={() => counterActions.decrement()}
>
減少
</Button>
</div>
</div>
);
};
CounterComponent.propTypes = {
counter: PropTypes.shape({
value: PropTypes.number,
}).isRequired,
counterActions: PropTypes.shape({
increment: PropTypes.func,
decrement: PropTypes.func,
}).isRequired,
};
export default CounterComponent;
webpack.configの修正
cssを読み込めるようにloadersの追加とpluginの追加を行います。
必要なモジュールを読み込みます
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
MiniCssExtractPluginの追加
読み込んだcssを出力する設定の記述を追記します。
plugins: [
// MiniCssExtractPluginのインスタンスを追記
// ここで設定するfilenameは出力するファイル名
new MiniCssExtractPlugin({
filename: 'css/bundle.css',
}),
],
css-loaderの追加
cssファイルのload処理を追記します。
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
optimization.minimizerの追加
cssファイルの出力時に、圧縮して最小化する設定を追記します。
optimization: {
minimizer: [new TerserPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
cssの圧縮はOptimizeCSSAssetsPluginで行いますが、optimization.minimizerを記述するとjsの圧縮も有効になってしまうので、TerserPluginも記述しています。
これで、ソース上で参照しているcssが読み込まれ、bundle時にはcss/bundle.cssというファイルに纏められて出力されるようになります。
HtmlWebpackPluginも使用しているので、作成されるindex.htmlには出力されたcss/bundle.cssへのLinkタグが動的に挿入されます。
webpack.configの全体像
全体的にはこんな感じになりました。
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
context: __dirname,
entry: [
'./src/index.jsx',
],
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.jsx$/,
enforce: 'pre',
exclude: /node_modules/,
loader: 'eslint-loader',
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: ['babel-loader'],
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body',
}),
new webpack.LoaderOptionsPlugin({
options: {
eslint: {
configFile: './.eslintrc',
},
},
}),
// MiniCssExtractPluginのインスタンスを追記
// ここで設定するfilenameは出力するファイル名
new MiniCssExtractPlugin({
filename: 'css/bundle.css',
}),
],
optimization: {
minimizer: [new TerserPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
};
実行してみる
npm startで実行してみましょう。
以前の状態
今回の状態
無事センタリングされていたらcssの反映は完了です。
buildしてみる
npmスクリプトのbuildタスクを実行してみると、生成ファイルがdistディレクトリに出力されるようになっています。
以下のコマンドをターミナルから出力してみてください。
$ npm run build
distディレクトリが生成されて中に以下のファイルが作成されたと思います。
index.htmlの内容を見てみると、出力されたbundle.cssのリンクが動的に作成されているのがわかると思います。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>React-Redux Boilerplate</title>
<link href="/css/bundle.css" rel="stylesheet"></head>
<body>
<div id="root"></div>
<script type="text/javascript" src="/bundle.js"></script></body>
</html>
webpackでCSSを読み込んで反映編
今回はcssをwebpackで読み込んで、最小化出力の方法を書いてみました。
cssファイルを別出しにしましたし、cssメタ言語のsassやlessは使用しませんでした。
もし使用する場合でもwebpackのloaderで問題なく対応できると思います。
webpack関連のプラグインはバージョンが変わるごとに変更になったり、様々な種類があるので、ちょっと複雑な感じがしちゃいますが、基本的には公式サイトに書いてあったりするので、正しいバージョンとモジュールの組み合わせさえ注意すれば問題なく実装できると思います。
- webpack v4ではcssの抽出を行うのにMiniCssExtractPluginを使う
- 圧縮するにはOptimizeCSSAssetsPluginをminimizerに追記する
- その際TerserPluginでjsも圧縮しておく
次回予告
次回予告というかやろうと思ってること
- Redux Toolkitから作成するDucksパターンで実装する[jin_icon_check_circle]完了
- ESLintでAirbnbのスタイルガイドを実装する[jin_icon_check_circle]完了
- Materialデザインを実装する[jin_icon_check_circle]完了
- カスタムCSSを実装する[jin_icon_check_circle]完了
- ページルーティングを実装する
- 開発環境の効率化をするためにHotReloadとソースマップを実装する
- REST通信を実装する
- ログイン制御のフローを実装する
- デプロイ方法を検討、実装する
次の記事はこちら
http://hirooooo-lab.com/development/react-redux-routing-by-react-router/勉強するならプログラミングスクールがベスト
今からプログラミングを勉強してプロのエンジニアを目指すなら、プログラミングスクールで勉強するのがベストです!
最短4週間で未経験からプロを育てるオンラインスクールなので、自宅からプログラミングやアプリ開発を学ぶことができます。
コメント