Help us understand the problem. What is going on with this article?

React の Helloworldを docker-compose を使って webpack + babel , express, webpack-dev-serverを試したメモ

React のチュートリアルをdockerを使って実行

Hello world

webpack + express で試してみる

ディレクトリ構成は以下

webpack                     # Reactのトランスパイルを行うビルドツール
  - Dockerfile
  - package.json            # npmのモジュールを管理・スクリプトの設定
  - webpack.config.babel.js # webpackの設定ファイル。babelを利用してes6で記述可
  - .babelrc                # babelによるトランスパイルの設定ファイル
express                     # サーバー
  - Dockerfile
src
  - app.js                  # webpackのエントリポイント。このファイルをトランスパイルする。
myapp
  - views                   # ビューファイル。
    - error.jade            # express-generatorによって作成されたものを上書きする。
    - index.jade            # index.jadeがホームに表示されるhtmlファイルとなる。
    - layout.jade           # index.jadeの使用するテンプレート
dist                        # webpackによって生成されるファイル群
  - .gitignore              # gitの管理外とする
  - bundle.js               # webpackによって生成されるファイル
docker-compose.yml          # Dockerの設定ファイル

サーバー。express-generatorを使った構成。

express/Dockerfile
FROM node:7.1.0
WORKDIR /my_express
RUN npm init -y
RUN npm install express-generator -g
RUN express myapp
WORKDIR /my_express/myapp
RUN npm install body-parser --save
RUN npm install cookie-parser --save
RUN npm install debug --save
RUN npm install express@5.0.0-alpha.2 --save
RUN npm install jade --save
RUN npm install morgan --save
RUN npm install serve-favicon --save

ビルドツール。Reactをインストール。es6を使うための設定も一緒に。

install と iは同じ意味。

webpack/Dockerfile
FROM node:7.1.0
WORKDIR /my_webpack
RUN npm init -y
RUN npm i --save-dev webpack@2.1.0-beta.26
RUN npm i --save babel-polyfill
RUN npm i --save-dev babel-core 
RUN npm i --save-dev babel-loader
RUN npm i --save-dev babel-preset-es2015
RUN npm i --save-dev babel-preset-stage-0
RUN npm i --save-dev babel-preset-react
RUN npm i --save react
RUN npm i --save react-dom
CMD ["npm", "run", "build"]

重要なのは"scripts":{"build":"webpack"}。

package.jsonを設定したディレクトリでnpm installを行った後に
npm run build とすることで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"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

トランスパイルを行うbabelの設定。

.babelrc
{
  "presets": [
    "es2015",
    "stage-0",
    "react"
  ]
}
webpack.config.babel.js
import 'babel-polyfill';

module.exports = {
  entry: './src/app.js',         // app.jsをエントリポイントにしてトランスパイルする。
  output: {
    path: 'dist',                // dist/フォルダにビルドしたファイルを出力する。
    filename: 'bundle.js'        // ビルドするファイルの名前
  },
  resolve: {
    extensions: [".js", ".jsx"]  // 省略できる拡張子。
  },                             //  import h from 'hoge.js' を import h from 'hoge'のように書ける
  module: {
    loaders: [
      {test: /\.jsx?$/, loaders: ['babel-loader']}, // .js、.jsxの拡張子のファイルにbabel-loaderを利用した
    ]                                               // トランスパイルを行う
  }
};
docker-compose.yml
server:
  build: ./express
  volumes:
   - ./myapp/views:/my_express/myapp/views
   - ./dist:/my_express/myapp/public/javascripts
  ports:
    - "80:3000"
  command: [node, bin/www]

webpack:
  build: ./webpack
  volumes:
   - ./src:/my_webpack/src
   - ./dist:/my_webpack/dist
   - ./webpack/package.json:/my_webpack/package.json
   - ./webpack/webpack.config.babel.js:/my_webpack/webpack.config.babel.js
   - ./webpack/.babelrc:/my_webpack/.babelrc
  command: [npm, run, build]

Reactを使ったjsファイル。

app.js
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

トランスパイルをしたjsファイルを読み込むhtmlテンプレート。

ポイントは最後にjsファイルを読み込むこと。

headで読み込んだりするとまだdomが出来ていないので実行がうまくいかない。

index.jade
extends layout

block content
  p Welcome to #{title}
  div#root
  script(src='/javascripts/bundle.js')

dockerの設定ファイル。サーバーとビルドツール両方の設定を行う。

docker-compose.yml
server:
  build: ./express
  volumes:
   - ./myapp/views:/my_express/myapp/views
   - ./dist:/my_express/myapp/public/javascripts
  ports:
    - "80:3000"
  command: [node, bin/www]

