一部修正しました
Udemy で React コース公開してます。(絶対 Udemy の 1200 円割引価格にはしないので、このリンクから買ってもらうのが一番お互いに得です。)
Udemy React + Redux コース
本発表における Modern JavaScript とは何か
Phase 1 として以下の環境での開発ができれば Modern JavaScript に入門できたものとする。
- Webpack, Parcel 等の module bundler による "module system" の活用。
- ES2015+ や TypeScript といった *"Compile to JS 1" の使用。それに伴う Babel によるトランスコンパイルツールの使用。
- ESlint, Prettier といった集団開発における、ソース品質安定のためのツール の使用。
ここまでのツールは、生産性が大きく上がるので、全フロントエンド開発者が使用すべきだと考える。
*1 本資料における compile to JS の定義は後述
そもそもなぜ伝統的な JavaScript で書かないのか?
入門書で解説されている書き方と、実際の開発で使われている書き方は現在大きく異なる。なぜなのか?
// 入門書で学習する関数の宣言
function func1(val) {
console.log(val);
}
func1("func1 test");
// 実際の開発で散見されるアロー関数(ラムダ式)による宣言
const func2 = val => console.log(val);
func2("func2 test");
JavaScript 特有の、扱いが難しい挙動をなるべく取り除き、一般的なプログラミング言語は持っているが "JavaScript にはない" 諸機能を与えるため。
今回の開発ツールを使用しない生の JavaScript で書くことはほぼないと思っていただいていい。むしろ生の JavaScript の方が**「圧倒的に難しい」**(体感的には三倍難しい)
1. Webpack, Parcel 等の module bundler による "module system" の活用
他のプログラミング言語には当然あるが、*"JS にはない 2" module system を使用するためにバンドルツールを使用する。
// module ( = 別ファイルに切り出した JS ファイル) を読み込む
import module1 from './module1.js'
import module2 from './Module2.js'
module1();
const Object1 = new Module2()
これがないと、こうなる。依存関係を解決するために「特定の順番で」ファイルを読み込まなくてはいけない。ファイル数が膨大になると人間が管理することは不可能になり、アプリケーションは破壊される。
<html>
<head></head>
<body>
<script src="js1.js"></script>
<script src="js2.js"></script>
<script src="js3.js"></script>
<script src="js4.js"></script>
<script src="js5.js"></script>
</body>
</html>
*2 この表現は正確ではない。ここで伝えたいのは、一般的に使用されているブラウザ要件の範囲全てで問題なく動くモジュールシステムはない、ということ。
Module Bundler の比較
有名なものは以下。
- Webpack: 大規模開発案件ではほぼこれ。
- Browserify: Webpack が主流になる前に主流だった。
- Parcel: バンドルツールの複雑な設定を廃し、簡易的に使える。
- Rollup: ライブラリ開発者がよく使っている。バンドルサイズが小さいらしい。
最終的には Webpack を使うようにする。しかし、まずは Parcel でモダン開発環境を導入する。
2. Compile to JS の使用と Babel によるトランスコンパイル
Compile to JS とは
本資料では Compile to JS を次のように定義する。ブラウザでは動かない、もしくは動かない可能性のある Syntax で書かれた言語で、最終的には JavaScript にトランスコンパイルされ使用されるもの。以下はその例。
- ES2015+: JS のスタンダードな仕様だがブラウザがまだ追いついていない、おいおい採用される、検討中だが使いたいので追加された、といった syntax の総称。ほぼ JavaScript の見た目。
- TypeScript: 静的型を JavaScript に組み込むための言語。
- Elm, ReasonML とかもあります。がユーザー数からいうと上記二つがほとんど。
そもそもなぜコンパイルする必要があるのか
フロントエンドの主戦場である「ブラウザ」が実行できるのは JavaScript のみ(WebAssembly 等は一旦脇に退ける)
そのため最終的には JavaScript にするしかない。
かといって生の JavaScript にはない機能がありすぎる。
そのため、何らかの言語で書いて、最終的に JavaScript にコンパイルするしかない。
Babel でトランスコンパイルする
試しに CLI ツールでコンパイルする
npm install --save-dev babel-cli # CLI をいれる
npx babel src -d lib
# src の中身をガッとコンパイルして lib に吐き出す
Babel の設定は .babelrc というファイルに書く(ディレクトリ直下に置くのが簡易的な開発では一般的)
例えば Babel の挙動を変更するプラグインをインストールして、それを使う設定
npm install babel-preset-env --save-dev
{
"presets": ["env"]
}
Parcel を使っておけば Babel によるトランスコンパイル, Module Bundle はやってくれるのでまずは後半の演習でこれを使う。
ESlint, Prettier といった集団開発における、ソース品質安定のためのツールの使用
定番ツール
- ESLint: 不備があったり、バグに繋がりやすい syntax で書かれているものを見つけてエラーを吐くツール。そのルールもカスタマイズできる。
- Prettier: 主に JavaScript のコードを成形してくれるツール。誰が書いても、このツールを実行すればかならず同じ形にしてくれるので、楽。
Prettier を使う
npm install --save-dev --save-exact prettier # インストール
WebStorm を使っている人なら command + option + shift + p で勝手に Prettier が発動する。Atom, VSCode 等々各種エディターにプラグインがあるのでこれを使うのが良い。
設定ファイルに細々書く。
- シングルクオートを使う
- セミコロンは使わない
- 追コンマは常に使用する
{
"singleQuote": true,
"semi": false,
"trailingComma": "all"
}
するとこうなる。
const obj1 = {
name: 'name1',
age: '30', // 追いコンマ
}
演習1: Parcel で Modern JavaScript 開発環境を作る
- parcel-bundler が本体
- node-sass は sass を使う際に必要
- babel-plugin... は babel に色々なシンタックスを使用できるようにするために必要
{
"dependencies": {
"react": "^16.4.1",
"react-dom": "^16.4.1"
},
"devDependencies": {
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
"node-sass": "^4.9.3",
"parcel-bundler": "^1.9.7",
"prettier": "^1.14.2"
}
}
npm script で parcel を実行する。
"scripts": {
"start": "npm run parcel:dev",
"parcel:dev": "npx parcel src/index.html",
"parcel:build": "npx parcel build src/index.html --out-dir build"
}
src/index.html
で src/js/index.js を読み込んでいる。この js ファイル内で import されているファイルは全部うまいことバンドルしてくれる。Babel でトランスコンパイルもしてくれる。
すると次のようにモダンな JS を書く環境ができる。
import '../scss/index.scss' // sass を読み込む
import 'babel-polyfill' // async 系で必要っぽい
// import module
import module1 from './module1'
console.log(module1, 'module 1')
import React from 'react'
import ReactDOM from 'react-dom'
// react component
class HelloMessage extends React.Component {
render() {
return <div>Hello {this.props.name}</div>
}
}
// render react component
const mountNode = document.getElementById('app')
ReactDOM.render(<HelloMessage name="Jane" />, mountNode)
// async / await
const url = 'http://api.myjson.com/bins/159wqn'
const asyncFunc = async url => {
console.log(await fetch(url), 'fetch result')
}
asyncFunc(url).then(() => console.log('fetch done (in then)'))
// object rest spread
const obj1 = { value: 1 }
const obj2 = { value: 2 }
const obj3 = { test: 'hey' }
const combinedObject = { ...obj1, ...obj2, ...obj3 }
console.log(combinedObject, 'combined object')
const func1 = ({ test }) => console.log(test)
func1(combinedObject)
Phase 1 のまとめ
- Parcel で module system が使えるようになった。
- Parcel で Babel の処理をしてくれるので、ES2015+ syntax で JS を書くことができるようなった。
- Parcel が勝手に JSX も処理してくれるので React コンポーネントを JSX で書けるようになった。
- Prettier でコードが成形できるようになった。
Phase 2 の展望
JavaScript おじさんが教える本当の Modern JavaScript 入門 2 「const, immutable, functional programming
モダンなパラダイムで JavaScript を書く
- var, let を書かないで、ほぼ全部 const にする。
- そのためには functional programming に則っていく必要あり。
- map, reduce 等をうまく使う。
- immutable
Phase 3 の展望
非同期処理をモダンに書く
- Callback の根絶
- Promise の理解
- async / await を使う
- redux/vuex 関係でも async/await を使う
const url = 'http://api.myjson.com/bins/159wqn'
const asyncFetch = async url => {
const res = await fetch(url)
const { data } = res
console.log(data)
}
asyncFetch(url).then(() => console.log('done'))
Phase 4 の展望
Virtual DOM を用いた View ライブラリの活用
- ReactJS
- VueJS
- Redux/Vuex
宣伝
最後に宣伝です。Udemy で React コース公開してます。
https://www.udemy.com/react-redux-basic/?couponCode=FROM_MY_SITE
開発業務で JS, jQuery を使っている人向けのレベル感なので、全くの初心者の方には対応していません。
ただし、この記事で説明したような Modern な開発環境で仕事をしたことがない人がわかるように、一から説明しています。