JS 模組化- 05 ES Module & 4 大規範總結

1 ES Module 規範

ES Module 是目前使用較多的模組化規範,在 Vue、React 中大量使用,大家應該非常熟悉。TypeScript 中的模組化與 ES 類似。

1.1 導出模組

導出模組有兩種方式:按需導出默認導出

按需導出是使用 export 關鍵字,將需要導出的成員(變數、函數、對象等)依次導出:

export const xxx = ''
export const xxx = () => {}

一個模組中可以有多個按需導出,但只能有一個默認導出。假設默認導出 A 模組,當 B 模組直接導入模組 A 時,其導入的值就是模組 A 默認導出的值。

export default {}

1.2 導入模組

導入按需導出的模組:

import { xxx } from 'xxx'

上面語法中,花括弧 {} 中的內容必須與導出的名稱一致。

如果按需導出的成員較多,可以使用 as 一次性導入:

import * as xxx from 'xxx'

導入默認導出的模組:

import xxx from 'xxx'

也可以直接導入一個模組,並直接執行該模組的程式碼:

import 'xxxxx'

2 使用 Webpack 編譯 ES Module

2.1 初始化項目

創建 modules 目錄,裡面存放兩個模組 module1.jsmodule2.js。入口文件與 modules 目錄同級,名為 index.js。文件和目錄結構如下:

05_ESM/
  |- modules/
    |- module1.js
    |- module2.js
  |- index.js
  |- index.html

2.2 實現兩個模組

module1.js 使用按需導出變數 str1 和函數 fun1,默認導出 user 對象:

console.log('in module1')

export const str1 = 'hello module1'

export const fun1 = (msg) => {
  return `module1:${msg}`
}


const user = {
  name: 'zhangsan',
  age: 30
}

export default user

module2.js 使用默認導出,導出一個對象,這個對象包括屬性 str2 和方法 fun2

console.log('in module2')

const str2 = 'hello module2'

const fun2 = (msg) => {
  return `module2:${msg}`
}

export default {
  str2,
  fun2
}

2.3 實現入口文件

在入口文件 index.js 中導入兩個模組。由於 module1.js 是按需導出,故導入時需要使用 {}module2.js 是默認導出,故此處可以直接導入:

import { str1, fun1 } from './modules/module1'
import m2 from './modules/module2'

console.log(str1)
console.log(fun1('程式設計師優雅哥'))
console.log(m2.str2)
console.log(m2.fun2('youyacoder'))

2.4 入口 HTML

創建 index.html 文件,使用 script 標籤導入 index.js

<script src="./index.js"></script>

在瀏覽器中訪問 index.html 文件,控制台會提示如下錯誤:

Uncaught SyntaxError: Cannot use import statement outside a module (at index.js:1:1)

這是由於瀏覽器不認識 ESM 語法。可以使用 babel 將 ES6 語法編譯為 ES5 的語法,然後使用 browserify 進行打包;也可以使用 webpack 打包。此處我使用 webpack 5

2.5 使用 Webpack 打包

使用 npmyarn 初始化項目:

yarn init -y

安裝 webpackwebpack-cli 為開發依賴:

yarn add webpack webpack-cli -D 

使用 webpack 打包:

npx webpack ./index.js -o ./dist/ --mode development

上面的打包命令直接在命令中配置參數,省略了額外的配置的文件。該命令指定了打包的入口文件為:index.js;輸出的目錄為 dist 目錄,打包模式為 development。關於 webpack 5 的使用,有興趣的可以看優雅哥的 webpack 5 系列文章。

執行完打包命令後,會生成 dist 目錄,並且在該目錄中有個 main.js 文件。

index.html 中刪除之前引入的 index.js,替換為 dist/main.js

<script src="./dist/main.js"></script>

重新在瀏覽器中訪問 index.html, 控制台輸出如下:

image-20220926223738435

3 ES Module 總結

導出模組:

  • 默認導出:export default xxx
  • 按需導出 export const xxx

導入模組:

  • 默認導入: import xxx from ‘xxx’

  • 按需導入 import { xxx } from ‘xxx’

4 JS 模組化 4 大規範總結

前面優雅哥依次寫了模組化的發展史,模組化的規範(可進主頁查看每個規範詳細版本),現進行一個大匯總方便大家查閱和總結:

01- 模組化前傳

02 – Common JS 規範

03 – AMD 規範(Require JS 實現)

04 – CMD 規範 (Sea JS 實現)

05 – ESM 規範

模組化相關 demo 源碼可以 github 搜索關鍵詞 js-module-demo 或聯繫 程式設計師優雅哥 獲取。

image

源碼目錄如下:

js-module-demo/
|- 01_Histry/			模組化發展史
|- 02_CommonJS/		CommonJS 規範
|- 03_AMD/				ADM 規範
|- 04_CMD/				CMD 規範
|- 05_ESM/				ESM 規範

各個模組化規範有相似之處,也有差異,模組定義與模組載入的語法如下:

4.1 Common JS 規範

定義模組的語法:

// 暴露函數
module.exports = function () {}

// 暴露對象
module.exports = {
  xxx: () => {}
}

exports.xxx = {}

exports.xxx = function() {}

載入模組的語法:

const xxx = require('xxxx')

4.2 AMD 規範

定義模組的語法:

define(id?, dependencies?, factory)

載入模組的語法:

require([module], callback)

4.3 CMD 規範

定義模組的語法:

// 定義模組
define(function(require, exports, module) {
	
	// 使用 exports 導出模組
	exports.xxx = xxx
	
	//也可以使用 return 導出模組
	// return xxx
})

載入模組的語法:

// 同步載入模組
const m1 = require('../xxx')

// 非同步載入模組
require.async('../xxx', function (m2) {
})

4.4 ESM 規範

導出模組:

// 按需導出
export const xxx = ''
export const xxx = () => {}

// 默認導出
export default xxx

導入模組:

import { xxx, yyy } from 'xxx'
import * as xxx from 'xxx'
import xxx from 'xxx'
import 'xxx'

感謝你閱讀本文,如果本文給了你一點點幫助或者啟發,還請三連支援一下,點贊、關注、收藏,作者會持續與大家分享更多乾貨