module export 的聚合操作

前言

import 代碼的時候會遇到下面這種狀況。

import CompA from './components/CompA'
import CompB from './components/CompB'
import CompC from './components/CompC'

當引入 component 一多,代碼多好幾行。

改成下面這樣,探討一下裡面的細節。

import { CompA, CompB, CompC } from './components/'

export 種類

MDN 文件列了四種

  • Exporting declarations
  • Export list
  • Default exports
  • Aggregating modules

他直接給了 sample 代碼

// Exporting declarations
export let name1, name2/*, … */; // also var
export const name1 = 1, name2 = 2/*, … */; // also var, let
export function functionName() { /* … */ }
export class ClassName { /* … */ }
export function* generatorFunctionName() { /* … */ }
export const { name1, name2: bar } = o;
export const [ name1, name2 ] = array;

// Export list
export { name1, /* …, */ nameN };
export { variable1 as name1, variable2 as name2, /* …, */ nameN };
export { variable1 as "string name" };
export { name1 as default /*, … */ };

// Default exports
export default expression;
export default function functionName() { /* … */ }
export default class ClassName { /* … */ }
export default function* generatorFunctionName() { /* … */ }
export default function () { /* … */ }
export default class { /* … */ }
export default function* () { /* … */ }

// Aggregating modules
export * from "module-name";
export * as name1 from "module-name";
export { name1, /* …, */ nameN } from "module-name";
export { import1 as name1, import2 as name2, /* …, */ nameN } from "module-name";
export { default, /* …, */ } from "module-name";
export { default as name1 } from "module-name";

講白話一點分類,就是分成

  • export 一個宣告的變數 (aka 具名匯出)
    • export 後面不能直接接變量,例如:export name
  • export object
    • object 裡面不能用:重新命名,要用as
    • export {a : b}會報錯
    • 同個檔可以 export 多個 object,只是命名不能重複
  • export default 這個特殊變數 (aka default 匯出)
  • export 聚合騷操作

網路上講named exportdefault export文章很多,我不想探討,我們來討論export 聚合操作

export 聚合操作

default 是什麼

通常我們寫 export default,跟引入他的時候會寫以下代碼

// a.js
const a = 456
export default a

// main.js
import a from './a.js'
console.log(a) //456

再看以下代碼

// a.js
const a = 456
export default a

// main.js
import a, { default as b } from './a.js'
console.log(a === b) //true

其實在 a 變量那個 default,跟 object 裡面的那個 default 是完全一樣的。

為了使用方便,JS 底層多做了這樣一層變數 assign

導出多個 object

直接看代碼,這樣是可以的,只是名稱不能重複

//a.js
const a = 1
const b = 2
const c = 3

export { a, c }
export { b }

//main.js
import { a, b, c } from './a.js'

像以下這樣就會報錯

因為 c 已經重複

export { a as c }
export { c }
export { b, d }

導出多個 default

要達到前言講的那種效果,只要在 components 目錄下面多一個 index.js,導入所有 components 之後,再導出

// /components/index.js
export { default as ComA } from './ComA'
export { default as ComB } from './ComB'
export { default as ComC } from './ComC'

// main.js
import { CompA, CompB, CompC } from './components/'

export *

  • 所有具名(變數)的都導出,除了 default
  • 衝突命名會產生問題

default 沒作用

//a.js
const a = 1
const b = 2
const c = 3
const d = 4
const e = 5

export { a }
export { c }
export { b, d }
export default e

//mid.js
export * from './a.mjs'

//main.js
import mid, { a, b, c, d } from './mid.mjs'

console.log({ a })
console.log({ b })
console.log({ c })
console.log({ d })
console.log({ mid })

會報SyntaxError: The requested module './mid.mjs' does not provide an export named 'default'的錯誤

衝突命名

有一樣的命名變數 a,會報錯

// -- mod1.js --
export const a = 1

// -- mod2.js --
export const a = 3

// -- barrel.js --
export * from './mod1.js'
export * from './mod2.js'

// -- main.js --
import * as ns from './barrel.js'
console.log(ns.a) // undefined
import { a } from './barrel.js'
// SyntaxError: The requested module './barrel.js' contains conflicting star exports for name 'a'