本発表における Modern JavaScript とは何か
Phase 1 として以下の環境での開発ができれば Modern JavaScript に入門できたものとする。
- Webpack, Parcel 等の module bunder による "module system" の活用。
- ES2015+ や TypeScript といった "Alt JS" の使用。それに伴う Babel によるトランスコンパイルツールの使用。
- ESlint, Prettier といった集団開発における、ソース品質安定のためのツール の使用。
ここまでのツールは、生産性が大きく上がるので、全フロントエンド開発者が使用すべきだと考える。
そもそもなぜ伝統的な 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 bunder による "module system" の活用
他のプログラミング言語には当然あるが、"JS にはない" 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>
Module Bundler の比較
有名なものは以下。
- Webpack: 大規模開発案件ではほぼこれ。
- Browserify: Webpack が主流になる前に主流だった。
- Parcel: バンドルツールの複雑な設定を廃し、簡易的に使える。
- Rollup: ライブラリ開発者がよく使っている。サイズが小さいらしい。
最終的には Webpack を使うようにする。しかし、まずは Parcel でモダン開発環境を導入する。
2. Alt JS の使用と Babel によるトランスコンパイル
Alt JS とは
(正確ではないかもしれないが) Alt JS とは ブラウザでは動かない、もしくは動かない可能性のある Syntax で書かれた言語で、最終的には JavaScript にトランスコンパイルされるもの。
- ES2015+: JS のスタンダードな仕様だがブラウザがまだ追いついていない、おいおい採用される、検討中だが使いたいので追加された、といった syntax の総称。ほぼ JavaScript の見た目。
- TypeScript: 静的型を JavaScript に組み込むための言語。ほぼ見た目は C? ですか? わかりません。
- 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 開発環境を作る
https://github.com/superyusuke/minumum-modern-front-end-setting
- 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 を書く
- 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