前回はMaterial-uiの実装を行い、デザインの変更を行いました。
今回もデザイン関連の設定になりますが、cssファイルを作成して、webpackで読み込んで反映させる方法を書きたいと思います。
複数のcssファイルが作成されたときのことを考慮して、bundle時に1つのcssにまとめて出力するようにしてみたいと思います。
- 必要なnodeモジュールをインストールする
- cssファイルを作成する
- cssファイルを反映させる
- webpack.configの修正
- 実行してみる
- buildしてみる
- まとめ
- 参考にさせていただいたサイト
- 次回予告
- 次回の記事
- 今までの記事
必要なnodeモジュールをインストールする
cssを反映させるために、以下のモジュールをインストールします。
- css-loader
- extract-text-webpack-plugin
css-loader
cssをjavascriptで読み込めるようにするローダーです。
以下のコマンドでインストールしてください。
$ npm install --save-d css-loader
extract-text-webpack-plugin
今回はcssを1つのファイルにまとめて出力するために使用しています。
その際minimizeも行おうと思います。
以下のコマンドでインストールしてください。
$ npm install --save-d extract-text-webpack-plugin
これで必要なモジュールのインストールは完了です。
最近はbundle.js内に<style>
タグとして読み込ませてしまい、cssファイルを別に出力しないようにするのが流行りですが、今回はあえてcssファイルを別で出力するようにしたいと思います。
Javascript in cssを行う場合は style-loaderを使用するとできます。
ちなみに、webpackのcss周りについては以下の記事が参考になると思います。
cssファイルを作成する
src/css/main.cssファイルを作成します。
ブラウザの規定でbodyに余分なmarginがあったりしたので、そのあたりを削除ました。
あと、スタイルとしてdiv用のセンタリングスタイルとしてcenterDiv
というスタイルを作ってみました。
html { font-size: 13px; line-height: 20px; color: #5b5b5b; min-height: 100%; position: relative; } body { margin: 0px; min-height: 100%; background-color: #FAFAFA } .centerDiv { margin: 0 auto 0 auto; display: table; }
cssファイルを反映させる
src/index.jsxの修正
index.jsxでcssファイルをインポートしておきます。
// cssインポート require('./css/main.css');
src/index.jsx
// index.jsx import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-redux'; import App from '../containers/App'; import configureStore from '../store/configureStore'; // cssインポート require('./css/main.css'); const store = configureStore(); render( <Provider store={store}> <App /> </Provider>, document.getElementById('root'), );
components/Counter.jsxの修正
Counter.jsxのカウント値が表示されるところと、ボタンのところをセンタリングさせたいと思います。
対象箇所を<div>
でくくり、作成したcssのcenterTableスタイルを当てます。
components/Counter.jsx
// components/Counter.jsx import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import Button from 'material-ui/Button'; import AddIcon from 'material-ui-icons/AddCircle'; import RemoveIcon from 'material-ui-icons/RemoveCircle'; import { withStyles } from 'material-ui/styles'; const styles = { button: { margin: 5, }, }; class Counter extends PureComponent { static propTypes = { counter: PropTypes.object.isRequired, actions: PropTypes.object.isRequired, classes: PropTypes.object.isRequired, }; render() { const { counter, actions, classes } = this.props; return ( <div style={{ width: '100%' }}> <div className="centerTable"> <h2>count={counter.value}</h2> </div> <div className="centerTable"> <Button raised color="primary" className={classes.button} onClick={actions.increment}> 増加 <AddIcon /> </Button> <Button raised color="secondary" className={classes.button} onClick={actions.decrement}> 減少 <RemoveIcon /> </Button> </div> </div> ); } } export default withStyles(styles)(Counter);
webpack.configの修正
cssを読み込めるようにloadersの追加とpluginの追加を行います。
ExtractTextPluginの追加
以下の記述を追記します。
const ExtractTextPlugin = require('extract-text-webpack-plugin'); plugins: [ new ExtractTextPlugin('css/bundle.css'), ],
css-loaderの追加
以下の記述を追記します。
module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract('css-loader?minimize') }, ],
これで、ソース上で参照しているcssが読み込まれ、bundle時にはcss/bundle.css
というファイルに纏められて出力されるようになります。
HtmlWebpackPluginも使用しているので、作成されるindex.htmlには出力されたcss/bundle.cssへのLinkタグが動的に挿入されます。
全体的にはこんな感じになりました。
webpack.config.js
const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { context: __dirname, entry: [ './src/index.jsx', ], output: { path: path.resolve(__dirname, 'dist'), publicPath: '/', filename: 'bundle.js', }, devtool: 'inline-source-map', module: { loaders: [ { test: /\.jsx?$/, enforce: 'pre', exclude: /node_modules/, loader: 'eslint-loader', }, { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel-loader'], }, { test: /\.css$/, loader: ExtractTextPlugin.extract('css-loader?minimize') }, ], }, resolve: { extensions: ['.js', '.jsx'], }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html', inject: 'body', }), new webpack.LoaderOptionsPlugin({ options: { eslint: { configFile: './.eslintrc', }, }, }), new ExtractTextPlugin('css/bundle.css'), ], };
実行してみる
ターミナルでnpm start
を打ってみてください。
$ npm start
以前の状態
↑から↓
に変更されて、センタリングされていたらcssの反映は完了です。
buildしてみる
npmスクリプトのbuildタスクを実行してみると、生成ファイルがdistディレクトリに出力されるようになっています。
以下のコマンドをターミナルから出力してみてください。
$ npm run build
distディレクトリが生成されて中に以下のファイルが作成されたと思います。
index.htmlの内容を見てみると、出力されたbundle.cssのリンクが動的に作成されているのがわかると思います。
// index.html <!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>
まとめ
これでcssの読み込みと出力については完了です。
今回はcssファイルを別出しにしましたし、cssメタ言語のsassやlessは使用しませんでした。
使用する場合でもwebpackのloaderで問題なく対応できると思います。
参考にさせていただいたサイト
次回予告
次回予告というか、あとやらなきゃいけないと思ってること
- 開発環境の効率化をするためにHotReloadとソースマップを実装する → Done!
- ESLintでAirbnbのスタイルガイドを実装する → Done!
- Materialデザインを実装する → Done!
- CSSの読み込みを実装する → Done!
- ページルーティングを実装する
- REST通信を実装する
- ログイン制御のフローを実装する
- デプロイ方法を検討、実装する
次回の記事
現在作成中です。もうしばらくお待ち下さい。