상세 컨텐츠

본문 제목

자바스크립트 javascript es6,7 기능 import, export 기능 맛보기?? 브라우저 EDGE es6,7 import,export 맛보기 관련

WEB/html5

by AlrepondTech 2016. 10. 4. 11:47

본문

반응형
728x170

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


MS브라우져 edge 에서 ES6,7 모듈 import 테스트시 주소 리로드시 로드가 잘 안된다면 아래와 같이 코드를 넣어주세요~!



    <script type="text/javascript">

        window.addEventListener('load', function (e) {

            window.applicationCache.addEventListener('updateready', function (e) {

                window.location.reload();

            }, false);

        }, false);

    </script>



출처: http://d2.naver.com/helloworld/2809766


ECMAScript의 브라우저 구현

2015년 6월에 ECMAScript의 6번째 명세인 ECMAScript 2015(이하 ES6)가 발표됐고, 7번째 명세인 ECMAScript 2016(이하 ES7)이 2016년 6월에 발표됐다. 이전 일정으로 미루어 볼 때 늦지 않는다면 아마도 다음 명세인 ECMAScript 2017(이하 ES8)은 2017년 6월에는 완료돼 발표될 것으로 보인다.

그러나 새로운 명세의 발표와는 상관없이 '브라우저에서 해당 명세를 실제로 사용할 수 있는가'는 완전히 다른 말이다. 아직까지도 많은 브라우저가 ES6을 온전하게 지원하지 않는 상태라 Babel이나 Traceur와 같은 트랜스파일러를 사용해 하위 버전인 ECMAScript 5(이하 ES5)로 변환하는 과정을 거쳐야 ES6을 사용할 수 있다.

ECMAScript 2015의 브라우저 구현

다음은 ES6 호환성 테이블(ECMAScript 6 compatibility table)의 일부다.

구현표 테이블: http://kangax.github.io/compat-table/es6/


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


출처: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import



This article needs an editorial review. How you can help.

The import statement is used to import functions, objects or primitives that have been exported from an external module, another script, etc.

Note: This feature is not implemented in any browsers natively at this time. It is implemented in many transpilers, such as the Traceur CompilerBabel or Rollup.

Syntax

import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name";
name
Name of the object that will receive the imported values.
member, memberN
Name of the exported members to be imported.
defaultMember
Name of the object that will  receive the default export from the module.
alias, aliasN
Name of the object that will receive the imported property
module-name
The name of the module to import. This is a file name.

Description

The name parameter is the name of the object that will receive the exported members. The member parameters specify individual members, while the name parameter imports all of them. name may also be a function if the module exports a single default parameter rather than a series of members. Below are examples to clarify the syntax.

Import an entire module's contents. This inserts myModule into the current scope, containing all the exported bindings from "my-module.js".

import * as myModule from "my-module";

Import a single member of a module. This inserts myMember into the current scope.

import {myMember} from "my-module";

Import multiple members of a module. This inserts both foo and bar into the current scope.

import {foo, bar} from "my-module";

Import a member with a more convenient alias. This inserts shortName into the current scope.

import {reallyReallyLongModuleMemberName as shortName} from "my-module";

Import multiple members of a module with convenient aliases.

import {reallyReallyLongModuleMemberName as shortName, anotherLongModuleName as short} from "my-module";

Import an entire module for side effects only, without importing any bindings.

import "my-module";

Importing defaults

It is possible to have default export (whether it is an object, a function, a class, etc.). Reciprocally, it is possible to use the import instruction to import such defaults.

The simplest version directly imports the default:

import myDefault from "my-module";

It is also possible to use the default syntax with the ones seen above (namespace imports or named imports). In such cases, the default import will have to be declared first. For instance:

import myDefault, * as myModule from "my-module";
// myModule used as a namespace

or

import myDefault, {foo, bar} from "my-module";
// specific, named imports

Examples

Importing a secondary file to assist in processing an AJAX JSON request.

// --file.js--
function getJSON(url, callback) {
  let xhr = new XMLHttpRequest();
  xhr.onload = function () { 
    callback(this.responseText) 
  };
  xhr.open("GET", url, true);
  xhr.send();
}

export function getUsefulContents(url, callback) {
  getJSON(url, data => callback(JSON.parse(data)));
}

