ja ja en en ja ja ja ja ja ja ja pl zh cs ja ja ja ja ja ja en ja ja en ja mk ja ja ja ja zh ja ja ja ja ja ja ja ja ja ja ja pl ja es ja zh ja ja ja ja ja ja ja ja cs ja ja en ja ja ja ja ja ja ja ja en ja ja ja ja ja ja ja ja id ja ja ja sv ja ja ja ja ja fr ja ja ja ja ja ja ja ja ja ja en ja en ja en en ja en ja ja en ja en ja en ja ja en ja ja ja ja ja ja fr ja en ja tr ja ja en ja en ja en ja en ja zh fr en te ja ja zh ja ja en ja en ja en ja es ja ja mk ja ja ja en ja ja ja ja sl ja ja ja ja ja ja ja ja ja ja ja ja fr ja en ja zh ja ja en ja en ja es ja ja ja ja ja es ja ja ja en nl ja en ja ja sv ja ja da ja ja nb ja ja nb ja ja ja ja ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja jbo en en ja nl nb en ko it en it it it en fr it ja ja en la fi ja it it it pt it de en ja en en it fr it en it nb it ja ja ja ja en ja ja ja ja ja ja ja ja ja
石器時代みたいなWebアプリ開発をしていたエンジニアがReact.jsに導かれて2016年にやってきた話 - Sanwa Systems Tech Blog
function App() { return  hello world! ; } ReactDOM.render( , document.getElementById('app'));
JavaScriptのコード中にHTMLのタグが出現しています。これは、
1行目で独自のAppというタグ(コンポーネントと呼びます)を定義し、
2行目でAppコンポーネントを新しく生成し、HTML側のdivタグに流し込む
という処理です。コンポーネントはいくらでも作ることができます。React.jsでは、Webアプリケーションを構成する要素をこのコンポーネントに分解し、それらを組み立てることでDOMを構築していきます。
JSX→JavaScriptの変換をしたい
JSXはFacebookの偉大なエンジニアが勝手に定義した言語ですので、ブラウザは解釈できません。したがって、JSX→素のJavaScriptへの変換を誰かが行う必要があります。
1つめの方法は手動で変換をかけるものです。オンラインの変換ツールがありますので、ここにJSXをコピペすれば通常のJavaScriptに変換してもらえます。実際にやることはないでしょうが、一度このリンクを開いておいてください。
2つめの方法は毎回動的に変換をかけるものです。HTML側で
と書いておくと(type="text/jsx"に注目しましょう)、JSXで書かれたapp.jsをその場でJSXTransformerがJavaScriptに変換してくれます。これはお手軽なのですが、当然ながらパフォーマンス上の問題が生じますし、JSXTransformerは既にdeprecatedになっています。
最後の方法は、何らかのツールでトランスパイル*1をかける方法です。
ここでちょっとnpmについて
.NETにNuGetがあるように、PHPにPEARやComposerがあるように、またRubyにgemがあるように、JavaScript*2にもnpm (Node.js Package Manager)というパッケージマネージャーがあります。多数の人々により様々なパッケージが提供されているわけですが、そのパッケージをダウンロード・インストールしてくれたり、その際に依存関係を解決してくれたり、また新しいコマンドをインストールしてくれたりする優れものです。
npmはsudo apt install npmで簡単に入ります。すみませんがAmazon LinuxなどFedora系では入れるのが地味に面倒くさいので自分で調べてください。
npmでは、まず最初にプロジェクトを作成する必要があります。空のディレクトリに対して
を実行すると、プロジェクト名などの基本情報を入力するように要求され*3、これが終わるとこのディレクトリはプロジェクトとして管理対象になります。管理対象と言っても、単に管理用ファイルpackage.jsonが新規作成されるだけです。
パッケージ取得・インストール
これができたら次のコマンドでパッケージを取得・インストールすることができます。
npm intall --save   npm intall --save-dev
ここで--saveと書いているのは、package.jsonの中に「このプロジェクトが依存するパッケージ」としてインストールしたパッケージを記録しておくことを示します。開発時にのみ必要なパッケージをインストールする際は--save-devオプションを指定します。他の人は後からpackage.jsonを見ればそのプロジェクトのために必要なパッケージが分かりますし、package.jsonだけ手元にあれば、npm installでその中に記載されたパッケージを一括でダウンロード・インストールすることができます。
さてインストールを行うと、プロジェクトのディレクトリ直下にnode_modulesディレクトリが作成され、ダウンロードしたファイル(多くの場合はJavaScriptのコード)が入ります。これらのコードは、
var hoge = require("MODULE_NAME");
などの文法で参照することができます。これについては後述します。
また、インストールと同時にnode_modules/.bin/以下に実行可能ファイルが置かれるものもあります。これはプロジェクトごとにインストールされるものですが、プロジェクトによらず、OS全体で(グローバルに)利用したいこともあるでしょう。後述のgulpなどがそれにあたります。この場合は、
sudo npm install --global
でインストールができます。OS全体に影響が及ぶのでsudoが必要なことがあります。
さて、上の方で試しに利用したオンライン変換ツールの名前はBabelとありました。そもそもBabelってなんでしょう?
Babelの名前は、(おそらく)聖書のバベルの塔の記述、「全ての地は、同じ言葉と同じ言語を用いていた」から来ています。JavaScript*4にはES5, ES2015(ES6), ES2017(ES7)といくつかのバージョンがあり、また正式採用前ながらも開発者コミュニティによく使われている文法もあり、さらにはJSXのような方言も存在します。そのサポート状況はブラウザによって異なります。先進的なバージョンの文法で書かれたJavaScriptはどれ一つとしてブラウザが対応していないことだって考えられますし、現時点ではJSXを理解できるブラウザは存在しません(これから先もないでしょう)。このようなJavaScriptを古いバージョンのJavaScriptに変換し、どのようなブラウザでも解釈できるようにしてくれるのがBabelです。「同じ言葉と同じ言語」が実現するわけですね。
Babelはオンラインで使うこともできますが、普通はコマンドとして使いたいでしょう。そこでnpmを使います。このような流れで実行します。
空のプロジェクトを作る
このプロジェクトにnpmでBabelをインストールする(babelコマンドも入る)
このプロジェクトにnpmでBabelのreactプリセット(プラグインのようなもの)をインストールする
順に実行します。まず空のディレクトリを作り、そこに空のプロジェクトを作成します。
mkdir helloworld cd helloworld npm init
次にBabelとBabelのプリセットをインストールします。
npm install --save-dev babel-cli babel-preset-react
変換が終わってしまえば稼働時には必要ないので--save-devを指定しています。これで準備は完了です。次のコマンドでJSXのファイルを読み込み、JavaScriptに変換して標準出力に吐き出します。
function App() { return  hello world! ; } ReactDOM.render( , document.getElementById('app'));
neko@ubuntu:/workdir$ node_modules/.bin/babel --presets react app.js function App() { return React.createElement( 'span', null, 'hello world!' ); } ReactDOM.render(React.createElement(App, null), document.getElementById('app'));
先ほどオンラインで試したものと同じコードが出力されました。
ES2015? ES2016???
上の方で出てきた「ES2015」「ES2016」について説明します。
まず、JavaScriptはECMAScriptという規格に沿った原語です。ECMAScriptには、
ECMAScript 5th Edition (ES5)
IE6とかのいにしえの時代はこれ準拠のJavaScriptが使われていた
ECMAScript 2015 (ES2015)
ECMAScript 2016 (ES2016)
というバージョンがあり、更新されるたびに便利な(あるいは複雑な)機能が追加されていっています。テンプレートリテラル(文字列の組み立て)などはもうES5の時代には戻れません。
var name = "neko"; // ES5 console.log("my name is " + name + "."); // ES2015 console.log(`my name is ${name}.`);
主要なブラウザが搭載しているJavaScriptエンジンはES2015に対応していますが、ES2016は新しすぎるためまったくと言っていいほど未対応です。
さて話を戻して、ここではgulpというツールを投入します。
gulpとは「ビルドシステム」で、あらかじめ定義したタスクをまとめてコマンド一発で実行してくれるツールです。たとえばJSXをJavaScriptに変換するだけではなく、ついでに圧縮とかもしたいですよね? それもコマンド一発でやって欲しいですよね? さらにはファイルの更新を監視し、それらの処理を自動で済ませたりしてほしいですよね? gulpがやってくれます。
まず、グローバルでgulp-cliをインストールします。どこのディレクトリで実行しても構いません。
sudo npm install --global gulp-cli
これでどこからでもgulpコマンドが実行できるようになりました。次に、プロジェクトのディレクトリに移動してgulpとgulpが利用するパッケージをインストールします。ここではJavaScriptのコードを圧縮するgulp-minifyを入れてみます。
npm install --save-dev gulp gulp-minify
gulpは「あらかじめ定義したタスク」を自動で行うものだと言いました。この定義はgulpfile.jsというファイルで行います。プロジェクトディレクトリの直下にgulpfile.jsを作成し、以下のように書きます。
var gulp = require('gulp'); var minify = require('gulp-minify'); gulp.task("neko", function() { gulp.src("src/*.js") .pipe(minify()) .pipe(gulp.dest("lib")); }); gulp.task("default", ["neko"]);
ここではnekoという名前のタスクを定義していて、その内容はsrcディレクトリ以下の*.jsを対象にminify()して、結果をlibディレクトリに出力するというものになっています。また、タスク名が指定されなかった場合のdefaultタスクの内容としてはnekoを使ってね、ということも書いてあります。
試しにsrc/app.jsとしてこんなJavaScriptを書いて、
// tama-san is kawaii var name = "tama"; console.log("hello, my name is " + name + " desu.");
コマンドラインでgulpとだけ実行すると(明示的にgulp nekoと実行しても構いません)、libディレクトリ(存在しなければ自動的に作成されます)にオリジナルのapp.js、圧縮済みのapp-min.jsが出力されます。中身を見てみます。
var name="tama";console.log("hello, my name is "+name+".");
確かにコメントや空白が削除されて圧縮されています。
gulp + Babel
これでgulpが何者かは分かりました。gulpからBabelを使えるようにしましょう。まずgulpが利用するパッケージをインストールします。
npm install --save-dev gulp babel-cli babelify browserify vinyl-source-stream babel-preset-react babel-preset-es2015
見知らぬ名前がたくさん出てきました。
gulp : gulp本体
babel-cli : Babel CLI
babelify : Babel
browserify : (後述)
vinyl-source-stream : gulpが利用する
babel-preset-react : BabelのReact.js用プリセット
babel-preset-es2015 : BabelのES2015用プリセット
分かってしまえばどうと言うことはありませんね!*5
gulpfile.jsの内容はこうなります。
var gulp = require("gulp"); var babelify = require("babelify"); var browserify = require("browserify"); var source = require("vinyl-source-stream"); gulp.task("neko", function() { browserify({entries: "src/app.js"}) .transform(babelify) .bundle() .on("error", function (err) { console.log("Error : " + err.message); }) .pipe(source("app.js")) .pipe(gulp.dest("./lib/")) }); gulp.task("default", ["neko"]); gulp.task("watch", function() { gulp.watch("src/*.js", ["neko"]); });
さらにプロジェクトディレクトリの直下に.babelrcというファイルを新規作成します。これはBabelの動作内容を決める設定ファイルです。ReactのJSXとES2015を使いたいのでこのように書きます。
{"presets": ["react", "es2015"]}
これで下準備が全て整いました。srcディレクトリにapp.jsを配置します。
const App = props =>  hello world!!!! ; // ES2015の新文法 ReactDOM.render( , document.getElementById('app'));
これでgulpを実行すると、libディレクトリに変換されたJavaScriptが出力されます。これを次のHTMLで読み込めば動作します。
gulpとだけ実行すると、gulpはタスクを1回だけ行って終了します。gulp watchとすると、gulpはファイルの更新を監視し、更新されたらその場その場でタスクを繰り返し実行してくれます。つまり、もう手動でコマンドを実行する必要はなくなるのです。
次に、上の項で唐突に出てきたBrowserifyの解説をします。
ここでjQuery UIのことを思い出してみましょう。ドキュメントを読むと「jQuery UIはjQueryに依存している」と書いてあります。したがって、HTMLに
のように書かないといけないのでした。このような依存関係は人間がドキュメントを読んだり書いたりして管理しないといけません。また、jQueryはグローバル変数$を利用するため、同じ変数を利用するライブラリとは同時に利用できません*6。これも利用者が気を配ってやる必要があります。
Node.jsではどうやっているか
このような牧歌的な時代は終わりました。現代のJavaScriptではこんなのどかなことを言っていてはいけません。
サーバーサイドJavaScript実行環境であるNode.jsには他モジュールのインポート機能があります。たとえばAWS APIを使いたいのであれば、まずnpmを使ってaws-sdkパッケージをインストールします。
npm install --save aws-sdk
プログラムコード中でaws-sdkをインポートするにはrequire()文を使います。
var AWS = require("aws-sdk"); // aws-sdkという名前のモジュールを読み込む var ec2 = new AWS.EC2(); ec2.startInstances(...); // EC2インスタンスを起動
ブラウザでも同じことがしたいと誰もが思います。しかし(現在の)ブラウザに許されるのは タグでHTTPリクエストを発生させてソースコードを読み込むことだけ。このような仕事はブラウザの領分を超えています。
そこでBrowserify
Browserifyは、npmと組み合わせてこのインポート構文をブラウザ用JavaScriptにも持ち込むためのツールです。このように使います。
npm install --save  で必要なパッケージをインストールする
JavaScriptのコードの中にrequire()文を書く
Browserifyを通すと、require()が消滅し、代わりに参照したパッケージが埋め込まれる
この結果、ユーザーは参照しているライブラリ(パッケージ)が全て結合された1つの大きな.jsファイルを得ます。名前空間の汚染がないような工夫も行われています。
JavaScriptで日次を任意の書式(たとえばYYYY/mm/dd HH:mmとか)で出力したいというとき、整数のフォーマットが面倒でいつも頭を悩ませていました。従来はそのためのjQueryプラグインなどに頼っていたわけです。
我々はもうjQueryと手を切ると決めたので、ここでnpmパッケージを探すとdateformatというものがあります。便利そうなので使わせてもらいましょう。インストールは簡単です。
npm install --save dateformat
あとはrequire()で読み込むだけです。
var dateFormat = require("dateformat"); // これ! var timestamp = dateFormat(new Date(), "yyyy/mm/dd HH:MM"); console.log(timestamp); // "2016/12/21 12:34"
これをgulpでビルドすると、require()部分が消えてdateformatが取り込まれ、単体で動作するJavaScriptのソースコードが出てきます。
最初の方の例では、react.js, react-dom.jsを直接CDNから読み込んでいました。これを統合してみましょう。
まず、npmでreact, react-domを追加します。
npm install --save react react-dom
次にapp.jsを修正します(上2行を追加します)。
var React = require("react"); var ReactDOM = require("react-dom"); const App = props =>  hello world!!!! ; // ES6の文法 ReactDOM.render( , document.getElementById('app'));
そしてgulpでこのapp.jsをビルドすると、生成されたlib/app.jsはライブラリを取り込んで700KBになりました*7。これならもうスクリプトは1個で済みます。
ここまで準備してしまえば、その他のライブラリを導入するのも、別のトランスパイラを利用するのもぐっと障壁が低くなります。特にJavaScriptの開発環境は異様なほど流行廃りが速いのですが、なるべく便利なものをどんどん取り入れて快適に開発を進めていきたいものです。
*1:コンパイルのようなものですが、コンパイルのようにバイナリを吐くわけではないのでこう呼ばれることがあります
*2:正確にはNode.js
*3:全てEnter空打ちでOKですが、プロジェクト名に大文字は含められないため、ディレクトリ名に大文字が入っている場合だけは手で入力する必要があります
*4:正しくはECMAScript
*5:こういうところでは気になってもとりあえず先に進み、しかし後から戻ってきてちゃんと理解するのが惑わずにいるコツです
*6:近年ではあまり名前を見なくなりましたが、prototype.jsが該当します
*7:圧縮すればもっと縮みます
nurenezumi 2016-12-21 12:06
SlackからHubotを経由してDBを参照する
こんにちは、95(くごー)です。前回の記事にも書きましたが、私…
OpenSSLコマンドでオレオレ証明書を作り、ルート認証局としてサーバー証明書を発行する
こんにちは、最近あまりWebの話をしていないwakです。IISをあれ…
Fabricを試してみた
こんにちは、おにぎりエンジニア平尾です。弊社のとあるプロダ…
Backbone.jsでToDoアプリをつくる
こんにちわ、95(くごー)です(^o^) 先週ラーメン屋に行きまして…
Electronでアプリケーションをつくる
はじめまして、今回初めて記事を書かせて頂きます95(くごー)で…
« Slackにスレッド表示機能が追加されました LINEのMessaging API WebhookをAPI Gatewa… »