ES Module 是目前使用較多的模組化規範,在 Vue、React 中大量使用,大家應該非常熟悉。TypeScript 中的模組化與 ES 類似。
匯出模組有兩種方式:按需匯出 和 預設匯出。
按需匯出是使用 export 關鍵字,將需要匯出的成員(變數、函數、物件等)依次匯出:
export const xxx = ''
export const xxx = () => {}
一個模組中可以有多個按需匯出,但只能有一個預設匯出。假設預設匯出 A 模組,當 B 模組直接匯入模組 A 時,其匯入的值就是模組 A 預設匯出的值。
export default {}
匯入按需匯出的模組:
import { xxx } from 'xxx'
上面語法中,花括號 {} 中的內容必須與匯出的名稱一致。
如果按需匯出的成員較多,可以使用 as 一次性匯入:
import * as xxx from 'xxx'
匯入預設匯出的模組:
import xxx from 'xxx'
也可以直接匯入一個模組,並直接執行該模組的程式碼:
import 'xxxxx'
建立 modules 目錄,裡面存放兩個模組 module1.js 和 module2.js。入口檔案與 modules 目錄同級,名為 index.js。檔案和目錄結構如下:
05_ESM/
|- modules/
|- module1.js
|- module2.js
|- index.js
|- index.html
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
}
在入口檔案 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'))
建立 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。
使用 npm 或 yarn 初始化專案:
yarn init -y
安裝 webpack、webpack-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, 控制檯輸出如下:
原始碼目錄如下:
js-module-demo/
|- 01_Histry/ 模組化發展史
|- 02_CommonJS/ CommonJS 規範
|- 03_AMD/ ADM 規範
|- 04_CMD/ CMD 規範
|- 05_ESM/ ESM 規範
各個模組化規範有相似之處,也有差異,模組定義與模組載入的語法如下:
定義模組的語法:
// 暴露函數
module.exports = function () {}
// 暴露物件
module.exports = {
xxx: () => {}
}
exports.xxx = {}
exports.xxx = function() {}
載入模組的語法:
const xxx = require('xxxx')
定義模組的語法:
define(id?, dependencies?, factory)
載入模組的語法:
require([module], callback)
定義模組的語法:
// 定義模組
define(function(require, exports, module) {
// 使用 exports 匯出模組
exports.xxx = xxx
//也可以使用 return 匯出模組
// return xxx
})
載入模組的語法:
// 同步載入模組
const m1 = require('../xxx')
// 非同步載入模組
require.async('../xxx', function (m2) {
})
匯出模組:
// 按需匯出
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'
感謝你閱讀本文,如果本文給了你一點點幫助或者啟發,還請三連支援一下,點贊、關注、收藏,作者會持續與大家分享更多幹貨