reactjsでアプリケーション構築した際、
production環境へのデプロイを見据えてwebpack周りの設定を見直したので
それをまとめました。
webpack.config.jsのリネーム
webpack.configでbabelなコードが書きたかったのでリネーム
あわせて、constじゃなくて、importでライブラリを読み込むように変更
リネーム & 書き換え
% mv webpack.config.js webpack.config.babel.js
// before
const webpack = require('webpack');
// after
import webpack from 'webpack';
webpack-merge
webpack.configをマージするためのモジュール。
共通設定ファイルと環境別の設定ファイルをマージするみたいな用途で利用する。
環境別でwebpack.configをかき分けたい。
手動でオブジェクトのdeep mergeするのはいやだ!みたいな人は使おう。
インストール
npm i -D webpack-merge
設定
- 共通設定:
webpack.config.babel.js
-
NODE_ENV=production
:webpack.config.prod.babel.js
-
NODE_ENV=development
:webpack.config.dev.babel.js
import merge from 'webpack-merge';
// NODE_ENVで分岐
const config = process.env.NODE_ENV === 'production' ?
require('./webpack.config.prod.babel.js') :
require('./webpack.config.dev.babel.js');
const common = {
context: __dirname,
entry: './src/index.jsx',
output: {
path: `${__dirname}/public`,
publicPath: '/',
filename: 'bundle.js',
},
module: {
preLoaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'eslint' },
],
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ['react-hot-loader/webpack', 'babel'] },
{ test: /\.css$/, loaders: ['style', 'css'] },
{ test: /\.json$/, loader: 'json' },
{ test: /\.(jpe?g|png|gif)$/, loader: 'url?limit=10000' },
],
},
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
},
eslint: {
configFile: './.eslintrc',
},
};
module.exports = merge(common, config);
npm runコマンドでwebpack呼ぶときは適宜NODE_ENVをつける。
scripts: {
start: webpack-dev-server --history-api-fallback --hot --inline --progress --colors,
build-debug: webpack --display-error-details --progress --colors,
build: NODE_ENV=production webpack --progress --colors,
},
UglifyJsPlugin などでjsを最適化・圧縮
UglifyJsPluginで圧縮して、DedupePlugin, AggressiveMergingPluginで最適化する。
詳細が知りたければこちら
list of plugins
設定
import webpack from 'webpack';
module.exports = {
debug: false,
devtool: false,
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
comments: false,
}),
new webpack.optimize.AggressiveMergingPlugin(),
],
};
html-webpack-plugin
index.htmlに直接、bundle.jsを書き込んでいたところに、
ハッシュコード付きのscriptタグを挿入したかったのでこのプラグインを導入した。
ハッシュコードってのはこういうやつね
<script src="/bundle.js?4398c4ce46af21776b47"></script>
インストール
npm i -D html-webpack-plugin
テンプレートファイルの用意
index.htmlをejsファイルにリネームし、<script src="/bundle.js" />
なコードを除去する。
mv src/index.html src/index.template.ejs
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>title</title>
</head>
<body>
<div id="root"></div>
- <script type="text/javascript" src="/bundle.js"></script></body>
</body>
</html>
設定
pluginsに下記のように設定すると、npm run build
した時にいい感じでindex.htmlを吐いてくれる。
他にもscriptとかmetaタグを<head>
に入れたくなったらマニュアル見てね。
import HtmlWebpackPlugin from 'html-webpack-plugin';
plugins: [
new HtmlWebpackPlugin({
hash: true,
filename: 'index.html',
favicon: './src/favicon.jpg',
template: './src/index.template.ejs',
inject: 'body',
}),
],
出力サンプル
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>title</title>
<link rel="shortcut icon" href="/favicon.jpg"></head>
<body>
<div id="root"></div>
<script type="text/javascript" src="/bundle.js?4398c4ce46af21776b47"></script></body>
</html>
webpack-manifest-plugin
bundle.jsって名前だとCDNに上げた時、世代管理できない。
自動生成されたファイル名にしたいってなったらこれ。
インストール
npm i -D webpack-manifest-plugin chunk-manifest-webpack-plugin
設定
下記設定だと、entryのキーが出力後のファイル名になるので注意。
hot loadしたいのでproduction環境以外は[chunkhash]
つけない。
import ManifestPlugin from 'webpack-manifest-plugin';
import ChunkManifestPlugin from 'chunk-manifest-webpack-plugin';
module.exports = {
context: __dirname,
entry: {
+ bundle: './src/index.jsx',
},
output: {
path: `${__dirname}/public`,
publicPath: '/',
- filename: 'bundle.js',
+ filename: '[name].js',
},
plugins: [
+ new ManifestPlugin(),
+ new ChunkManifestPlugin({
+ filename: 'chunk-manifest.json',
+ manifestVariable: 'webpackManifest',
+ }),
]
module.exports = {
context: __dirname,
entry: {
+ bundle: './src/index.jsx',
},
output: {
path: `${__dirname}/public`,
publicPath: '/',
- filename: 'bundle.js',
+ filename: '[name].[chunkhash].js',
},
]
npm run build
したらこういうのが出力される。
manifest.jsonも吐き出されるので、なにかと連携したければそれを読み込むといいかも。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>title</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="/bundle.b00a9f3a29b791781cc5.js?7490b7329f7ad1443141"></script></body>
</html>
copy-webpack-plugin
本番環境にデプロイして、いざ動作確認してみたら、
react-router使ってるせいで、404出ちゃったとかありませんか。
そしたら、apacheの設定ファイル置きたくなったり、sass用のリダイレクトファイルを
public配下に設置したくなりますよね。 そいういう時にこれ使いました。
例 .htaccess
, _redirects
import CopyWebpackPlugin from 'copy-webpack-plugin';
// 〜略〜
plugins: [
new CopyWebpackPlugin([
{ from: { glob: './src/static/**', dot: true }, to: '[name].[ext]' },
]),
Google Analytics
react-router使ってたら、画面遷移時にアナリティクスに取れなくなるのでこれを導入
インストール方法
npm i -S react-ga
設定
import React from 'react';
import ReactDOM from 'react-dom';
import ReactGA from 'react-ga';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import App from '../containers/App';
window.React = React;
ReactGA.initialize('UA-123456-7');
const logPageView = () => {
ReactGA.set({ page: window.location.pathname });
ReactGA.pageview(window.location.pathname);
};
ReactDOM.render((
<Router history={browserHistory} onUpdate={logPageView}>
<Route path="/">
<IndexRoute component={App} />
<Route path="/:userName" component={App} />
</Route>
</Router>
), document.getElementById('root'));
所管
あとやり残してることあるかな。気が付いたら追記する。