概要
dockerを利用してビルドツールを準備し、
Redux ExampleのTodo Listをはじめからていねいにを実行できる環境を作る。
環境
- windows10
- vagrant1.8
- virtualbox5.0
- ubuntu-16.04
- docker1.12
- docker-compose1.8
仮想環境のIPは192.168.50.10に指定。
ブラウザはfirefoxで確認。
ディレクトリ構成
redux-todo
- bin # docker-composeの操作をシェル化
- start.sh # 開発サーバの起動
- build.sh # dist内にjsファイルをビルド
- bash.sh # コンテナ内にログイン
- container_build.sh # コンテナの再作成
- remove_all_container.sh # 全てのコンテナの削除
- public # 開発サーバのベースとなるフォルダ
- index.html # 開発サーバのホーム。
- src
- app.js # エントリーポイント
- components # Reactコンポーネント
- App.js
- webpack # ビルドツール
- Dockerfile # コンテナの環境設定ファイル
- package.json # コンテナ内にコピーされるnpm設定ファイル
- webpack.config.babel.js # ビルドツールの設定
- .babelrc # ビルドツールで利用するトランスパイラの設定
+ dist # ビルドされたファイルの格納先
- docker-compose.yml # コンテナ起動時設定ファイル
ビルドツール
Webpack + babelを使用。
docker-compose.yml
# buildtoolというコンテナ名で作成
buildtool:
# webpackディレクトリ内のDockerfileビルド
build: ./webpack
# webpackを使用するディレクトリを共有する。
volumes:
# ビルドするソースファイル
- ./src:/my_webpack/src
# ビルドファイルの出力先
- ./dist:/my_webpack/dist
# 開発用サーバのホームページに使用するhtml用ディレクトリ
- ./public:/my_webpack/public
# コンテナ上のpackage.jsonを上書き
- ./webpack/package.json:/my_webpack/package.json
# webpackの設定ファイル
- ./webpack/webpack.config.babel.js:/my_webpack/webpack.config.babel.js
# babelの設定ファイル
- ./webpack/.babelrc:/my_webpack/.babelrc
# ホストのポート8080をコンテナのポート8080にポートフォワーディング
ports:
- "8080:8080" # ホスト:コンテナでポート指定
# docker-compose run を行ったときにコンテナ上で下のコマンドを行う
command: [npm, run, start]
webpack/Dockerfile
# docker-hubからnode入りコンテナを取得
# https://hub.docker.com/_/node/
FROM node:7.2.0
# コンテナ上の作業ディレクトリ作成
WORKDIR /my_webpack
# 後で確認出来るようにpackage.jsonを作成
RUN npm init -y
# ビルドツール
RUN npm i --save-dev webpack@2.1.0-beta.27
# 開発用サーバ
RUN npm i --save-dev webpack-dev-server@2.1.0-beta.12
# トランスパイラ babel
RUN npm i --save babel-polyfill
RUN npm i --save-dev babel-core
RUN npm i --save-dev babel-loader
# babelのes6用preset
RUN npm i --save-dev babel-preset-es2015
RUN npm i --save-dev babel-preset-stage-0
# babelのreact用preset
RUN npm i --save-dev babel-preset-react
# jsViewライブラリreact
RUN npm i --save react
RUN npm i --save react-dom
# jsフレームワークredux
RUN npm i --save-dev redux
RUN npm i --save react-redux
webpack/package.json
{
"name": "my_webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --display-error-details",
"start": "webpack-dev-server"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.18.2",
"babel-loader": "^6.2.8",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-0": "^6.16.0",
"redux": "^3.6.0",
"webpack": "^2.1.0-beta.27",
"webpack-dev-server": "^2.1.0-beta.12"
},
"dependencies": {
"babel-polyfill": "^6.16.0",
"react": "^15.4.1",
"react-dom": "^15.4.1",
"react-redux": "^4.4.6"
}
}
webpack/webpack.config.babel.js
import 'babel-polyfill'; // このファイルでes6の記法が使えるようにする
import path from 'path';
import webpack from 'webpack';
module.exports = {
// src以下のソースをビルド対象とする
context: __dirname + '/src',
// エントリーポイントとしてapp.jsを起点にビルドする
entry: {
javascript: './app.js'
},
// distにビルドしたファイルをbundle.jsの名前で保存
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
// importするときに、以下の配列に登録した拡張子は省略できる
resolve: {
extensions: [".js", ".jsx"]
},
module: {
rules: [
// .js, .jsxに一致する拡張子のファイルはbabel-loaderを通してトランスパイル
{ test: /\.jsx?$/,
exclude: /node_modules/,
// ビルド時に警告が出るのでcompact=falseを指定
loader: 'babel-loader?compact=false',
include: path.join(__dirname, 'src'),
}
]
},
// hot loadを有効にするためのプラグイン
plugins: [
new webpack.HotModuleReplacementPlugin()
],
// source-mapを出力して、ブラウザの開発者ツールからデバッグできるようにする。
devtool: '#cheap-module-eval-source-map',
// 開発サーバの設定
devServer: {
// public/index.htmlをデフォルトのホームとする
contentBase: './public',
inline: true,
port: 8080,
// dockerのコンテナ上でサーバを動かすときは以下の設定で全ての接続を受け入れる
host:"0.0.0.0",
// hot loadを有効にする
hot: true,
},
// vagrantの仕様でポーリングしないとファイルの変更を感知できない
watchOptions: {
aggregateTimeout: 300,
// 5秒毎にポーリング
poll: 5000
}
};
webpack/.babelrc
{
"presets": [
"react",
"es2015",
"stage-0"
]
}
開発サーバ用html
開発サーバにはwebpack-dev-serverを利用する。
public/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!-- reactのコンポーネントを#root以下に作成する設定にしている -->
<div id="root"></div>
<!-- ビルドされたbundle.jsを読み込む -->
<script src="bundle.js"></script>
</body>
</html>
Hello world
Hellor world
では、storeを作成しなくてもとりあえず動くと書いてあるが、firefoxでは動かない。
chromeなら動作する。
src/app.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todo from './reducers'
import App from './components/App'
// stateを保存するstoreを作成。
let store = createStore(todo)
render(
// providerにstoreは必須
<Provider store={store}>
<App />
</Provider>,
// reactのコンポーネントを#root以下に作成する
document.getElementById('root')
)
src/components/App.js
import React from 'react'
const App = () => (
<div>
Hello World!
</div>
)
export default App
src/actions/index.js
let nextTodoId = 0;
// actionを発行する関数
export const addTodo = (text) => {
// actionはtypeを持つオブジェクト
// この場合、アクションタイプはADD_TODO
// データはidとtextとなる。
return {
type: 'ADD_TODO',
id: nextTodoId++,
text
}
}
src/reducers/index.js
// 現在のstateとactionを受け取り、新しいstateを返す関数
const todo = (state, action) => {
switch (action.type) {
// actionTypeがADD_TODOのとき、
// { id: action.id, text: action.text }
// という新しいstateを返す
case 'ADD_TODO':
return {
id: action.id,
text: action.text
}
// それ以外のときはstateを変化させない
default:
return state
}
}
export default todo
shell
docker-composeのコマンドを毎回タイプするのが面倒なのでシェルにしている。
開発サーバの起動。
bin/start.sh
#!/bin/bash
# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
# docker-composeの起動。 docker-compsoe.ymlに記載されたcmdが実行される。
cd $bin_dir/../ && docker-compose up
webpack-dev-serverではビルドファイルは出力されない。
ビルドファイルを出力するスクリプトの起動。
bin/build.sh
#!/bin/bash
# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
# docker-composeを起動し、コンテナ内で npm run buildを実行
cd $bin_dir/../ && docker-compose run buildtool npm run build
コンテナ内の環境を確かめたい時用。
bin/bash.sh
#!/bin/bash
# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
# docker-composeの起動。 コンテナ内に入る
cd $bin_dir/../ && docker-compose run buildtool /bin/bash
コンテナを作成し直したい場合。
bin/container_build.sh
#!/bin/bash
# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
# docker-composeの起動。 docker-compsoe.ymlに記載されたcmdが実行される。
cd $bin_dir/../ && docker-compose build
コンテナが不要になった場合。
bin/remove_all_container.sh
#!/bin/bash
# 全てのdockerコンテナを止める
docker stop $(docker ps -q)
# 全てのdockerコンテナを削除
docker rm $(docker ps -aq)
実行
開発用サーバを起動。
./bin/start.sh
ブラウザでアクセスして確認。