站長阿川

站長阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

站長精心設計,帶你實作 63 個小專案,得到作品集!

立即開始免費試讀!

為什麼有些依賴必須 import * 引入使用?

image

嗨,我是石小石~


在日常前端開發中,我們常常透過 import 來引入第三方庫或模組。像這樣:

import dayjs from "dayjs";
import { useState, useEffect } from 'react';

但你可能遇過這樣一種情況:有些依賴如果直接寫成

import echarts from 'echarts';

會報錯,或者運行時報 echarts is undefined,而必須寫成:

import * as echarts from 'echarts';

這種現象可能會讓你感到疑惑:為什麼 ECharts 必須使用 import * 的方式?難道普通的默認導入不行嗎?

本文將以 ECharts 為例,深入探討這一問題的根源,並順帶梳理 ES Module(ESM)與 CommonJS(CJS)模組規範的差異,幫助你從底層理解 import * 背後的原因。

import 的幾種常見用法

在 ES Module 規範中,常見的幾種導入方式包括:

默認導入

import xxx from 'module';

要求模組導出中必須有 export default xxx;

類名導入

import { a, b } from 'module';

要求模組內部有 export const aexport const b 等類名導出。

命名空間導入

import * as mod from 'module';

將模組的所有導出整合到一個物件 模組 上。

通過 ECharts 的導出方式深入 import *

ECharts 的導出方式

熟悉完 ES6 的 import 的命名空間導入用法,我想 echarts 為什麼需要透過 import * 答案已經很明確了。我們來看看 echarts 的入口檔案:

image

這三句話分別代表了三種不同的模組兼容策略:

  • import * as echarts from ...
    表示 ECharts 的所有導出都是 具名導出,並沒有 export default

  • export as namespace echarts;
    這是為了兼容 UMD 模組,即在瀏覽器透過 <script> 直接引入時,可以掛載到全局變數 window.echarts 上。這樣我們在代碼裡就能直接寫:

echarts.init(document.getElementById('main'));
  • export = echarts;
    這是 CommonJS 風格的導出,相當於 module.exports = echarts,用於兼容 Node.js 或舊的打包工具。在這種情況下,TypeScript 需要你用 import * as echarts 來導入,而不是 import echarts from 'echarts'

為什麼 ECharts 沒有用 export default

看到這裡,你可能還是有些困惑,如果導出入口改成

import * as echarts from './types/dist/echarts';
// Export for UMD module.
export as namespace echarts;
export default echarts;

我們代碼裡不是就可以使用下面的導入方式了嗎?

import echarts from 'echarts';

原因主要有三點:

  • 兼容性考量

ECharts 是一個全球用戶量非常大的可視化庫,既要兼容 ESM,又要兼容 CommonJS,還要兼容 UMD(透過 <script> 引入時掛到 window.echarts 上)。
如果用 export default,對 CJS/UMD 的支持會比較麻煩,而 export = 在 TypeScript 下能天然兼容多種模組系統。

  • 歷史包袱

ECharts 最早是基於 UMD 格式發佈的(早於 ES Module 普及)。
當時的入口寫法更偏向:

if (typeof module === 'object' && module.exports) {
  module.exports = echarts;
} else {
  window.echarts = echarts;
}

後來遷移到 TypeScript 時,延續了 export = echarts 這種兼容寫法,而不是強行改為 export default

  • API 設計思路

ECharts 官方的定位是“命名空間式 API”,也就是說,用戶習慣透過 echarts.xxx() 方式調用。
為了保持這種語義一致性,團隊沒有提供 default export,而是把所有 API 都掛在一個 echarts 命名空間物件下。

import * 的其他應用場景

除了 ECharts,還有一些庫或工具函數常常需要使用 import *

  • 工具類庫

有些工具庫導出了非常多的函數,如果不想逐個引入,可以整合為一個命名空間物件。例如:lodash-es

import * as _ from 'lodash-es';

const arr = [1, 2, 2, 3, 4];
console.log(_.uniq(arr)); // [1, 2, 3, 4]
  • 配置性常量集合

當一個模組只導出大量的常量或枚舉值時,import * 可以避免逐個列出,寫法更整潔。

例如:Node.js 內建 path 模組(ESM 版本)

import * as path from 'path';

console.log(path.sep);   // 當前系統路徑分隔符(Windows: '', Linux/Mac: '/')
console.log(path.resolve('./src'));

如何判斷是否需要 import *

如果你不確定一個庫該怎麼導入,可以採用以下幾種方式:

看文檔示例

image

查看原始碼或 d.ts 檔案

如果不想找文檔,可以直接打開專案的依賴

image

找到對應的包,導出方式在 index.d.ts 檔案中可以看到

image

Trae/Cursor 智能提示

並不是所有第三方庫都內置 Ts 支持,有 index.d.ts 檔案,這個時候你可以借助 AI 編譯器(如 Trae 或 Cursor)的智能提示。

Trae 的註解生成代碼為例:

image


原文出處:https://juejin.cn/post/7544301375816237107


共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
站長阿川

站長阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

站長精心設計,帶你實作 63 個小專案,得到作品集!

立即開始免費試讀!