Transcript
ES6 in Practice@teppeis
Firefox Dev Conf 2015 Nov 15
Hello!• Teppei Sato, @teppeis
• Cybozu, Inc. / kintone
MUST BUY!
https://gihyo.jp/dp/ebook/2015/978-4-7741-7477-8
いまES6を正しく使うために
• ES6, ES7, ECMAScriptとは
• ES6 Modules • ES6 ≠ Babel • TypeScript • Rollup • HTTP/2
ほとんどModulesの話になっちゃいました :)
ECMAScript
ES6
ECMAScript
• ざっくり言えばJavaScriptの仕様
• Ecma Internationalが標準化 (ECMA-262)
• ISOでも標準化 (ISO/IEC 16262)
• TC39 (Technical Committee) が策定
• メンバーは全ブラウザベンダーとWeb関連企業
ECMAScript 6
• 2015年6月に公開されたESの最新仕様
• ES5から6年ぶりの大幅改定!
New syntax• Arrow Function • Classes • Modules • Block Scope (let/const) • Extended Object
Literal • Default Params • Rest Params • Spread Operator
• Destructuring • Iterator • Generator • Template Literal • Tail Call Optimization
New built-in classes and objects
• Promise • Map • Set • WeakMap/WeakSet • TypedArray • Symbol • Proxy/Reflect
Improvement of existing classes
• String • RegExp • Array • Object • Math • Number
ES6 compatibility tablehttps://kangax.github.io/compat-table/es6/
ES6 or ES2015?
• 正式にはECMAScript 2015
• 来年以降、ES2016, ES2017と年次リリースされていくため(後述)
• でも、慣れ親しんでる&短いのでES6もまだまだ使われてます
ES.next
The TC39 Process: Annual• 機能単位で仕様を策定
• 各仕様提案の策定は5段階のStage
Stage 0: Strawman (idea)
Stage 1: Proposal (problem, solution and demo/polyfill)
Stage 2: Draft (initial spec)
Stage 3: Candidate (review and feedback)
Stage 4: Finished (two implementations at least)
• Stage 4を毎年ES201Xとしてリリース
Stage 0: Strawman• アイデアレベル
• GitHubにPRすれば誰でも提案可能
• Send PR to github.com/tc39/ecma-262 !
Stage 4: Finished• 仕様公開の準備完了
• 2つ環境で実装済み
ES2016?
ES2016 (ES7) はどうなる?• 2016年6月に公開予定
• 主にES6のバグ修正
• 2016年1月のTC39 Meetingの時点で Stage 4になっている提案
• Array#includes はFF, Chrome, WKで実装済み
• 他は exponential operator (**), async/await, SIMD
ES7言うな問題• ES2016(ES7)にはほとんど新機能入らない
• ES6以降の提案仕様をまとめてES7と言いがち
• ES7 Decorator, ES7 Object.observe…
• ES.nextと言おう
• ブラウザに実装されてもキャンセルされる場合も
@domenic said
specversionnumbersarebullshites6,es2015,es2016…whocares?
youshouldnot.
http://www.slideshare.net/domenicdenicola/the-state-of-javascript-2015
ES6 Modules
Good Points
• 1ファイル 1モジュール
• staticで宣言的なsyntax
• strictモード
• 循環参照に対応
Syntax
Default export/import
// export.js export default function() { return "foo"; }
// import.js import foo from "./export.js"; foo();
Named export/import
// export.js export function foo() { return "foo"; } export class Bar {} export var baz = "baz";
// import.js import {foo, Bar, baz} from "./export.js";
foo(); new Bar(); console.log(baz); // "baz"
Mixed
// export.js export default function() { return "Default"; } export function foo() { return "Named"; }
// import.js import def, {foo} from "./export.js";
def(); // "Default" foo(); // "Named"
Defaultがオススメ• ES6 ModulesはDefault Exportが最も使いやすいようにデザインされている
• Named Exportは、バインディング名を知らないとimportできない
• まずはシンプルな1module 1exportから
Static and Declarative
Staticであるメリット• 実行前にパース時点で依存関係がわかる
• 実行前に各種SyntaxErrorを投げられる
• Browserify系バンドルツールを書きやすい
• 最適化しやすい
重複したexport default
SyntaxError!
// export.js export default function() { return "foo1"; } export default function() { return "foo2"; }
存在しないモジュールをimport
SyntaxError!
// import.js import foo from "./missing-module.js";
存在しないバインディングをimport
// export.js export function foo() { return "foo"; }
// import.js import bar from "./export.js";
SyntaxError!
注意:
• default exportのプロパティとnamed exportは異なる
Default export property
// export.js export default { foo: "Default Property" }; export var foo = "Named";
// import.js import def, {foo} from "./export.js";
console.log(def.foo); // "Default Property" console.log(foo): // "Named"
Strict Mode
Script or Module• ES6では実行前にScriptかModuleか指定
• Moduleの場合:
• 強制strictモード ("use strict"; 不要)
• トップレベルthisはundefined (非window)
• トップレベル変数がグローバルにならない
Strict mode in Modules
// in module console.log(this); // undefined var foo = 1; // module local, not global
// Error! with (obj) {}
// Error! var obj = {a: 1, a: 1};
ところで
Script or Module、 どうやって指定するの?
そもそも、 ブラウザからどうやって モジュール読むんだっけ?
Node.jsからは?
モジュール名の識別子は Node/CommonJSと同じルール? 拡張子.jsは不要?
既存のCommonJSモジュールと相互運用できる?
動的にモジュールを読むときは? RequireJSみたいにフックできる?
ES6 Modules
• ES6で最も熱望された機能
• ES6で最も実装が遅れそうな機能
• 半分しか仕様が決まってない
ES6 Modules• ES6で定義
• Syntax
• Semantics
• ES6で未定義
• Loader
• Dynamic API
whatwg/loader
ブラウザでの読み込み方法(案)
<!-- external file --> <script type="module" src="./path/to/module.js"></script>
<!-- inline --> <script type="module"> import foo from "./path/to/module.js"; foo(); </script>
<!-- 従来の普通のscript要素ではmoduleを使えない -->
識別子(案)
// 相対URL import foo from "./path/to/module.js";
// 絶対URL import foo from "https://example.com/path/to/module.js";
jsc shellでES6 Modules体験• JavaScriptCoreが初期実装 (Constellation++)
• http://nightly.webkit.org/
• Download the latest binary for Mac OS
$ WebKit.app/Contents/Frameworks/10.11/ \ JavaScriptCore.framework/Versions/A/Resources/jsc \ -m ./module.js
Roadmap of Loader
https://github.com/whatwg/loader/blob/master/roadmap.md
ES6 Modules in Node.js
議論はまだ開始せず• npmはNode.js待ち
• Node.jsはV8待ち
• V8はwhatwg/loader待ち
論点: CommonJSとの相互運用• ES6 Modules importでCommonJSを読む
• CommonJS require()でES6 Modulesを読む
CommonJSはStaticに解析できない
// module.js if (someCondition) { exports.foo = "foo"; }
// import.js import foo from "./module.js";
Babel
BabelのCommonJS変換• 識別子の解釈はNode.jsと同じ
• CommonJSとの相互運用を重視強気に解釈して今動くことを優先
Babel export
// source export default {foo: 1};
// transpiled (with babel v5) Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = { foo: 1 }; module.exports = exports["default"];
Babel import
// source import foo from "./module.js" foo();
// transpiled "use strict"; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } var _moduleJs = require("./module.js"); var _moduleJs2 = _interopRequireDefault(_moduleJs); (0, _moduleJs2["default"])();
CommonJSとの相互変換
// module.js function React() {} React.Component = ... module.exports = React;
// import.js import Ract, {Component} from "react";
問題点• staticなsyntax errorが失われている
• default exportとnamed exportを併用不可
module.exportsに入れなくなった
// source export default {foo: 1};
// transpiled (with babel v6) Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = { foo: 1 }; // module.exports = exports["default"]; これが消えた
// import with CommonJS var foo = require("./foo").default; // .defaultが必要に
Babel Risk
• ES6 Modulesは仕様未決定が多い分、Babelの独自解釈成分が強い
• Babelの解釈変更やNode.js/ブラウザの正式実装で、今書いているBabel版ES6
Modulesのコードが動かなくなる可能性
@sebmck said
https://speakerdeck.com/sebmck/javascript-transformation-jsconf-2015?slide=52
TypeScript
TypeScript export
// source export default {foo: 1};
// transpired exports.__esModule = true; exports["default"] = { foo: 1 };
TypeScript import
// export.ts function foo() {return 1;} export = foo;
// import.ts import foo from "./export"; // Error!
ES6 Modules in TypeScript
• 旧形式のモジュールは旧形式でロード、ES6モジュールはES6形式でロード
• 文法が2種類あるのはスマートではないが、 相互運用の独自解釈が少ないため堅牢
• 旧形式が独自なのでES6への移行に動機
Transpilers for ES6
トランスパイラを使う理由• 生産性の高い機能を実行環境に実装される前から使いたい
• 標準化されているから(altJSとは違って)相互運用性があり将来も動作するはず
ES6 Modulesを今使う?• 標準化はまだ途中、相互運用性はツール依存、将来動作しない可能性も
• staticな文法の利点が薄い
• 結局Browserifyする
• リスクリターンをよく考慮しましょう
Rollup
Rollup
• Next-generation ES6 Module Bundler
• staticな文法を最大限活用
• 最適化で未使用のバインディングを削除
jsnext:main in package.json
{ "name": "my-package", "version": "0.1.0", "main": "dist/index.js", "jsnext:main": "src/index.js" }
https://github.com/rollup/rollup/wiki/jsnext:main
jsnext:main
• ES6コードとCommonJSコードを両方ともnpmパッケージに載せる仕組み
• staticな強みと、後方互換による資産の活用、 両方のメリットを活かせる
• Node.js/npmの未来へのヒント?
ES6 Modules with HTTP/2
生ES6 Modulesは速い?遅い?• ブラウザにES6 Modulesがネイティブに実装されたら、依存は実行時に解決される
• 非同期にリクエストを大量になげる通信コスト
HTTP/1.x では遅い• 多量のTCP接続: 多量の依存ファイル
• ラウンドトリップタイム: 深いネストした依存
• これまでのRequireJS等と同じ問題
• r.js: 本番環境用の事前ビルドツールで解決
HTTP/2で解決?• 多量のTCP接続: 多重化で解決!
• ラウンドトリップタイム: 解決できず…
ラウンドトリップタイムの解決• ただのServer Pushではキャッシュ制御に難点
• クライアントで制御: ServiceWorker
• サーバーで制御: H2O cache-aware server pusher
• 現実世界での探求はまだまだこれから!
http://teppeis.hatenablog.com/entry/2015/05/es6-modules-and-http2
Conclusion
Conclusion
• 「ES6はいまから使える」言い過ぎた :)
• ES6/ES7を正しく理解しよう
• BabelとES6の違いを正しく認識しよう
• ES6 Modulesはこれからだ!
MUST BUY!
https://gihyo.jp/dp/ebook/2015/978-4-7741-7477-8
Thanks!
top related