ES Module では各モジュールが独自のスコープを持つため、モジュール内で宣言した変数は自動的にグローバルにならない。真のグローバル変数として使いたい場合は、明示的に window オブジェクトに代入する必要がある。
モジュール側で window に登録する
最も直接的な方法は、モジュール内で window オブジェクトにプロパティを追加することである。
// config.js const appConfig = { apiUrl: 'https://api.example.com', version: '1.0.0' } window.appConfig = appConfig export { appConfig }
// main.js await import('./config.js') console.log(window.appConfig.apiUrl) // 'https://api.example.com' console.log(appConfig.apiUrl) // グローバルなのでこれも動く
モジュールが読み込まれた時点で window への登録が実行されるため、インポート後はどこからでもアクセスできる。
インポート側で window に登録する
モジュール側を変更できない場合は、インポート側で登録する。
// utils.js export const helpers = { formatDate: (d) => d.toISOString(), capitalize: (s) => s.charAt(0).toUpperCase() + s.slice(1) }
// main.js const { helpers } = await import('./utils.js') window.helpers = helpers // 以降どこでも使える console.log(helpers.capitalize('hello')) // 'Hello'
globalThis を使う
ブラウザ以外の環境(Node.js など)でも動作させたい場合は、window の代わりに globalThis を使う。
// config.js const appConfig = { debug: true } globalThis.appConfig = appConfig export { appConfig }
globalThis は ES2020 で標準化され、ブラウザでは window、Node.js では global を指す。環境を問わずグローバルオブジェクトにアクセスできる。
副作用としての登録
エクスポートを行わず、インポートするだけでグローバル登録される設計も可能である。
// polyfill.js window.customFeature = function() { console.log('Custom feature loaded') }
// main.js await import('./polyfill.js') customFeature() // 'Custom feature loaded'
ただし、この方法は依存関係が暗黙的になり、コードの追跡が難しくなる。通常は export/import を使い、必要な箇所でのみ window に登録する方が保守性が高い。