script 標籤與模組

September 9, 2022

網頁透過 script 標籤來定義 JavaScript 程式碼,若瀏覽器支援,可以將 type 屬性設定為 "module",表示內嵌或引用的 .js 程式碼是 ES6 模組。例如:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <script type="module">
        let welcome = document.getElementById('welcome');
        let name = prompt('輸入你的名稱');
        welcome.innerHTML = `哈囉!${name}!`;
    </script>    
</head>
<body>
    <span id="welcome"></span>
</body>
</html>

引用模組

type 設定為 "module" 時,script 內嵌或透過 src 引用 .js 時,預設具有 defer 的特性,也就是 .js 會以非同步方式下載,並在 DOM 樹生成與其他非 defer 的 .js 執行完後,才依頁面出現順序執行 defer的程式碼,因此,上例的script雖然寫在head標籤中,也是在 DOM 樹生成後執行 。 當type設定為“module” 時,src` 引用的 .js 就視為模組,例如,若 hello.js 如下定義:

let welcome = document.getElementById('welcome');
let name = prompt('輸入你的名稱');
welcome.innerHTML = `哈囉!${name}!`;

引用模組時,.js 不能來自本機,因此得啟動一個 HTTP 伺服器,才能如下引用模組:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <script type="module" src="mods/hello2.js"></script>    
</head>
<body>
    <span id="welcome"></span>
</body>
</html>

可見性

每個模組中的定義的名稱,僅在模組內可見,script 標籤的 type 設為 "module" 時,就代表著一個模組,內嵌的程式碼也是一個模組,其他 script 看不到其中的名稱。例如以下會發生錯誤:

<script type="module">
    // hello僅在此模組可見
    function hello(name) {
        return `Hello! ${name}!`;
    }
</script>
<script type="text/javascript">
    console.log(hello('Justin')); // ReferenceError
</script>

就算兩個 script 標籤的 type 設為 "module" 時,各自的名稱也是互不相見,以下也是會發生錯誤:

<script type="module">
    // hello僅在此模組可見
    function hello(name) {
        return `Hello! ${name}!`;
    }
</script>
<script type="module">
    console.log(hello('Justin')); // ReferenceError
</script>

標籤的 type 設為 "module" 並引用外部模組時,可以附加 async 屬性,此時會非同步下載 .js 檔案,先下載完成就先執行。

降級處理

支援模組的瀏覽器,會忽略 <script nomodule></script>,因此對於打算提供降級處理的情境,可以如下撰寫:

<script type="module" src="mods/util.js"></script>
<script nomodule src="js/util_fallback.js"></script>

支援模組的瀏覽器會使用 util.js,忽略 <script nomodule></script>;不支援模組的瀏覽器,本來就不理會 type 設為 modulescript 標籤,因此會使用 util_fallback.js。

分享到 LinkedIn 分享到 Facebook 分享到 Twitter