Upload
teppei-sato
View
8.296
Download
6
Embed Size (px)
Citation preview
YOU DON'T KNOW ES Modules
@teppeis
Node #21
June 29, 2016
Hello!• Teppei Sato, @teppeis • Cybozu, Inc. / kintone
kintone.com
(Module )
https://gihyo.jp/dp/ebook/2015/978-4-7741-7477-8
History of JavaScript Modules
Module PatternExt.namespace("myNameSpace"); myNameSpace.app = function() { // private variables var privVar1 = 11;
// private functions var btn1Handler = function( button, event ) { }; // public space return { // public methods init: function() { // ... } }; }();
AMD (RequireJS)
define(['require', 'dep1', 'dep2'], function(require) { var dependency1 = require('dep1'), dependency2 = require('dep2'); return function() {}; });
CommonJS Module (CJS)
// foo.js module.exports = function() { // ... };
// main.js var foo = require('./foo');
•
•
•
•
• • ex) browserify, webpack
var moduleName = 'foo'; if (someCondition) { moduleName = 'bar'; } var module = require(moduleName);
• • Node.js
• 3rd party • • •
ES6 Modules
export/import
// export.js export default function() { return "foo"; }
// import.js import foo from "./export.js"; foo();
Awesome!•
• parse • •
• • write one, run anywhere!?
• `Module` is the new script • strict
• top level `this`: undefined • `await`: future reserved word
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
• 1 module 1 export
:
• 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"
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!
Rollup: tree shakinghttp://rollupjs.org/
MS Edge https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/
Standard and Universal
• ES Syntax
• • Node
• Write once, run anywhere!? • …
Module is the new script
Script or Module
• ES6 2
• 15.1.9 `ScriptEvaluationJob(sourceText)` • 15.2.1.16.1 `ParseModule(sourceText)`
• Script Module •
Module
• strict
• top level scope, not global scope • top level `this`: undefined • `await`: future reserved word
• top level await
• HTML comment
in Modules
// SyntaxError! (strict mode) with (obj) {}
console.log(this); // undefined
var foo = 1; // module local, not global
var await = 1; // SyntaxError! (future reserved word)
<!-- console.log() --> // SyntaxError! (HTML comment)
https://twitter.com/domenic/status/743981311568785408
ECMAScript
ECMAScript•
• module fetch •
• Loader API • • API
• • : whatwg/html
• Node.js: nodejs/node-eps • Loader API
• whatwg/loader
Loading semantics whatwg/loader
whatwg/loader• This repository consolidates work on the
ECMAScript module loading semantics with the integration points of Web browsers, as well as Node.js.https://github.com/whatwg/loader
• `<script>`
whatwg/html (#83)
• roadmap
Dynamic Loader API (reflection)
•
System.loader.import('./foo.js').then(foo => { // use foo! });
Loader pipeline (hooks)
1. resolve 2. fetch 3. translate 4. instantiate
Modules in browsers whatwg/html
whatwg/html
• PR: https://github.com/whatwg/html/pull/443
• 4.12 The elements > Scripting • script
• 8.1 Web app APIs > Scripting • fetch, parse
<script type=“module”>
External module <script type="module" src="./foo.js"></script>
Inline module <script type="module"> import fo from './foo.js'; console.log(foo()); </script>
type=“module” •
•
• •
MIME ”module” type
•
MIME
scope <script><script> var foo = 1; </script> <script type="module"> console.log(typeof foo); // undefined console.log(window.foo); // 1 var foo = 2; console.log(window.foo); // 1 console.log(foo); // 2 </script> <script type="module"> console.log(typeof foo); // undefined console.log(window.foo); // 1 var foo = 3; console.log(window.foo); // 1 console.log(foo); // 3 </script>
• import
• URL
• "/", "./", "../" URL
• TypeError!
• URL
• inline: document base • external, imported: URL
• ".js"
// OK import "https://example.com/lodash.js"; import "/lodash.js"; import "./lodash.js"; import "../lodash.js";
// NG import ".../lodash.js"; import "lodash.js"; import "lodash";
defer
•
fetch
• fetch
• DOM
async
•
fetch
•
module fetch •
<script type="module" src="./foo.js" async></script>
cors mode
• import
CORS
• CDN
// from `https://example.com/foo.html` import $ from 'https://cdn.example.com/jquery.js';
// cdn.example.com must send `Access-Control-Allow-Origin` header
crossorigin• crossorigin import cookie
(credentials mode)
• default: omit • "anonymous": same-origin • "use-credentials": include
• cookie
JS
Module Workers
• • module importScripts TypeError
// Web Worker const worker = new Worker("worker.js", {type: "module"});
// Service Worker navigator.serviceWorker.register("sw.js", {type: "module"});
• realm URL
• URL HTTP 1
• realm
<script type="module"> import './foo.js'; // sends HTTP request </script> <script type="module"> import './foo.js'; // doesn't send request </script>
• UTF-8 • meta Content-Type charset
• Content-Type JavaScript MIME Type
• Chrome/IE `X-Content-Type: nosniff`
• module export
• script src URL fetch
document insert
• Edge: https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/ • Preview
• Chrome: https://bugs.chromium.org/p/v8/issues/detail?id=1569 • Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=568953 • WebKit: https://bugs.webkit.org/show_bug.cgi?id=147340
• JSC const
Modules in Node.js nodejs/node-eps
ES6 Modules
• npm Node.js
• Node.js V8
• V8 whatwg/loader
• •
• ES Modules • • CJS Modules ES Modules
• import "cjs" • require("esm")
ES Modules
• 2 : Module or Script
• ES6 • • `<script type=module>`
• Node.js CJS Script • • require, module, exports
Module or Script?
// global scope? function foo(value) { // the arguments object is modified? value = value || ''; var args = [].slice.call(arguments); // what is `this`? args.unshift(this); return args; } foo(null);
How to detect
• New Pragma: "use module"; • New file extension: .mjs • Content sniffing • package.json
New Pragma: "use module";
• strict
`"use module”;`
• Cons • Unacceptable boilerplate tax • :
•
New file extension: .mjs• ".mjs" Module
• `import './foo'` foo.mjs, foo.js
• Cons • "*.js"
• : .jsx
• Modules .mjs
• bin •
Content sniffing
• Module
Script
• Cons • import/export •
•
package.json (a): entry point• package.json module
• type=module
• Rollup jsnext:main
{ // ... "main": "old/index.js", "module": "lib/index.js", // ... }
package.json (a): entry point• Cons
• package.json
• Module
• import ( )
import "foo/bar";
package.json (b): white list
• package.json Module
• import
{ // files and directories: "modules": ["special.js", "lib", "bin/hello.js"],
// if package never uses CJS Modules "modules": ["."], }
.mjs draft
Defense of .js
Defense of .js• https://github.com/dherman/defense-of-dot-js/ • Dave Herman, Yehuda Katz, Caridy Patiño • package.json (a)(b)
• modules.root pacakge.json
• ES Modules • .js .mjs
package.json
• interop : https://github.com/dherman/defense-of-dot-js/issues/6
Unambiguous JavaScript Grammar
Unambiguous JavaScript Grammar
• https://github.com/bmeck/UnambiguousJavaScriptGrammar • bmeck (Bradley Meck), jdalton • content sniff Module
import export
• 7 TC39 ( bmeck TC39 )
•
package.json CLI
Unambiguous, but Redundant• https://github.com/bmeck/UnambiguousJavaScriptGrammar/issues/14
<script type="module"> console.log('hello'); export {}; // Required !!! </script>
https://twitter.com/awbjs/status/743146150828482561
• ES Modules
vs.
• TC39/ Node
• Node
https://twitter.com/awbjs/status/744701901560651777
IMO• JS Module • `type=module` • Universal! Node • Unambiguous export {} Node • • import(cjs) interop
• ES Modules
• ES /
• ES Modules •
• Node.js ES Modules
• 7 TC39 meeting