// --main.js--
import { getUsefulContents } from "file";
getUsefulContents("http://www.example.com", data => {
  doSomethingUseful(data);
});

Specifications

SpecificationStatusComment
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Imports' in that specification.
StandardInitial definition.
ECMAScript 2017 Draft (ECMA-262)
The definition of 'Imports' in that specification.
Draft 

Browser compatibility

FeatureChromeFirefox (Gecko)Internet ExplorerEdgeOperaSafari
Basic supportNo support[2]No support[1]No supportBuild 14342 No supportNo support

Edge 브라우져 익스플로어 엣지에 빌드 14342 로 적혀 있다, 기능을 사용가능하다는 애기?!


[1] See bug 568953.

[2] See Chromium bug 1569

See also

Document Tags and Contributors




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


출처: https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/#DMPtgKHOiptM7rgb.97



Chakra, the recently open-sourced JavaScript engine that powers Microsoft Edge and Universal Windows applications, has been pushing the leading edge of ECMAScript language support.  Most of ES2015 (aka ES6) language support is already available in Edge, and last week’s Windows Insider Preview build 14342 brings more ES6 capabilities including modules, default parameters, and destructuring. We’re not stopping there – Edge also supports all ES2016 (aka ES7) proposals – the exponentiation operator and Array.prototype.includes – as well as future ECMAScript proposals such as Async Functions and utility methods like Object.values/entries and String.prototype.padStart/padEnd.

ES6 Modules

Modules let you write componentized and sharable code. Without complete support from any browser, developers have already started to get a taste of ES6 modules through transpiling from tools such as TypeScript or Babel. Edge now has early support for ES6 modules behind an experimental flag.

Modules aren’t exactly new to JavaScript with formats such as Asynchronous Module Definition (AMD) and CommonJS predating ES6. The key value of having modules built in to the language is that JavaScript developers can easily consume or publish modular code under one unified module ecosystem that spans both client and server. ES6 modules feature a straightforward and imperative-style syntax, and also have a static structure that paves the way for performance optimizations and other benefits such as circular dependency support. There are times when modules need to be loaded dynamically, for example some modules might only be useful and thus loaded if certain conditions are met in execution time. For such cases, there will be a module loader which is still under discussion in the standardization committee and will be specified/ratified in the future.

ES6 Modules in Microsoft Edge

To light up ES6 modules and other experimental JavaScript features in Edge, you can navigate to about:flags and select the “Enable experimental JavaScript features” flag.

image: https://winblogs.azureedge.net/win/2015/09/experimentalflag.png




The “Experimental JavaScript features” flag at about:flags

As a first step, Edge and Chakra now support all declarative import/export syntax defined in ES6 with the exception of namespace import/export (import * as name from “module-name” and export * from “module-name”). To load modules in a page, you can use the <script type=”module”> tag. Here is an example of using a math module:

/* index.html */

...

<script type='module' src='./app.js'>

...



/* app.js */

import { sum } from './math.js';

console.log(sum(1, 2));

 

/* math.js */

export function sum(a, b) { return a + b; }

export function mult(a, b) { return a * b; }


Read more at https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/#dMlJQl6H8UKBgrH3.99




Implementation: static modules = faster lookup

One of the best aspects of ES6’s modules design is that all import and export declarations are static. The spec syntactically restricts all declarations to the global scope in the module body (no imports/exports in if-statement, nested function, eval, etc.), so all module imports and exports can be determined during parsing and will not change in execution.

From an implementation perspective, Chakra takes advantage of the static nature in several ways, but the key benefit is to optimize looking up values of import and export binding identifiers. In Microsoft Edge, after parsing the modules, Chakra knows exactly how many exports a module declares and what they are all named, Chakra can allocate the physical storage for the exports before execution. For an import, Chakra resolves the import name and create a link back to the export it refers to. The fact that Chakra is aware of the exact physical storage location for imports and exports allows it to store the location in bytecode and skip dynamically looking up the export name in execution. Chakra can bypass much of the normal property lookup and cache mechanisms and instead directly fetch the stored location to access imports or exports. The end result is that working with an imported object is faster than looking up properties in ordinary objects.

Going forward with modules

We have taken an exciting first step to support ES6 modules. As the experimental status suggests, the work towards turning ES6 modules on by default in Edge is not fully done yet. Module debugging in the F12 Developer Tools is currently supported in internal builds and will be available for public preview soon. Our team is also working on namespace import/export to have the declarative syntax fully supported and will look into module loader once its specification stabilizes. We also plan to add new JSRT APIs to support modules for Chakra embedders outside of Edge.

More ES6 Language Features

Microsoft Edge has led the way on a number of ES6 features. Chakra has most of ES6 implemented and on by default including the new syntax like let and const, classes, arrow functions, destructuring, rest and spread parameters, template literals, and generators as well as all the new built-in types including Map, Set, Promise, Symbol, and the various typed arrays.

In current preview builds, there are two areas of ES6 that are not enabled by default – well-known symbols and Proper Tail Calls. Well-known symbols need to be performance optimized before Chakra can enable them – we look forward to delivering this support in an upcoming Insider flight later this year.

The future of Proper Tail Calls, on the other hand, is somewhat in doubt – PTC requires a complex implementation which may result in performance and standards regressions in other areas. We’re continuing to evaluate this specification based on our own implementation work and ongoing discussions at TC39.

ES2016 & Beyond with the New TC39 Process

TC39, the standards body that works on the ECMAScript language, has a new GitHub-driven process and yearly release cadence. This new process has been an amazing improvement so far for a number of reasons, but the biggest is that it makes it easier for implementations to begin work early for pieces of a specification that are stable and specifications are themselves much smaller. As such, Chakra got an early start on ES2016 and are now shipping a complete ES2016 implementation. ES2016 was finalized (though not ratified) recently and includes two new features: the exponentiation operator and Array.prototype.includes.

The exponentiation operator is a nice syntax for doing `Math.pow` and it uses the familiar `**` syntax as used in a number of other languages. For example, a polynomial can be written like:

let result = 5 * x ** 2 – 2 * x + 5;
Read more at https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/#dMlJQl6H8UKBgrH3.99
1
let result = 5 * x ** 2 – 2 * x + 5;

Certainly a nice improvement over Math.pow, especially when more terms are present.

Chakra also supports Array.prototype.includes which is a nice ergonomic improvement over the existing Array.prototype.indexOf method. Includes returns `true` or `false` rather than an index which makes usage in Boolean contexts lots easier. `includes` also handles NaN properly, finally allowing an easy way to detect if NaN is present in an array.

Meanwhile, the ES2017 specification is already shaping up and Chakra has a good start on some of those features as well, namely Object.values and entriesString.prototype.padStart and padEnd, and SIMD. We’ve blogged about SIMD in the past, though recently Chakra has made progress in making SIMD available outside of asm.js. With the exception of Object.values and entries, these features are only available with experimental JavaScript features flag enabled.

Object.values & Object.entries are very handy partners to Object.keys. Object.keys gets you an array of keys of an object, while Object.values gives you the values and Object.entries gives you the key-value pairs. The following should illustrate the differences nicely:





let obj = { a: 1, b: 2 };

Object.keys(obj);

// [ 'a', 'b' ]

Object.values(obj);

// [1, 2]

Object.entries(obj);

// [ ['a', 1], ['b', 2] ]


Read more at https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/#dMlJQl6H8UKBgrH3.99

1
2
3
4
5
6
7
let obj = { a: 1, b: 2 };
Object.keys(obj);
// [ 'a', 'b' ]
Object.values(obj);
// [1, 2]
Object.entries(obj);
// [ ['a', 1], ['b', 2] ]

String.prototype.padStart and String.prototype.padEnd are two simple string methods to pad out the left or right side of a string with spaces or other characters. Not having these built-in has had some rather dire consequences recently as a module implementing a similar capability was removed from NPM. Having these simple string padding APIs available in the standard library and avoiding the additional dependency (or bugs) will be very helpful to a lot of developers.

Chakra is also previewing SIMD, with the entire API surface area in the stage 3 SIMD proposal completed, as well as a fully-optimized SIMD implementation integrated with asm.js. We are eager to hear feedback from you on how useful these APIs are for your programs.

You can try ES2015 modules and other new ES2015, ES2016, and beyond features in Microsoft Edge, starting with the latest Windows Insider Preview and share your thoughts and feedback with us on Twitter at @MSEdgeDev and @ChakraCore or file an issue on the ChakraCore GitHub. We look forward to hearing your input!

― Taylor Woll, Software Engineer
― Limin Zhu, Program Manager
― Brian Terlson, Program Manager

UPDATED MAY 18, 2016 8:36 AM


Read more at https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/#eIVHC6JjCXjfxbkJ.99



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


출처: http://browser.hatenablog.com/entry/2016/05/22/220131



現状、実装途中ですが調べたついでに書き留めています。

 

まずは注意点

実装途中ですので動かないものがあります。

 

その1

どうやら、名前からの呼び出しとデフォルトメンバーからの呼び出しをまだできません。
仕様上、以下の import が使えますが、動くのは赤文字のものだけです。

import name from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as alias from "module-name";
import defaultMember from "module-name";
import "module-name";

 

その2

import の際に相対のパスの場合 "./" を付けないと import できません。

import { sum } from "math.js"; // 動かない

 

その3

import の際、モジュール名の".js" を省くと動作しません。

import { sum } from "./math"; // 動かない

 

 

Modules とは?

JavaScript から他の JavaScript の指定しているプロパティ、関数、オブジェクトを呼び出すことができます。

 

使い方

以下の3つを行うと使用できます。

  • 使用する場合、読み込む script タグに type="module" の属性を追加
  • 読み込む方は import で呼び出し
  • 呼び出し側は読み込むプロパティ、関数、オブジェクトに export をつける

 

下準備

アドレスバーに about:flags を入力し、JavaScript の項目の「試験的な JavaScript 機能を有効にする」にチェックを入れ有効にしてください。

また、Insider Preview Build 14342 で使用できます。
(Mobile でも使えます)

 

使ってみる

math.js の足し算をする関数を import してを alert 関数で表示させます。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Modules</title>
    <script type="module" src="app.js"></script>
</head>
<body>
</body>
</html>

app.js

import { sum } from "./math.js";
alert(sum(1, 2));

math.js

export function sum(a, b) { return a + b; }
export function mul(a, b) { return a * b; }

 

複数の export を呼び出す

export で設定したものは、明示的に指定しないと呼び出すことができません。

app.js

import { sum, mul } from "./math.js";
alert(sum(1, 2));
alert(mul(4, 2));

 

別名で export を呼び出す

app.js と math.js でプロパティ、関数、オブジェクトなどが被ってしまうとエラーが出ます。
そのため、回避するために sum の後に "as 別名" を付け別名で呼び出します。

app.js

import { sum as SUM } from "./math.js";
alert(SUM(1, 2));

 

仕様? バグ?

確か明確には記載されていなかった気がしますが、import する JS のプロパティ、関数、オブジェクトに export がないと import 側でそのまま読み込めてしまします。
alert() など即実行すものを書くと、import した時点で実行されるようです。


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



출처: http://www.atmarkit.co.jp/ait/articles/1606/28/news029.html



 JavaScriptのソースコードに別のソースコードを取り込みたいと思ったことはないだろうか? 例えば、JavaScriptのソースコードを複数のファイルに分けたいのだが、HTMLの<script>タグで指定するJavaScriptのファイルは1つだけにしておきたいといった場合だ。jQueryを使えば、それが簡単にできる。

 本稿では、jQueryを使ってソースコードを取り込む方法を解説するとともに、JavaScriptの新しい機能による方法も紹介する。

jQueryを使って別ソースをインポートするには?

 jQueryのajaxメソッドを使えばよい。

 同期的に取り込むには、次のコードのようにajaxメソッドを使う(本稿では紹介しないが、非同期処理でよければgetScriptメソッドの方が簡潔に書ける)。

$(window).load(function(){
  "use strict";

  // jQueryを使ってWebサーバからJavaScriptファイルを読み込む
  $.ajax({
    url: "./sample01.js",  // JavaScriptファイルのURL(内容は後述)
    dataType: "script",
    async: false, // 同期処理にする
  })
  // 成功時の処理
  .done(function (script, textStatus) {
    // 本来は、非同期処理にして、取り込んだ関数をここで使うことが望ましい
    console.log("done: " + textStatus);
  })
  // 失敗時の処理
  .fail(function (jqxhr, settings, exception) {
    console.log("fail: " + jqxhr.status + ", " + exception);
  })
  // 終了時の処理(成功/失敗にかかわらず実行される)
  .always(function (script, textStatus, exception) {
    console.log("always: " + textStatus);
  });

  // 同期処理を指定しているので、成功時にここへきたときには、
  // sample01.jsファイル内の関数が使えるようになっている
  console.log("getTime(): " + getTime());
  // 出力例⇒getTime():18:57
  console.log("func1(3): " + func1(3));
  // 出力⇒func1(3):これはfunc1です。値は3
})

jQueryを使ってソースコードを取り込む例(JavaScript)
取り込んでいるソースコード「sample01.js」ファイルの内容は、後に記載する。getTime関数とfunc1関数は、「sample01.js」ファイルに記述してある。
ajaxメソッドのdataType引数に"script"を指定すると、JavaScriptファイルを読み込んで、それに含まれている関数を使えるようにしてくれる。
async引数をfalseに設定すると、同期的に処理してくれる(既定値はtrue)。コメントにあるように、できれば非同期的に処理して、doneメソッド内で取り込んだ関数を使うようにする方がよい。

 なお、上の例で取り込んでいる「sample01.js」ファイルの内容は、次のようなものだ。ごく普通なJavaScriptのソースコ―ドである。

// 関数宣言(function文)
function getTime() {
  "use strict";

  // 現在時刻
  var now = new Date();
  // 時分秒に分割し、それぞれ2桁の文字列(先頭ゼロ埋め)にする
  var hh = ('0' + now.getHours()).toString().slice(-2);
  var mm = ('0' + now.getMinutes()).toString().slice(-2);
  // HH:mmという書式で現在時刻を返す
  return hh + ":" + mm;
}

// 関数式(function演算子)
var func1 = function (n) {
  "use strict";
  return "これはfunc1です。値は" + n;
}

上のコードで取り込んでいる「sample01.js」ファイルの内容(JavaScript)
ごく普通にJavaScriptの関数が記述してあるだけだ。

JavaScriptのmodule機能を使って別ソースをインポートするには?

 以上のようにjQueryのajaxメソッドを使えば別ソースを取り込めるのだが、ちょっと面倒ではある。ところが、ECMAScript 2015のmodule機能がWebブラウザで使えるようになると、もっと簡潔に実現できるようになる。

 このmoduleとは、ECMAScript 2015仕様で定められている機能だ。ただし、本稿執筆時点では、メジャーなWebブラウザでこれを正式にサポートしているものはなく、一部で試験的なサポートが始まった段階である。ここではWindows 10 Insider Previewに搭載されているEdgeブラウザの試験的な実装を紹介しよう*1

*1 Windows 10 Insider Preview Build 14342のEdgeから実装された。ただし、本稿執筆時点では既定では無効になっている。有効にするには、アドレスバーに「about:flags」と入力し、[試験的な JavaScript 機能を有効にする]チェックボックスにチェックを付けてから、Edgeを再起動する。

 まず、JavaScriptのファイルをmoduleとして扱うには、HTMLの<script>タグでtype属性に「module」と指定してWebページに取り込む(次のコード)。

<!-- 従来の取り込み方 -->
<!-- script type="text/javascript" src="./importSample.js"></script -->

<!-- moduleとして取り込む方法 -->
<script type="module" src="./importSample.js" ></script>

JavaScriptファイルをmoduleとしてWebページに取り込む(HTML)
現在は、<script>タグを利用し、type属性に「module」と指定する。将来は専用のタグが作られるかもしれない。

 moduleの中では、import/export文が利用できる。上で示した「importSample.js」ファイルの中で、別のファイル(後述する「sample02.js」ファイル)から関数と定数をインポートして使うコードは次のようになる。

// ファイル:importSample.js

// sample02.jsに定義されている関数squareと定数piをインポート
import { square , pi, } from "/sample02.js";
// 別名を付けることも可能(この場合は、square関数を「sq」という名前で利用する)
//import { square as sq, pi, } from '/sample02.js';

// 円の面積を求める(インポートした関数squareと定数piを使う)
function getAreaOfCircle(radius) {
  return square(radius) * pi;
}

import文で別のファイルから関数と定数をインポートするコードの例(JavaScript)
import文は、ECMAScript 2015仕様で定められている機能だ。
このようにして、他のmoduleでエクスポートされている関数や定数などを取り込める。import文の書き方には、この他に、エクスポートされているものを全て取り込む方法などがあるが、本稿執筆時点でEdgeが対応しているのはこの書き方だけのようである。

 上でインポートしている「sample02.js」ファイルは、次のコードのようになる。export文を使って明示的にエクスポートする。

// ファイル:sample02.js

// 定数piをエクスポート
export const pi = Math.PI;

// 関数squareをエクスポート
export function square(x) {
  return x * x;
}

export文で関数と定数をエクスポートするコードの例(JavaScript)
export文は、ECMAScript 2015仕様で定められている機能だ。
このようにしてエクスポートしたものだけが、他のmoduleでインポートできる。
この他に、default exportというものもある。これは無名関数などをmoduleで1つだけエクスポートする機能だ(本稿執筆時点のEdgeでは未対応のようだ)。

 最後に、WebページのJavaScriptからgetAreaOfCircle関数を呼び出す(次のコード)。

  <script type="module" src="./importSample.js" ></script>
  <!-- 上の<script>タグについては前述した -->

  <script type="text/javascript">
$(window).load(function(){
  "use strict";

  console.log(getAreaOfCircle(2.0));
  // 出力⇒12.5663706143592
})
  </script>

moduleに含まれる関数をWebページから呼び出すコードの例(JavaScript)
WebページのJavaScriptからmoduleに含まれる関数を呼び出すコードは、従来通りだ。ただし、前述したように、moduleファイルを取り込む<script>タグのtype属性には「module」と指定する。

まとめ

 jQueryのajaxメソッドを使うと、別のファイルに記述されたJavaScriptを読み込んで、そこに定義された関数などを呼び出せる。ただし、将来的にはJavaScriptのimport/export文を使って、より簡潔に記述できるようになる予定だ。

カテゴリ:JavaScript 処理対象:言語構文
カテゴリ:JavaScript 処理対象:ファイルダウンロード
カテゴリ:オープンソース・ライブラリ 処理対象:JavaScript
使用ライブラリ:jQuery
関連TIPS:Ajax(非同期通信)を実装するには?[JavaScript/jQuery]
関連TIPS:strictモードとは?[JavaScript]


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


출처: https://jakearchibald.com/2017/es-modules-in-browsers/



ES modules are starting to land in browsers! They're in…

  • Safari 10.1.
  • Chrome Canary 60 – behind the Experimental Web Platform flag in chrome:flags.
  • Firefox 54 – behind the dom.moduleScripts.enabled setting in about:config.
  • Edge 15 – behind the Experimental JavaScript Features setting in about:flags.
<script type="module">
  import {addTextToBody} from './utils.js';

  addTextToBody('Modules are pretty cool.');
</script>
// utils.js
export function addTextToBody(text) {
  const div = document.createElement('div');
  div.textContent = text;
  document.body.appendChild(div);
}

Live demo.

All you need is type=module on the script element, and the browser will treat the inline or external script as an ECMAScript module.

There are already some great articles on modules, but I wanted to share a few browser-specific things I'd learned while testing & reading the spec:

"Bare" import specifiers aren't currently supported

// Supported:
import {foo} from 'https://jakearchibald.com/utils/bar.js';
import {foo} from '/utils/bar.js';
import {foo} from './bar.js';
import {foo} from '../bar.js';

// Not supported:
import {foo} from 'bar.js';
import {foo} from 'utils/bar.js';

Valid module specifiers must match one of the following:

  • A full non-relative URL. As in, it doesn't throw an error when put through new URL(moduleSpecifier).
  • Starts with /.
  • Starts with ./.
  • Starts with ../.

Other specifiers are reserved for future-use, such as importing built-in modules.

nomodule for backwards compatibility

<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>

Live demo.

Browsers that understand type=module should ignore scripts with a nomoduleattribute. This means you can serve a module tree to module-supporting browsers while providing a fall-back to other browsers.

Browser issues

  • Firefox doesn't support nomodule (issue). Fixed in Firefox nightly!
  • Edge doesn't support nomodule (issue).
  • Safari 10.1 doesn't support nomodule, but it's fixed in their latest technical preview. For 10.1, there's a pretty smart workaround.

Defer by default

<!-- This script will execute after… -->
<script type="module" src="1.js"></script>

<!-- …this script… -->
<script src="2.js"></script>

<!-- …but before this script. -->
<script defer src="3.js"></script>

Live demo. The order should be 2.js1.js3.js.

The way scripts block the HTML parser during fetching is baaaad. With regular scripts you can use defer to prevent blocking, which also delays script execution until the document has finished parsing, and maintains execution order with other deferred scripts. Module scripts behave like defer by default – there's no way to make a module script block the HTML parser while it fetches.

Module scripts use the same execution queue as regular scripts using defer.

Inline scripts are also deferred

<!-- This script will execute after… -->
<script type="module">
  addTextToBody("Inline module executed");
</script>

<!-- …this script… -->
<script src="1.js"></script>

<!-- …and this script… -->
<script defer>
  addTextToBody("Inline script executed");
</script>

<!-- …but before this script. -->
<script defer src="2.js"></script>

Live demo. The order should be 1.js, inline script, inline module, 2.js.

Regular inline scripts ignore defer whereas inline module scripts are always deferred, whether they import anything or not.

Async works on external & inline modules

<!-- This executes as soon as its imports have fetched -->
<script async type="module">
  import {addTextToBody} from './utils.js';

  addTextToBody('Inline module executed.');
</script>

<!-- This executes as soon as it & its imports have fetched -->
<script async type="module" src="1.js"></script>

Live demo. The fast-downloading scripts should execute before the slow ones.

As with regular scripts, async causes the script to download without blocking the HTML parser and executes as soon as possible. Unlike regular scripts, async also works on inline modules.

As always with async, scripts may not execute in the order they appear in the DOM.

Browser issues

  • Firefox doesn't support async on inline module scripts (issue).

Modules only execute once

<!-- 1.js only executes once -->
<script type="module" src="1.js"></script>
<script type="module" src="1.js"></script>
<script type="module">
  import "./1.js";
</script>

<!-- Whereas normal scripts execute multiple times -->
<script src="2.js"></script>
<script src="2.js"></script>

Live demo.

If you understand ES modules, you'll know you can import them multiple times but they'll only execute once. Well, the same applies to script modules in HTML – a module script of a particular URL will only execute once per page.

Browser issues

  • Edge executes modules multiple times (issue).

Always CORS

<!-- This will not execute, as it fails a CORS check -->
<script type="module" src="https://….now.sh/no-cors"></script>

<!-- This will not execute, as one of its imports fails a CORS check -->
<script type="module">
  import 'https://….now.sh/no-cors';

  addTextToBody("This will not execute.");
</script>

<!-- This will execute as it passes CORS checks -->
<script type="module" src="https://….now.sh/cors"></script>

Live demo.

Unlike regular scripts, module scripts (and their imports) are fetched with CORS. This means cross-origin module scripts must return valid CORS headers such as Access-Control-Allow-Origin: *.

Browser issues

  • Firefox fails to load the demo page (issue).
  • Edge loads module scripts without CORS headers (issue).

No credentials

<!-- Fetched with credentials (cookies etc) -->
<script src="1.js"></script>

<!-- Fetched without credentials -->
<script type="module" src="1.js"></script>

<!-- Fetched with credentials -->
<script type="module" crossorigin src="1.js?"></script>

<!-- Fetched without credentials -->
<script type="module" crossorigin src="https://other-origin/1.js"></script>

<!-- Fetched with credentials-->
<script type="module" crossorigin="use-credentials" src="https://other-origin/1.js?"></script>

Live demo.

Most CORS-based APIs will send credentials (cookies etc) if the request is to the same origin, but fetch() and module scripts are exceptions – they don't send credentials unless you ask for them.

You can add credentials to a same-origin module by including the crossorigin attribute (which seems a bit weird to me, and I've questioned this in the spec). If you want to send credentials to other origins too, use crossorigin="use-credentials". Note that the other origin will have to respond with the Access-Control-Allow-Credentials: true header.

Also, there's a gotcha related to the "Modules only execute once" rule. Modules are keyed by their URL, so if you request a module without credentials, then request it with credentials, you'll get the same without-credentials module back. This is why I've used a ?in the URLs above, to make them unique.

Browser issues

  • Chrome requests same-origin modules with credentials (issue).
  • Safari requests same-origin modules without credentials even if you use the crossorigin attribute (issue).
  • Edge gets this backwards. It sends credentials to the same origin by default, but then doesn't send them if you add the crossorigin attribute (issue).

Firefox is the only one that gets this right – well done folks!


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

반응형
그리드형


관련글 더보기

댓글 영역