JavaScript ES6 模組化 import export CommonJS Node.js require
前端工程

JavaScript ES6 的模組化功能:import, export。建置前端時 require 與 import 有何不同?

商業,創業,業務,職涯,美食,葡萄酒,閱讀,網路科技。

從 Larry 創業以及商業的經驗,希望以白話的口吻,介紹給大家這個商業的世界。

FB粉專會頻繁地更新 Larry 對於商業、社會、人生的觀察與心得,歡迎大家追蹤互動~

這篇文章我們來聊一個不新,但重要的議題:JavaScript 的模組化。

其實 JavaScript 早期只是一個腳本式語言,做做 HTML DOM 的簡單變化而已。也許直接寫在 HTML 裡,也許引用幾支 JS 檔,這樣而已。

2010 年 AngularJS 問世,開啟了 201x 年前端工程的飛速成長,包含各種前端框架的興起,與 Single Page Application (單頁式網站)。AngularJS 後來變成了 Angular,加上 React、Vue.js,這三大家前端框架維持了好一段時間。

延伸閱讀,後來 Laravel 預設的前端框架從 Vue.js 改為使用 Alpine.js

2015年,JavaScript ECMAScript 2015 發布,也稱為 ES6。為什麼是 6 這個數字?是 JavaScript 這個語言的第 6 版。也就是從 ES6 開始,JavaScript 導入了模組化的概念以及語法。

基本上一個 JS 檔案就是一個模組,用 export 語法,將你想要輸出的變數、函式、物件、類別,都可以輸出。例如

export const your_var = 'test';

export function your_func() {
    // …
}

假設上面檔案叫 your_module.js。你可以在 HTML 裡直接輸入 JS 模組,注意一定要寫 type="module",且 import 的後方是大括號

<script type="module">
    import { your_var, your_func, your_object, your_class } from './your_module.js';

    // 就可以使用 your_var, your_func …
</script>

或是在另一支 JS (假設名稱是 abc.js) 裡面 import,HTML 直接引用 abc.js,注意一樣要寫 type="module"。也就是 your_module.js 的變數輸入到 abc.js,並在 abc.js 執行

<script type="module" src="./abc.js"></script>

或是你在輸出時也可以改變數名稱

export { your_var as new_name, your_function as new_func };

當然,輸入時就要用新名稱輸入。

輸入時也可以改名

import { your_var as new_name } from "./your_module.js";

這樣在輸入模組就是用新名稱。

還有一種寫法也滿常見的,把整個模組輸入

import * as your_module from './your_module.js';

your_module.func_a();  // 在 your_module.js, func_a 要 named export

以上的 export / import 範例是 named export / import (具名輸出/輸入),還有一種是 default export / import。例如

// 輸出
export default your_var;
// 輸入
import new_name from './your_module.js';

default export 最重要的就是在輸出模組「只能出現一次」。在輸入模組則是任意取名去接。

這樣就是一個最簡單的 export / import 架構了。完整的 export / import 寫法還有很多變形,可以參考 MDN 的 export 語法文件import 語法文件

CommonJS 的 require

目前大部分網站,都是在 Node.js 開發環境 build 前端。常常會看到一個 JS 關鍵字 require('...')

require 來自於 CommonJS,始於開發者的獨立專案。後來 Node.js 用 CommonJS 實作,也採用了 require,直至今日。但必須說明,require 並非 JavaScript ES6 的原生規格。

require 的參數常常是「不加」檔名,為什麼?例如

require(‘./your_your_module’);

依照 Node.js 官方文件,Node.js 會先找 .js、.json、.node。如果你要輸入的不是這3個副檔名,require 參數就要寫檔名全稱 (包含副檔名)。

require 參數也可以填入 package.json 中列出的套件名稱,這樣 Node.js 就會知道要輸入的檔案路徑 (通常是在 node_modules 資料夾底下)。

建置前端時 require 與 import 的不同

我們以 Laravel 舉例。基本上 Laravel 是用 require,因為 Laravel 前端建置基底是 Node.js,用的是 CommonJS module system。當然,Node.js 稍作調整可以支援 ES6 module system,不在這裡討論。

如果你有 local module (非 Node.js 核心,非 npm 安裝,開發者自己擺在專案的 js 檔案),require 跟 import 都可以。

這邊要說明一下,不管是 require 或 import,一般情形只是「執行」該 js 檔案。在建置前端時,是將輸入的模組一起 compile 起來。

結論

本篇回顧了一下 JavaScript ES6 的 import / export,也藉這個機會比較了 Node.js 建置前端時用的 require。

本篇重點並「不在」比較 CommonJSES6 module system,兩者寫法不同,規格也不同。例如,require 輸入的是整個模組,import 可以輸入一個模組中部分的變數、函式、物件、類別。

import / export 與 require 不是新題目,但卻是現代前端技術很重要的模組化功能。很多前端建置工具是基於 Node.js (例如 Laravel),require 與 import 也大量被使用,很值得再回顧一下。

商業,創業,業務,職涯,美食,葡萄酒,閱讀,網路科技。

從 Larry 創業以及商業的經驗,希望以白話的口吻,介紹給大家這個商業的世界。

FB粉專會頻繁地更新 Larry 對於商業、社會、人生的觀察與心得,歡迎大家追蹤互動~