如果瀏覽器支援 ES6 模組(可參考〈ECMAScript modules in browsers〉),例如 Chrome 61 之後,可以支援 ES6 模組,那麼可以將 <script>
的 type
屬性設定為 "module"
,表示這是一個 ES6 模組,例如:
<script type="module" src="js/util.js"></script>
當 type
設定為 "module"
時,<script>
也會是 defer
的,因此指定的 .js 會以非同步方式下載,並在 DOM 樹生成與其他非 defer
的 .js 執行完後才(依序)執行。
<script type="module"></script>
之間也可以撰寫 JavaScript 程式碼,也才可以撰寫 import
語句,例如,如果有個 hello.js 作為 ES6 模組:
function hello(name) {
return `Hello! ${name}!`;
}
export {hello};
可以撰寫底下的 HTML,必須注意的是,在瀏覽器中,模組的 import from
中,必須加上 .js 副檔名:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script type="module">
import {hello} from './hello.js';
window.onload = function() {
let welcome = document.getElementById('welcome');
welcome.innerHTML = hello(prompt('Input your name'));
};
</script>
</head>
<body>
<span id="welcome"></span>
</body>
</html>
若程式碼中有 import
語句時,瀏覽器以非同步方式下載模組,若有多個 import
語句,全部下載完成後再依 import
的順序執行,然後才執行模組頂層的程式碼。
無論 import
幾次,或者 <script type="module" src="./hello.js"></script>
多次,模組都只會被載入與執行一次。
type
被設為 "module"
的 <script></script>
中,可以使用 type
被設為 "text/javascript"
的 <script></script>
中的程式相關定義:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script type="text/javascript">
function hello(name) {
return `Hello! ${name}!`;
}
</script>
<script type="module">
window.onload = function() {
let welcome = document.getElementById('welcome');
welcome.innerHTML = hello(prompt('Input your name'));
};
</script>
</head>
<body>
<span id="welcome"></span>
</body>
</html>
然而,反過來不行:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script type="module">
function hello(name) {
return `Hello! ${name}!`;
}
</script>
<script type="text/javascript">
window.onload = function() {
let welcome = document.getElementById('welcome');
welcome.innerHTML = hello(prompt('Input your name')); // ReferenceError
};
</script>
</head>
<body>
<span id="welcome"></span>
</body>
</html>
兩個 type
為 "module"
的 <script></script>
,被視為兩個獨立的模組,因此也沒辦法直接取用定義:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script type="module">
function hello(name) {
return `Hello! ${name}!`;
}
</script>
<script type="module">
window.onload = function() {
let welcome = document.getElementById('welcome');
welcome.innerHTML = hello(prompt('Input your name')); // ReferenceError
};
</script>
</head>
<body>
<span id="welcome"></span>
</body>
</html>
當然,如果可以使用 type = "module"
,會有一個主要的模組,在該模組中使用 import
,如果真的有需求,必須從 type = "text/javascript"
的 <script></script>
中使用 ES6 的模組的話,是有些 ES6 Module Loader 的 polyfill 程式庫可以使用。
另一個方式是放棄使用 ES6 模組,一個可以處理 type = "module"
的瀏覽器,會忽略 <script nomodule></script>
,因此,當這麼撰寫時:
<script type="module" src="js/util.js"></script>
<script nomodule src="js/util_fallback.js"></script>
支援 ES6 模組的瀏覽器會使用 util.js,而不支援的瀏覽器會使用 util_fallback.js。