buildtool:
  build: ./webpack
  volumes:
   - ./src:/my_webpack/src
   - ./dist:/my_webpack/dist
   - ./webpack/package.json:/my_webpack/package.json
   - ./webpack/webpack.config.babel.js:/my_webpack/webpack.config.babel.js
   - ./webpack/.babelrc:/my_webpack/.babelrc
  command: [npm, run, build]
$ docker-compose build
$ docker-compose up

ブラウザでアクセスするとHello worldが表示される。

webpack-dev-serverの使用

ホストを0.0.0.0とする設定に気が付かずに、サーバを起動しても繋がらないと2時間くらい悩んだ。

webpack.config.babel.js
import 'babel-polyfill';

// コンテナ中では/my_webpack/webpack.config.babel.jsに配置
import HtmlWebpackPlugin from 'html-webpack-plugin';

module.exports = {
  entry: './src/app.js',
  output: {
    path: 'dist',
    filename: 'bundle.js'
  },
  resolve: {
    extensions: [".js", ".jsx"]
  },
  module: {
    loaders: [
      { test: /\.jsx?$/, loaders: ['babel-loader']}
    ]
  },
// HTMLファイル作成プラグインを追加
  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.html'
    })
  ],
// ブラウザの開発ツールでソースマップを確認できるようにする
  devtool: '#cheap-module-eval-source-map',
// webpack-dev-server用の設定
  devServer: {
    contentBase: './dist', // サーバーが見に行くディレクトリ
    inline: true,          // http:localhost:8080/webpack-dev-server/ではなくhttp:localhost:8080/でアクセスできるようになる。
    port: 8080,            // ポート設定
    host:"0.0.0.0"         // ※ dockerのコンテナで立てたサーバが他のホストからアクセスできるように全てのネットワークインターフェースに接続
  }
};
FROM node:7.1.0
WORKDIR /my_webpack
RUN npm init -y
RUN npm install --save-dev webpack@2.1.0-beta.26
RUN npm i --save babel-polyfill
RUN npm i --save-dev babel-core 
RUN npm i --save-dev babel-loader
RUN npm i --save-dev babel-preset-es2015
RUN npm i --save-dev babel-preset-stage-0
RUN npm i --save-dev babel-preset-react
RUN npm i --save react
RUN npm i --save react-dom
RUN npm i --save-dev webpack-dev-server  # 追加
RUN npm i --save-dev html-webpack-plugin # 追加
src/app.js
import React from 'react';
import ReactDOM from 'react-dom';

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

ReactDOM.render(
  element,
  document.getElementById('root')
);
src/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>Document</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>

startのスクリプトを追加

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",
    "start": "webpack-dev-server"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

最後のコマンドを[npm, run, start]に変更

docker-compose.yml
devserver:
  build: ./webpack
  volumes:
   - ./src:/my_webpack/src
   - ./dist:/my_webpack/dist
   - ./webpack/package.json:/my_webpack/package.json
   - ./webpack/webpack.config.babel.js:/my_webpack/webpack.config.babel.js
   - ./webpack/.babelrc:/my_webpack/.babelrc
  ports:
    - "80:8080"
  command: [npm, run, start]
$ docker-compose build
$ docker-compose up

webpack-dev-serverのhotloaderを有効にする。

ファイルの変更を検知して、モジュール単位で置き換える。

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",
    "start": "webpack-dev-server"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

babelのauto compactが有効になっていて警告がでているので消す設定もついでに行う。

Vagrantを使用しているため、ポーリングの設定をしないとファイルの変更が検知されない。

// webpack.config.babel.js
import 'babel-polyfill';
import path from 'path';
import webpack from 'webpack'; // hotmoduleを使用するために必要

module.exports = {
  context: __dirname + '/src',
  entry: {
    javascript: './app.js',
    html: './index.html'
  },
  output: {
    path: 'dist',
    filename: 'bundle.js'
  },
  resolve: {
    extensions: ["", ".js", ".jsx"]
  },
  module: {
    loaders: [
      { test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel-loader?compact=false',
        include: path.join(__dirname, 'src'),
      },
      {
        test: /\.html$/,
        loader: 'file-loader?name=[path][name].[ext]'
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin() // hot-loaderプラグイン

  ],
  devServer: {
    contentBase: './dist',
    inline: true,
    port: 8080,
    host:"0.0.0.0",
    hot: true,  // hot-loaderの使用設定。
  },
  // vagrantの仕様で、pollingを使用しないとファイルの変更が検知できない。
  watchOptions: {
    aggregateTimeout: 300,
    poll: 5000 // 5秒ごとにファイルの更新を確認
  }
};

参考

react tutorial
Webpack + React + ES6の最小構成を考えてみる。
webpack-dev-serverの基本的な使い方とポイント
意訳
Stack over flow

hibohiboo
Javascriptが好きです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした