はじめに
以下の記事の 開発環境構築編 です。
Riot.js と RiotControl で Flux を実装してみる - Qiita
Webpack2 を利用して Riot.js + RiotControl の環境を構築していきます。
以下の方であれば難なく理解できる内容となっています。
- Webpack をある程度理解している方
- Migrating from v1 to v2 を読み Webpack v1 と v2 との違いを理解している方
いい感じに開発環境を構築した ( と思っている ) ので参考にしてもらえると助かります!
実際に作成したプロジェクト ( 開発環境 ) は以下にリポジトリを置いています。
kotarella1110/riot-starter at v1.0.0
開発環境構築
今回構築する開発環境は以下がベースとなっています。
準備
プロジェクトを作成します。
$ mkdir riot-starter
$ cd riot-starter
Node.js のバージョン管理ツールとして nvm をインストールしてください。
まずは、Node.js のバージョンを固定するために、バージョン番号を含む .nvmrc ファイルをプロジェクトに作成します。
※ バージョン番号は現在 ( 2016/04 ) LTS の v6.10.2 を指定しています
6.10.2
以下のコマンドにより、.nvmrc ファイルに記載されたバージョンの Node.js をインストールして使用する事ができます。
$ nvm install
$ nvm use
パッケージマネージャとして yarn
をインストールしてください。npm install -g yarn
でインストールする事ができます。
yarn
を利用して package.json ファイルを作成します。
$ yarn init -y
Riot.js
$ yarn add riot riot-route riotcontrol
riot
: シンプルで洗練されたコンポーネントベースの UI ライブラリriot-route
: シンプルなクライアント側のルータriotcontrol
: Flux のインスピレーションを受けた Riot.js のためのシンプルな Central Event Controller / Dispatcher
$ yarn add --dev riot-tag-loader riot-hot-reload
riot-tag-loader
: Riot.js のタグをトランスパイルする Webpack ローダーriot-hot-reload
: Riot.js を拡張してタグをホットリロード可能にする Api
Babel
Promise など、最新の ES の仕様を使いたい場合には、babel-polyfill
をクライアントコードに含める必要があります。
この polyfill を使うと、バンドルのサイズが増えるため、これらの機能を使いたい場合のみ追加するようにしてください。
$ yarn add --dev babel-polyfill
babel-polyfill
: Babel の polyfill
$ yarn add --dev babel-core babel-loader babel-preset-latest babel-preset-es2015-riot
babel-core
: Babel のコアパッケージbabel-loader
: JavasScript をトランスパイルする Webpack ローダーbabel-preset-latest
: JavaScript のプリセットbabel-preset-es2015-riot
: Riot.js のプリセット
.babelrc
ファイルを作成します。
babel-preset-es2015-riot
を設定しています。
{
presets: [ 'es2015-riot' ]
}
Sass
変換には3つの別々のローダーとnode-sassライブラリーが関わっています。
$ yarn add --dev style-loader css-loader sass-loader node-sass
style-loader
: ドキュメントの<style>
タグ内にCSSを出力する Webpack ローダーcss-loader
: CSS を解析して JavaScript で扱えるようにして、すべての依存オブジェクトを解決する Webpack ローダーsass-loader
: SassファイルをCSSへ変換する Webpack ローダーnode-sass
: Sass のスタイルシートプリプロセッサの C 言語バージョン LibSass を Node.js で使用できるようにしたライブラリモジュール
画像
$ yarn add --dev file-loader url-loader
file-loader
url-loader
: 画像等を取り扱う Webpack ローダー
Webpack2
$ yarn add --dev webpack webpack-dev-server webpack-merge
webpack
: JavaScript ファイルをブラウザで使用するためのバンドルや、あらゆるリソースやアセットを変換、バンドル、パッケージ化することができるモジュールバンドラwebpack-dev-server
: Webpack を使用したライブリロードを提供する開発サーバーwebpack-merge
: Webpack の config 等をマージする関数
$ yarn add --dev html-webpack-plugin clean-webpack-plugin extract-text-webpack-plugin
html-webpack-plugin
: バンドルに対応する HTML ファイルの作成を簡単にする Webpack プラグインclean-webpack-plugin
: ビルドフォルダーをビルド実行する前に削除する Webpack プラグインextract-text-webpack-plugin
: モジュールをバンドルから抽出してファイルに出力する ( Sass からコンパイルされた CSS を JavaScript バンドルファイルから抜き出し、CSSバンドルとして抽出する ) Webpack プラグイン
ディレクトリ作成
$ mkdir webpack src dist
- webpack: Webpack の config 管理用のディレクトリ
- src: コンパイル入力元のディレクトリ
- dist: コンパイル出力先のディレクトリ
config ファイル作成
異なる環境で複数の設定を念頭に置いているため、環境ごとに別々の js ファイルを作成しています。
まずは、Webpack で扱うパスを保持したオブジェクトを返す paths ファイルを作成します。
import path from 'path';
export default {
srcHtml: path.join(__dirname, '../src/index.html'),
srcJs: path.join(__dirname, '../src/index.js'),
distDir: path.join(__dirname, '../dist')
}
開発環境と本番環境に適用する共通の config ファイルを作成します。
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import CleanWebpackPlugin from 'clean-webpack-plugin';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import paths from './paths.js';
export default (env) => {
return {
entry: {
polyfills: [
'babel-polyfill'
],
main: [
paths.srcJs
]
},
output: {
path: paths.distDir,
filename: '[name].bundle.js',
// publicPath: publicPath,
sourceMapFilename: '[name].map'
},
module: {
rules: [
{ // js
test: /\.(js|tag)$/,
include: /src/,
exclude: /node_modules/,
enforce: 'post',
loader: 'babel-loader',
options: {
babelrc: false,
presets: [
[ 'latest', { modules: false } ]
]
}
},
{ // css
test: /\.css$/,
include: /src/,
exclude: /node_modules/,
enforce: 'post',
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
},
{ // sass
test: /\.(scss|sass)$/,
include: /src/,
exclude: /node_modules/,
enforce: 'post',
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
'sass-loader'
]
})
},
{ // img
test: /\.(jpg|png|gif)$/,
include: /src/,
exclude: /node_modules/,
enforce: 'post',
use: 'file-loader'
},
{ // font
test: /\.(woff|woff2|eot|ttf|svg)$/,
include: /src/,
exclude: /node_modules/,
enforce: 'post',
use: {
loader: 'url-loader',
options: {
limit: 100000
}
}
}
]
},
resolve: {
extensions: ['.js'],
},
plugins: [
new webpack.ProvidePlugin({
riot: 'riot'
}),
new HtmlWebpackPlugin({
template: paths.srcHtml,
inject: true
}),
new CleanWebpackPlugin(['*'], {
root: paths.distDir,
exclude: '.gitkeep'
}),
new ExtractTextPlugin('main.css')
]
};
}
babel-preset-latest
に ES モジュールの書き換えを無効化する事で Tree Shaking 機能を有効にして、エクスポートしたのに使われていない部分をバンドルファイルから取り除いてサイズを抑えます。
presets: [
[ 'latest', { modules: false } ]
]
開発環境のみに適用する config ファイルを作成します。
import webpack from 'webpack';
import env from '../env.js';
import paths from './paths.js';
export default () => {
return {
entry: {
vendor: [
'riot-hot-reload'
]
},
module: {
rules: [
{ // riot
test: /\.(tag)$/,
include: /src/,
exclude: /node_modules/,
enforce: 'pre',
loader: 'riot-tag-loader',
options: {
type: 'es6', // transpile the riot tags using babel
hot: true,
debug: true
}
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('development'),
}
}),
new webpack.HotModuleReplacementPlugin()
],
devtool: 'inline-source-map',
devServer: {
contentBase: paths.distDir,
host: env.devServer.host || 'localhost',
port: env.devServer.port || 8080,
open: true,
hot: true,
inline: true,
}
};
}
本番環境のみに適用する config ファイルを作成します。
import webpack from 'webpack';
export default () => {
return {
module: {
rules: [
{ // riot
test: /\.(tag)$/,
include: /src/,
exclude: /node_modules/,
enforce: 'pre',
loader: 'riot-tag-loader',
options: {
type: 'es6', // transpile the riot tags using babel
}
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: true,
drop_debugger: true
},
output: {
comments: false
}
})
]
};
}
webpack.config.babel.js ファイルを作成します。
webpack-merge
を利用して、共通の config ファイルと環境に応じた config ファイルをマージして返しています。
webpack --env=production --progress --profile --colors
と実行することで、 env.production
が true
になります。
import webpackMerge from 'webpack-merge';
import commonConfig from './webpack/common.config.js';
import devConfig from './webpack/dev.config.js';
import prodConfig from './webpack/prod.config.js';
export default (env = {}) => {
let isProd = !!env.production;
if(isProd) {
return webpackMerge(commonConfig(env), prodConfig());
}
return webpackMerge(commonConfig(env), devConfig());
}
env.example.js ファイルを作成します。
export default {
devServer: {
host: 'localhost',
port: 8080
}
};
yarn install
の後に env.example.js をコピーして env.js を作成するようにしています。
env.js ファイルで定義されたホストとポートは webpack/dev.config.js ファイルで使われます。
...
import env from '../env.js';
...
host: env.devServer.host || 'localhost',
port: env.devServer.port || 8080,
...
env.js ファイルのホストとポートを変更に応じて、webpack-dev-server
のホストとポートも変更でるようにしています。
npm-script
例えば、筆者の場合 webpack-dev-server
を起動する場合以下のようなコマンドを実行します。
webpack-dev-server --progress --colors
とても長くて覚えることができません。
以下のように、npm-script を使うことで yarn start
という短いコマンドで webpack-dev-server
を起動することができます。
+ "scripts": {
+ "postinstall": "cp env.example.js env.js",
+ "start": "webpack-dev-server --progress --colors",
+ "build": "webpack -d --progress --colors",
+ "build:prod": "webpack --env.production --progress --colors",
+ "watch": "webpack --watch --progress --colors",
+ "watch:prod": "webpack --watch --env.production --progress --colors"
+ },
postinstall
は npm install
( yarn install
) の後に実行されます。
git
空ディレクトリも管理できるように .gitkeep ファイルを作成します。
touch webpack/.gitkeep src/.gitkeep dist/.gitkeep
.gitignore を作成します。
dist 以下と env.js を git 管理対象外としています。
# Created by https://www.gitignore.io/api/osx,node,linux,windows
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
### OSX ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.gitignore.io/api/osx,node,linux,windows
/dist/*
/env.js
完成した開発環境の確認
プロジェクトのディレクトリ構造を確認してください。
.
├── dist
│ └── .gitkeep
├── src
│ └── .gitkeep
├── node_modules/
├── webpack
│ ├── .gitkeep
│ ├── common.config.js
│ ├── dev.config.js
│ ├── paths.js
│ └── prod.config.js
├── .babelrc
├── .gitignore
├── .nvmrc
├── env.example.js
├── package.json
├── webpack.config.babel.js
└── yarn.lock
package.json を確認にしてください。
{
"name": "riot-starter",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"postinstall": "cp env.example.js env.js",
"start": "webpack-dev-server --progress --colors",
"build": "webpack -d --progress --colors",
"build:prod": "webpack --env.production --progress --colors",
"watch": "webpack --watch --progress --colors",
"watch:prod": "webpack --watch --env.production --progress --colors"
},
"dependencies": {
"riot": "^3.4.3",
"riot-route": "^3.1.1",
"riotcontrol": "^0.0.3"
},
"devDependencies": {
"babel-core": "^6.24.1",
"babel-loader": "^7.0.0",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015-riot": "^1.1.0",
"babel-preset-latest": "^6.24.1",
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.0",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.11.1",
"html-webpack-plugin": "^2.28.0",
"node-sass": "^4.5.2",
"riot-hot-reload": "^0.0.2",
"riot-tag-loader": "^1.0.0",
"sass-loader": "^6.0.3",
"style-loader": "^0.16.1",
"url-loader": "^0.5.8",
"webpack": "^2.4.1",
"webpack-dev-server": "^2.4.4",
"webpack-merge": "^4.1.0"
}
}
やっと開発環境構築が完了です!
サンプルアプリを動かしてみる
開発環境整ったので、試しに Riot.js のアプリケーションを動かしてみましょう。
examples/todo-app at gh-pages · riot/examples を ES6 と Sass で書き直した riot-starter/src at v1.0.0 · kotarella1110/riot-starter を src ディレクトリ以下に格納してください。
yarn start
と実行することでブラウザが立ち上がります。
最後に
筆者が作成した開発環境に誤りがある場合はプルリクエストやコメント等でご指摘お願いします。
どうでもいい話ですが、今回 yarn
に習って初めて絵文字使ってみました!!