追記: webpack-serve は非推奨となり webpack-dev-server が開発再開しました。新しく始める際はスタックに webpack-serve を採用しないほうがよいでしょう。webpack-dev-server で同じような内容を書き残したのがこちら。
なんか普段開発しているフロントアプリケーションが依存しているツールスタックがそれぞれ少しずつバージョンあがっているので、手軽に環境用意するための手順を備忘録がてら書いておきます。この記事の流れで React-Router 利用時のフォールバックコンテンツ返す設定は別に書いた。
- webpack 4.x
- webpack-serve 2
- babel 7
- babel-loader 8
- react 16.4.x
- node 10.8.0, npm 6.2.0
※ babel 7, babel-loader 8 がそれぞれリリースされました。
プロジェクト初期化とパッケージのインストール
以下、適当なプロジェクトディレクトリを作成してその中で行います。
npm init -y
npm install react react-dom
npm install --save-dev webpack webpack-serve webpack-cli
npm install --save-dev @babel/preset-env @babel/cli @babel/core @babel/preset-react
npm install --save-dev babel-loader style-loader css-loader html-webpack-plugin
npm install --save-dev babel-plugin-transform-class-properties
※ babel は 6系までは babel-
って命名なので、スコープ付きパッケージを指定すると自動的に7系最新が入ります。
※ babel-plugin-transform-class-properties
は実質的に必須なのでサンプルコードでは使っていませんが入れています。
ファイルレイアウトを決める
以下のような構成にすることにします。
├── src/
│ └── index.css
│ └── index.js
│ └── index.html
├── dist/
├── package.json
├── babel.config.js
└── webpack.config.js
当初JS以外は public/
以下に静的ファイルとして置いていましたが、エントリポイントとなるHTMLは html-webpack-plugin
で出力し、CSSは style-loader
でJSに組み込む形に変えました。全部 webpack 経由でまとめた方が開発サーバでのリロードの挙動などが快適なことに気が付きました。またキャッシュバスター埋め込みなどを考えてもHTMLはwebpack管理下の方が何かと楽です。
webpack.config.js を置く
const path = require('path')
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: process.env.WEBPACK_SERVE ? 'development' : 'production',
entry: {
main: path.resolve(__dirname, './src/', "index.js")
},
output: {
path: path.resolve(__dirname, './dist/'),
publicPath: '/',
filename: '[name]-[hash].js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude:[ /node_modules/ ],
loader: 'babel-loader'
},
{
test: /\.css$/,
exclude: [/node_modules/],
use: ["style-loader", { loader: "css-loader", options: { url: false, modules: true } }]
}]
},
devtool: 'source-map',
serve: {
open: true,
port: 8080,
content: path.resolve(__dirname, 'public'),
},
plugins: [new HtmlWebpackPlugin({ template: "src/index.html" })]
}
ここでは serve.config.js をおかず webpack.config.js に webpack-serve の設定も書いています。css-loader
は options: { modules: true }
で CSS Modules サポートです。
babel.config.js を置く
module.exports = {
presets: [
"@babel/preset-env",
"@babel/preset-react"
],
plugins: ["transform-class-properties"]
}
src/index.js を作成する
import React from "react";
import { render } from "react-dom";
import "./index.css";
class App extends React.Component {
render() {
return (
<div>
<h1> Hello React!</h1>
<p> this is a component.</p>
</div>
);
}
}
render(<App />, document.getElementById("content"));
#content
要素に <App />
をマウントする簡単なコードです。
src/index.css を作成する
懐かしい感じに黒背景に白文字にします。
body {
color: #fff;
background-color: #000;
}
src/index.html を作成する
html、header、body などは省略しています。script 要素は webpack-html-plugin
が補完してくれるので、Reactの描画ターゲットとなるdiv要素一つだけを置いています。
<div id="content"/>
開発サーバで実行する
$ npx webpack-serve
サーバが 8080 番ポートで立ち上がり、ブラウザが起動すると思います。(http://0.0.0.0:8080
)
この時、環境変数 WEBPACK_SERVE
が設定されるため、webpack の mode には development が設定されます。ブラウザで開いたまま index.js
を編集すると、livereload 的に再読込が走っていることがわかります。
ビルドする
webpack コマンドでビルドを行います。
development
$ npx webpack --mode development
Hash: f368235ab2e8b186dd35
Version: webpack 4.17.1
Time: 1253ms
Built at: 2018-08-29 06:22:59
Asset Size Chunks Chunk Names
main-f368235ab2e8b186dd35.js 712 KiB main [emitted] main
main-f368235ab2e8b186dd35.js.map 820 KiB main [emitted] main
index.html 95 bytes [emitted]
Entrypoint main = main-f368235ab2e8b186dd35.js main-f368235ab2e8b186dd35.js.map
[./node_modules/css-loader/index.js?!./src/index.css] ./node_modules/css-loader??ref--5-1!./src/index.css 213 bytes {main} [built]
[./src/index.css] 1.08 KiB {main} [built]
[./src/index.js] 2.78 KiB {main} [built]
+ 24 hidden modules
Child html-webpack-plugin for "index.html":
1 asset
Entrypoint undefined = index.html
[./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html] 215 bytes {0} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 489 bytes {0} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {0} [built]
+ 1 hidden module
production
$ npx webpack --mode production
Hash: 931ddeccf4361df4a522
Version: webpack 4.17.1
Time: 1263ms
Built at: 2018-08-29 06:27:30
Asset Size Chunks Chunk Names
main-931ddeccf4361df4a522.js 107 KiB 0 [emitted] main
main-931ddeccf4361df4a522.js.map 270 KiB 0 [emitted] main
index.html 95 bytes [emitted]
Entrypoint main = main-931ddeccf4361df4a522.js main-931ddeccf4361df4a522.js.map
[6] ./src/index.js 3.11 KiB {0} [built]
[15] ./src/index.css 1.08 KiB {0} [built]
[16] ./node_modules/css-loader??ref--5-1!./src/index.css 213 bytes {0} [built]
+ 17 hidden modules
Child html-webpack-plugin for "index.html":
1 asset
Entrypoint undefined = index.html
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html 215 bytes {0} [built]
[2] (webpack)/buildin/global.js 489 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
+ 1 hidden module
約700kbから約100kbと、production ビルドにするとちゃんと minify かかっていますね。(そしてけっこう大きい)
package.json に script を追加する
します。
"scripts": {
"start": "npx webpack-serve",
"build": "npx webpack --mode production",
これで npm start
して開発サーバが立ち上がるようになりました。
まとめ
登場人物としては以下だけです。
- package.json
- webpack.config.js
- babel.config.js
- index.html
- index.js
- index.css