ES Module の動的インポートで同名関数は衝突しない

動的インポート(import())で別ファイルを読み込んだ場合、同名の関数があっても衝突しない。各モジュールは独立したスコープを持ち、インポート時に明示的に名前を指定するためである。

// moduleA.js
export function process() {
  return 'A'
}

// moduleB.js
export function process() {
  return 'B'
}

// main.js
const modA = await import('./moduleA.js')
const modB = await import('./moduleB.js')

console.log(modA.process()) // 'A'
console.log(modB.process()) // 'B'

動的インポートは Promise を返し、解決されるとモジュールの名前空間オブジェクトが得られる。このオブジェクトを通じてエクスポートされた関数にアクセスするため、同名であっても別々の変数に格納すれば問題ない。

同じ変数に代入すると上書きされる

同じ変数に代入すれば後からインポートしたものが残る。

let mod = await import('./moduleA.js')
console.log(mod.process()) // 'A'

mod = await import('./moduleB.js')
console.log(mod.process()) // 'B'

これは衝突ではなく、単なる変数の再代入である。

分割代入での注意点

分割代入を使うと、同じスコープ内で同名の変数を宣言できない。

const { process } = await import('./moduleA.js')
const { process } = await import('./moduleB.js') // SyntaxError

この場合はエイリアスを使う。

const { process: processA } = await import('./moduleA.js')
const { process: processB } = await import('./moduleB.js')

console.log(processA()) // 'A'
console.log(processB()) // 'B'

ES Module の設計上、名前空間が分離されているため、インポート側で適切に変数名を管理すれば衝突は起きない。