#es6の基本的な開発環境を用意する
Vue.js
やReact.js
等を利用したJSの開発が広まりつつあるが、フレームワークを使わないJSの開発もありえるので、備忘録としてes6の簡易的な開発環境の構築方法についてまとめる。
##node.jsのインスール
npm
コマンドが必要になるので、node.js
をインストールする。
インストール方法については、Windows10環境ではこちら、Macの場合はこちらが参考になる。
なお、Windows10の場合、node.js
のコマンドプロンプトで、chcp 65001
を実行することで、UTF-8テキスト表示ができ、文字化けを防止できる。
##browserifyを利用した環境構築
es6に準拠した書き方で開発すると動作幅広いブラウザで動作しないため、babelifyが必要となる。また、import/export
を利用し(babelifyでrequireに書き換わるため)、複数のJSファイルを一つにまとめるにはbrowserifyが必要となる。
###browserifyとbabelifyのインスール
es6で開発するルートディレクトリで、以下のようにnpm
コマンドを実行する。
npm init
実行時はすべて質問に対して"Enter"キーのみでスキップした。
$ npm init
$ npm install -g browserify
$ npm install --save-dev babelify babel-preset-es2015
browserify
はコマンドから頻繁に利用することを想定し、グローバルインストールした。
なお、JSファイルの改行や空白を除去し、minファイルを作成する場合、uglify
もインストールする。
$ npm install -g uglify-js
###サンプル
JS側でCSVファイルを読み込んで、その内容を描画するサンプルを用意。
具体的には、csvファイルの1列目を読み込みtextareaに表示するサンプル。データがURL形式(http/https)かどうかチェックし、読み込む行数はtextareaのmaxlengthで指定された値に制限する。
####コード
以下のファイルはすべて開発環境のルートディレクトリに配置する。
JSのコードについては、可能な限りES6で追加されているシンタックス(こちらを参考にした)を利用した。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>はじめてのES6</title>
</head>
<body>
<div style="margin: 20px" class="js-csv-read">
<div style="color: red" class="js-message"></div>
現在<span class="js-csv-count"></span>件登録されています<br>
<textarea style="height: 30px" class="js-csv-data" readonly maxlength="3"></textarea>
<br>
<input type="button" class="js-csv-clear" value="クリア">
<input type="file" class="js-csv-file">
</div>
<div style="margin: 20px" class="js-csv-read">
<div style="color: red" class="js-message"></div>
現在<span class="js-csv-count"></span>件登録されています<br>
<textarea style="height: 50px" class="js-csv-data" readonly maxlength="5"></textarea>
<br>
<input type="button" class="js-csv-clear" value="クリア">
<input type="file" class="js-csv-file">
</div>
<footer>
<script type="text/javascript" src="bundle.js"></script>
</footer>
</body>
</html>
"use strict";
export default class ReadCsv {
constructor(targets) {
this.targets = targets;
this.init_();
}
init_() {
[].forEach.call(this.targets, (target) => {
const area = target.querySelector(".js-csv-data");
const count = target.querySelector(".js-csv-count");
const clear = target.querySelector(".js-csv-clear");
const csv = target.querySelector(".js-csv-file");
this.clean_(area, count)
clear.addEventListener("click", (evt) => {
this.clean_(area, count)
this.dispalyMessage_(target, "クリアしました");
});
csv.addEventListener("change", (evt) => {
evt.preventDefault();
this.readCsv_(target, evt, area, count);
});
});
}
clean_(area, count) {
area.innerHTML = "";
count.innerHTML = "0";
}
displayMessage(target, message) {
const msg = target.querySelector(".js-message");
msg.innerHTML = message
}
appendValue_(target, area, v) {
const e = document.createTextNode(v + "\n");
area.appendChild(e);
}
readCsv_(target, evt, area, count) {
const file = evt.target.files;
const reader = new FileReader();
this.clean_(area, count)
this.displayMessage(target, "");
reader.onload = (function(obj) {
const o = obj;
return function(evt) {
o.processCsv(target, evt.target.result, area, count);
};
})(this);
reader.onerror = (function(obj) {
const o = obj;
return function(evt) {
o.displayMessage(target, "ファイルの読み込みに失敗しました");
};
})(this);
reader.readAsText(file[0]);
}
processCsv(target, csv, area, count) {
const lines = csv.split(/\r\n|\n/);
const maxLen = parseInt(area.getAttribute("maxlength"), 10);
let c = parseInt(count.innerHTML, 10);
try {
lines.forEach((elm, idx) => {
const data = elm.split(",");
if (data.length > 0 && /^(https?)(:\/\/[-_.!~*'()a-zA-Z0-9;\/?:@&=+$,%#]+)$/.test(data[0])) {
if (c >= maxLen) {
throw new Error('上限に達しました');
}
this.appendValue_(target, area, data[0]);
c++;
}
});
} catch (e) {
console.log(e);
}
count.innerHTML = c;
}
}
"use strict";
import ReadCsv from "./read-csv";
class MyApp {
static exec() {
const obj = new MyApp();
obj.prepareReadCsv();
}
prepareReadCsv() {
const targets = document.querySelectorAll(".js-csv-read");
if (targets) {
const ts = new ReadCsv(targets);
}
}
}
MyApp.exec();
####ビルド
下記のコマンドを実行する。
$ browserify app.js -o bundle.js -t [ babelify --presets es2015 ]
$ uglifyjs bundle.js -c -o bundle.min.js
####デモ
#####1. index.html
にアクセス
#####2. 2つの「ファイルを選択」ボタンをそれぞれクリックし、csvファイルを渡す
csvファイルは以下を利用した。
http://hogehoge/01
ftp://hogehoge/02
http://hogehoge/03
http:/hogehoge/04
http://hogehoge/05
http://ほげほげ/06
http://hogehoge/07
http://hogehoge/08
http://hogehoge/09
##webpackを利用した環境構築
webpack
は、フロントエンドにおけるビルドツールの1つ。browserify
のように「複数ファイルを1つのjsファイルにまとめる」ことができ、パッケージ管理もできるので非常に便利。
###インストール
下記コマンドを開発環境のルートディレクトリで実行する。
npm init
を実行するといくつか質問に答える必要があるが、今回作成時はすべてリターンキーを押下し、デフォルトとした。
$ npm init
$ npm install -g webpack
###ビルド
サンブルコードは、「browserify
を利用した環境構築」と同じコードを利用。
下記を実行することでビルドができる。
webpack app.js bundle.js
Hash: 2bae931e656c8d42ecde
Version: webpack 2.5.1
Time: 72ms
Asset Size Chunks Chunk Names
bundle.webpack.js 6.05 kB 0 [emitted] main
[0] ./read-csv.js 2.69 kB {0} [built]
[1] ./app.js 364 bytes {0} [built]
ただし、これでは複数ファイルをまとめただけなので、複数ブラウザで対応できていないので、package.json
とwebpack.config.json
を編集し、babel
を利用する。
###package.jsonとwebpack.config.json
####package.json
npm init
コマンド実行後に以下のようなpackage.json
が生成されている。ここでは作業ディレクトリ名がbase
のためname
キーの値がbase
となっている。
{
"name": "base",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
####babel-loader、プリセットのインストール
下記コマンドでwebpack
をローカルインストールし、babel
をインストールする。
$ npm install --save-dev webpack babel-loader babel-core babel-preset-es2015
インストールするとpackage.json
も下記のように更新される。
{
"name": "base",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"webpack": "^3.5.5"
}
}
####webpack.config.js
webpackコマンド実行時にファイル名をwebpack.config.js
とし、ワーキングディレクトリ直下に配置すると、webpackコマンド実行時に--config
オプションでconfigファイルを指定する必要がなくなる。
なお、便宜上、出力ファイル名をapp1とした。
var webpack = require('webpack');
module.exports = {
entry: {
'app1': './app.js',
},
output: {
path: __dirname,
filename: '[name].bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
query:{
presets: ['es2015']
}
}
]
}
};
余談だが、'app1'を'output/app1'とすることで、出力ファイルを指定したディレクトに変更することができるので、entryが複数あり、それぞれ別のディレクトリに出力したいときに便利。
###もう一度ビルド
準備ができたのでもう一度ビルドしてみる。
$ webpack -p
Hash: 4417e05b925329407a30
Version: webpack 2.5.1
Time: 1813ms
Asset Size Chunks Chunk Names
app1.bundle.js 8.37 kB 0 [emitted] app1
[0] ./read-csv.js 4.15 kB {0} [built]
[1] ./app.js 1.49 kB {0} [built]
これで複数ブラウザでもJSが動作できる。
####npm runコマンド
package.json
を以下のように変更することで、npm
コマンドでもビルドできる。
{
"name": "base",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack -p"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"webpack": "^3.5.5"
}
}
変更後、下記コマンドを実行しても同じ結果となる。
$ npm run build
###pluginを導入
せっかくなのでpluginも使ってみた。今回は、UglifyJs
とBrowserSync
を利用した。
Browsersync
はファイル変更を監視し、自動でブラウザリロードを行う。
####BrowserSyncのインストール
以下を実行する
$ npm install --save-dev browser-sync browser-sync-webpack-plugin
package.json
も更新される。
####UglifyJsのインストール
この場合、グローバルではなくローカルインストール。
$ npm install --save-dev uglify-js
####webpack.config.jsとpackage.jsonの更新
webpack.config.js
とpackage.json
をそれぞれ下記のように更新する。
var webpack = require('webpack');
var BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
entry: {
'app1': './app.js',
},
output: {
path: __dirname,
filename: '[name].bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
query:{
presets: ['es2015']
}
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false }
}),
new BrowserSyncPlugin({
host: 'localhost',
port: 3000,
server: { baseDir: ['./'] } })
]
};
{
"name": "base",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack -p",
"watch": "webpack --progress --colors --watch"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"browser-sync": "^2.18.13",
"browser-sync-webpack-plugin": "^1.2.0",
"webpack": "^3.5.5"
}
}
####ビルド
$ npm run watch
上記コマンドを実行すると、自動的にブラウザ起動し、http://localhost:3000
にアクセスされて、index.html
が表示される。
http://localhost:3001
にアクセスすると以下の画面が表示されるが、browser-sync-weboack-plugin
について理解度が不足しているのでさらに研究したいと思う。
###package.json
を利用したモジュールのインストール
es6
の開発環境が既に用意されている場合、package.json
があるディレクトリ配下で下記コマンドを実行するだけで、必要なpackageがローカルインストールされるので、個別にそれぞれ必要なモジュールをインストールする必要がない。プラグインなどもインストールされる。
$ npm install
##webpack-dev-serverについて
前述したBrowserSync
があるが、webpack-dev-server
があり、こちらを利用することが多い。
対象となるファイル(contentBase
で指定したディレクトリ配下)に修正・変更等があると自動的にビルドされる。
###インストール
$ npm install --save-dev webpack-dev-server
###package.json
とwebpack.config.js
の更新
webpack.config.js
とpackage.json
をそれぞれ下記のように更新する。今回は、path
を使っている。
webpack-dev-server
のデフォルトパスは
{
"name": "base",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack -p",
"watch": "webpack --progress --colors --watch",
"dev": "webpack-dev-server"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"browser-sync": "^2.18.13",
"browser-sync-webpack-plugin": "^1.2.0",
"webpack": "^3.5.5",
"webpack-dev-server": "^2.7.1"
}
}
var webpack = require('webpack');
var BrowserSyncPlugin = require('browser-sync-webpack-plugin');
var path = require('path');
module.exports = {
entry: {
'app1': './app.js',
},
output: {
path: __dirname,
filename: '[name].bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
query:{
presets: ['es2015']
}
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false }
}),
new BrowserSyncPlugin({
host: 'localhost',
port: 3000,
server: { baseDir: [path.resolve(__dirname)] } })
],
devServer: {
contentBase: path.resolve(__dirname),
compress: true,
port: 9000
}
};
####ビルド
$ npm run dev
上記コマンドを実行すると、自動的にブラウザ起動し、http://localhost:9000
にアクセスされて、index.html
が表示される。
####備考
BrowserSync
やwebpack-dev-server
を利用する場合、コンテンツがPHPなどCGI
で動作する場合、nginx
でリバースプロキシの設定などを施す必要がある。その場合、js
が実行されているサーバのURLもCGI
側でscript
タグで指定するといったイメージ。
##yarnについて
npm
互換のパッケージマネージャにyarn
があり、rails5.1
でサポートされていたり、React
を利用する際のパッケージマネージャとしてもこちらを利用することが推奨されている。
###yarnのインストール
Mac
では下記コマンドでインストール可能。
$ brew install yarn --ignore-dependencies
###npmとyarnでの簡単なコマンド比較
npm | yarn |
---|---|
npm init | yarn init |
npm install | yarn install |
npm install --save-dev | yarn add --dev |
npm install -g | yarn global add |
npm uninstall --save-dev | yarn remove |
npm uninstall --save | yarn remove |
npm run | yarn run |
npm test | yarn test |