MochiuWiki : SUSE, EC, PCB
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
JavaScriptの基礎 - ESモジュールのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
JavaScriptの基礎 - ESモジュール
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == ESモジュール (ECMAScript Modules, ESM) は、ES2015 (ES6) で導入されたJavaScriptの標準モジュールシステムである。<br> 各ファイルが独立したスコープを持ち、<code>export</code> で値を公開し、<code>import</code> で他のモジュールの値を利用する仕組みを提供する。<br> <br> ESモジュールの主な特性を以下に示す。<br> * strictモードの自動適用 *: モジュールファイルは自動的にstrictモードで実行される。<code>"use strict"</code> を明示する必要はない。 * プライベートスコープ *: <code>export</code> されない限り、モジュール内の宣言は外部からアクセスできない。 * 遅延実行 (defer) *: ブラウザでは、モジュールスクリプトはHTMLのパース完了後に実行される。 * 一度だけ評価 *: 同一モジュールが複数回 <code>import</code> されても、コードは初回のみ実行されキャッシュされる。 * 静的解析とTree Shaking *: <code>import</code> / <code>export</code> 文はファイルの先頭に記述し、静的に解析できる。バンドラーによるTree Shaking (未使用コードの除去) に対応する。 * トップレベルawait対応 *: モジュール内では、関数の外でも <code>await</code> を使用できる。 <br> ブラウザでは <code><script type="module"></code> と指定することでESMを利用できる。<br> Node.jsでは、ファイルの拡張子を <code>.mjs</code> にするか、<code>package.json</code> に <code>"type": "module"</code> を指定することでESMを有効化できる。<br> <br><br> == モジュールの基本 == ==== モジュールとは ==== <u>モジュールとは、関連するコードを一纏めにしたファイル単位の独立した単位である。</u><br> <br> モジュールシステムを使用することにより、コードを機能ごとに分割して管理して、再利用性と保守性を高めることができる。<br> <br> ESモジュールでは、各ファイルがそれ自体のスコープを持つ。<br> あるモジュール内で定義した変数や関数は、明示的に <code>export</code> しない限り他のモジュールからは参照できない。<br> <br> ==== モジュールの特性 ==== 下表に、ESモジュールが持つ主要な特性を示す。<br> <br> <center> {| class="wikitable" |+ ESモジュールの特徴 ! 特徴 !! 説明 |- | 自動strictモード || モジュールスコープは自動的にstrictモードとなる。<br>暗黙的なグローバル変数の作成やその他のstrictモード違反がエラーになる。 |- | プライベートスコープ || <code>export</code> されない宣言はモジュール内でのみ有効である。<br>グローバルスコープを汚染しない。 |- | 遅延評価とキャッシュ || モジュールは、初回 <code>import</code> 時に評価され、以降は評価済みの結果がキャッシュとして再利用される。<br>そのため、副作用を持つモジュールが複数箇所から <code>import</code> されても、副作用は1度しか実行されない。 |- | 静的な構造 || <code>import</code> 文と <code>export</code> 文は静的に解析される。<br>コードの実行前にモジュール間の依存関係が確定するため、循環依存の検出やTree Shakingが可能になる。 |- | トップレベルawait || ESモジュールでは、非同期関数の外側 (トップレベル) でも <code>await</code> を使用できる。<br>CommonJSにはない機能である。 |} </center> <br><br> == エクスポート == エクスポートとは、モジュールから値を公開することである。<br> <br> ==== 名前付きエクスポート ==== 名前付きエクスポートは、1つのモジュールから複数の値をエクスポートする方法である。<br> <br> エクスポートした名前がそのままインポート時の識別子となる。<br> <br> * 宣言と同時にエクスポートする方法 *: <syntaxhighlight lang="javascript"> // math.js // 宣言と同時にエクスポートする export function add(a, b) { return a + b; } export function subtract(a, b) { return a - b; } export const PI = 3.14159; </syntaxhighlight> *: <br> * 宣言後にまとめてエクスポートする方法 *: <syntaxhighlight lang="javascript"> // string-utils.js function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } function trim(str) { return str.trim(); } // エイリアス付きでエクスポートすることもできる function _internalHelper(str) { return str.toLowerCase(); } // まとめてエクスポートする export { capitalize, trim }; // エイリアス付きエクスポート : 内部名とは異なる名前で公開する export { _internalHelper as helper }; </syntaxhighlight> <br> ==== デフォルトエクスポート ==== デフォルトエクスポートは、1つのモジュールにつき1つだけ定義できるエクスポートである。<br> <br> <u>インポート時に任意の名前を付けることができるため、モジュールの主要な機能を公開する場合に適している。</u><br> <br> デフォルトエクスポートの例を以下に示す。<br> <br> * 関数のデフォルトエクスポート *: <syntaxhighlight lang="javascript"> // logger.js // 関数のデフォルトエクスポート export default function log(message) { console.log("[LOG]", message); } </syntaxhighlight> *: <br> * クラスのデフォルトエクスポート *: <syntaxhighlight lang="javascript"> // User.js // クラスのデフォルトエクスポート export default class User { constructor(name, email) { this.name = name; this.email = email; } toString() { return this.name + " <" + this.email + ">"; } } </syntaxhighlight> *: <br> * 値のデフォルトエクスポート *: <syntaxhighlight lang="javascript"> // config.js // 値のデフォルトエクスポート (export defaultの後に直接値を記述する) export default { apiUrl : "https://api.example.com", timeout : 5000, retries : 3 }; </syntaxhighlight> <br> ==== 名前付きエクスポート と デフォルトエクスポートの比較 ==== 下表に、名前付きエクスポートとデフォルトエクスポートの違いを示す。<br> <br> <center> {| class="wikitable" |+ 名前付きエクスポート vs デフォルトエクスポート ! 項目 !! 名前付きエクスポート !! デフォルトエクスポート |- | 1モジュールあたりの個数 || 複数可能 || 1つのみ |- | インポート時の名前 || エクスポート名と一致する。(<code>as</code> で変更可能) || 任意の名前を指定できる。 |- | インポート構文 || <u>import { name } from 'module'</u> || <u>import name from 'module'</u> |- | Tree Shaking || 容易 || 限定的 |- | リネームの必要性 || <code>as</code> キーワードが必要 || インポート時に自由に命名できる。 |- | 主な用途 || ユーティリティ関数群、定数群 || モジュールの単一のメイン機能 |} </center> <br><br> == インポート == ==== 名前付きインポート ==== 名前付きエクスポートされた値は、波括弧 <code>{ }</code> を使用してインポートする。<br> <br> <syntaxhighlight lang="javascript"> import { add, subtract } from './math.js'; console.log(add(10, 3)); // 13 console.log(subtract(10, 3)); // 7 </syntaxhighlight> <br> ==== デフォルトインポート ==== デフォルトエクスポートされた値は、波括弧なしでインポートする。<br> <br> インポート時の名前は任意に決めることができる。<br> <br> <syntaxhighlight lang="javascript"> import log from './logger.js'; import User from './User.js'; log("アプリケーション起動"); // "[LOG]アプリケーション起動" const user = new User("太郎", "taro@example.com"); console.log(user.toString()); // "太郎 <taro@example.com>" </syntaxhighlight> <br> 名前付きインポートとデフォルトインポートを1行で組み合わせることもできる。<br> <br> <syntaxhighlight lang="javascript"> // デフォルトインポートと名前付きインポートを同時に行う import React, { useState, useEffect } from 'react'; </syntaxhighlight> <br> ==== エイリアス (as) ==== <code>as</code> キーワードを使用することにより、インポートする値に別名 (エイリアス) を付けることができる。<br> <br> これは、名前の衝突を避けたい場合や、より分かりやすい名前で使用したい場合に有用である。<br> <br> <syntaxhighlight lang="javascript"> import { capitalize as capitalizeString } from './string-utils.js'; import { helper as stringHelper } from './string-utils.js'; console.log(capitalizeString("hello")); // "Hello" console.log(stringHelper("WORLD")); // "world" </syntaxhighlight> <br> ==== 名前空間インポート ==== <code>* as</code> 構文を使用することで、モジュールの全エクスポートを1つのオブジェクトにまとめてインポートできる。<br> <br> 名前空間として利用することで、複数のエクスポートを整理して管理できる。<br> <br> <syntaxhighlight lang="javascript"> import * as MathUtils from './math.js'; console.log(MathUtils.add(5, 3)); // 8 console.log(MathUtils.subtract(5, 3)); // 2 console.log(MathUtils.PI); // 3.14159 </syntaxhighlight> <br> ==== 副作用のみのインポート ==== インポートする値を指定せずに <code>import</code> 文を記述すると、モジュールのコードを実行するだけで何もインポートしない。<br> <br> これは、ポリフィルや、グローバルに副作用を適用するモジュールで使用される。<br> <br> <syntaxhighlight lang="javascript"> // モジュールのコードを実行するだけで、何もインポートしない import './polyfills.js'; import './global-styles.css'; </syntaxhighlight> <br><br> == 再エクスポート == 再エクスポートとは、他のモジュールからインポートした値を、そのまま別のモジュールとして公開する方法である。<br> <br> ==== 基本構文 ==== <code>export ... from</code> 構文を使用することにより、インポートした値を再エクスポートできる。<br> <br> 1度インポートしてから再エクスポートする場合と比較して、変数に束縛されないため簡潔に記述できる。<br> <br> <syntaxhighlight lang="javascript"> // 特定の名前付きエクスポートを再エクスポートする export { add, subtract } from './math.js'; // エイリアスを付けて再エクスポートする export { capitalize as cap } from './string-utils.js'; // モジュールの全エクスポートを再エクスポートする export * from './math.js'; // デフォルトエクスポートを名前付きで再エクスポートする export { default as User } from './User.js'; // デフォルトエクスポートをデフォルトのまま再エクスポートする export { default } from './logger.js'; </syntaxhighlight> <br> ==== バレルファイル (index.js) パターン ==== 複数のモジュールを1つのエントリポイントにまとめて公開するパターンをバレルファイルパターンと呼ぶ。<br> <br> <code>index.jsファイル</code> (または <code>index.tsファイル</code>) に再エクスポートをまとめることにより、利用側のインポートパスを短くできる。<br> <br> <syntaxhighlight lang="javascript"> // components/index.js (バレルファイル) export { Button } from './Button.js'; export { Modal } from './Modal.js'; export { TextInput } from './TextInput.js'; export { default as Icon } from './Icon.js'; </syntaxhighlight> <br> <syntaxhighlight lang="javascript"> // 利用側: バレルファイルを通じて複数のコンポーネントを1行でインポートできる import { Button, Modal, TextInput } from './components'; // 個別パスを指定する場合と比べて記述が簡潔になる // import { Button } from './components/Button.js'; // import { Modal } from './components/Modal.js'; // import { TextInput } from './components/TextInput.js'; </syntaxhighlight> <br> バレルファイルを使用する時の注意点を以下に示す。<br> <br> * <u>Tree Shakingへの影響</u> *: バンドラーによっては、バレルファイルを経由したインポートでTree Shakingが効きにくくなる場合がある。 *: 特に大規模なライブラリでは、バレルファイルのインポートがバンドルサイズの増加につながる場合がある。 * <u>循環依存のリスク</u> *: バレルファイルを多用すると、モジュール間の循環依存が発生しやすくなる。 <br><br> == 動的インポート == 動的にインポートとは、実行時に必要に応じてモジュールを非同期でロードする方法である。<br> <br> ==== import()の基本 ==== <code>import()</code> は関数のような構文で呼び出す動的インポートである。<br> <br> 通常の <code>import</code> 文と異なり、コードの任意の場所に記述でき、条件分岐やイベントに応じてモジュールを遅延ロードできる。<br> <code>import()</code> はPromiseを返し、モジュールオブジェクトに解決される。<br> <br> <syntaxhighlight lang="javascript"> // Promiseチェーンを使用した動的インポート import('./math.js') .then(mathModule => { console.log(mathModule.add(5, 3)); // 8 }); // async/awaitを使用した動的インポート const math = await import('./math.js'); console.log(math.add(5, 3)); // 8 // デフォルトエクスポートにアクセスする場合は .default を使用する const logModule = await import('./logger.js'); logModule.default("メッセージ"); </syntaxhighlight> <br> ==== 使用例 ==== 動的インポートの代表的な使用場面を以下に示す。<br> <br> * 条件に応じたモジュールの読み込み *: <syntaxhighlight lang="javascript"> // ユーザのロールに応じて異なるモジュールを読み込む async function loadUserModule(userRole) { if (userRole === 'admin') { const { AdminPanel } = await import('./admin-panel.js'); return new AdminPanel(); } else { const { UserDashboard } = await import('./user-dashboard.js'); return new UserDashboard(); } } </syntaxhighlight> *: <br> * ユーザの操作をトリガーとした遅延読み込み *: <syntaxhighlight lang="javascript"> // ボタンが押下された時にのみモジュールを読み込む button.addEventListener('click', async () => { const { initChart } = await import('./chart-library.js'); initChart(document.getElementById('chart-container')); }); </syntaxhighlight> *: <br> * React.lazyを使用したコンポーネントの遅延読み込み *: <syntaxhighlight lang="javascript"> import React, { lazy, Suspense } from 'react'; // 動的インポートによる遅延読み込み const HeavyComponent = lazy(() => import('./HeavyComponent.js')); function App() { return ( <Suspense fallback={<div>読み込み中...</div>}> <HeavyComponent /> </Suspense> ); } </syntaxhighlight> <br><br> == Import Attributes (ES2025) == Import Attributesは、モジュールの読み込み時にメタデータを指定する。<br> <br> ==== 基本構文 ==== Import Attributesは、<code>import</code> 文に <code>with</code> キーワードを付加して属性を指定する構文である。<br> <br> 以前の仕様ではImport Assertions (<code>assert</code> キーワード) と呼ばれていたが、ES2025でImport Attributes (<code>with</code> キーワード) に変更された。<br> <br> <syntaxhighlight lang="javascript"> // 静的インポートでの使用 import data from './data.json' with { type: 'json' }; import styles from './styles.css' with { type: 'css' }; // 動的インポートでの使用 const config = await import('./config.json', { with: { type: 'json' } }); </syntaxhighlight> <br> ==== JSONモジュールの読み込み ==== <code>type: 'json'</code> を指定することにより、JSONファイルをモジュールとして安全に読み込むことができる。<br> <br> <syntaxhighlight lang="javascript"> // JSONファイルをインポートする (type: 'json' を指定する) import packageJson from './package.json' with { type: 'json' }; console.log(packageJson.name); // パッケージ名 console.log(packageJson.version); // バージョン番号 </syntaxhighlight> <br> セキュリティ上のメリットとして、<code>type: 'json'</code> を明示指定されたリソースはJavaScriptコードとして実行されない。<br> 悪意あるサーバがJSONを返すべき場所でJavaScriptを返した場合でも、コードが実行されることを防ぐことができる。<br> <br> ==== CSSモジュールの読み込み ==== <code>type: 'css'</code> を指定することで、CSSファイルをCSSStyleSheetオブジェクトとしてインポートできる。<br> <br> これは、Web ComponentsのShadow DOMでスタイルを適用する時に活用できる。<br> <br> <syntaxhighlight lang="javascript"> // CSSファイルをモジュールとしてインポートする import styles from './component.css' with { type: 'css' }; // Web ComponentsのShadow DOMにスタイルを適用する class MyComponent extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: 'open' }); shadow.adoptedStyleSheets = [styles]; } } </syntaxhighlight> <br> Webブラウザの対応状況 および Node.jsサポートを以下に示す。<br> <br> * Webブラウザ *: Chrome 121以降、Edge 121以降、Safari 17.4以降でサポートされている。 * Node.js *: v22以降で <code>with</code> 構文が標準サポートされている。 <br><br> == CommonJSとの比較 == 下表に、JavaScriptのもう1つの主要なモジュールシステムであるCommonJS (CJS) とESモジュール (ESM) の違いを示す。<br> <br> <center> {| class="wikitable" |+ CommonJS と ESモジュール ! 項目 !! CommonJS !! ESモジュール |- | 読み込み構文 || <u>require('module')</u> || <u>import ... from 'module'</u> |- | エクスポート構文 || <u>module.exports</u> / <u>exports.name</u> || <u>export</u> / <u>export default</u> |- | ロードタイミング || 同期・実行時 || 非同期・解析時 |- | 静的解析 || 困難 (動的) || 容易 (静的) |- | Tree Shaking || 困難 || 容易 |- | トップレベルawait || 不可 || 可能 |- | strictモード || 手動指定 (<u>"use strict"</u>) || 自動適用 |- | ブラウザサポート || なし (バンドラーが必要) || ネイティブサポート |- | <u>__dirname</u> / <u>__filename</u> || 利用可能 || <u>import.meta.url</u> で代替 |} </center> <br> 下表に、Node.jsでのESMサポートに関する設定を示す。<br> <br> <center> {| class="wikitable" |+ Node.jsでのESMサポートに関する設定 ! 設定 !! 説明 |- | .mjs拡張子 || ファイルをESMとして扱う。 |- | .cjs拡張子 || ファイルをCommonJSとして扱う。 |- | package.jsonファイルへの <code>"type": "module"</code> の指定 || ディレクトリ内の <u>.js拡張子</u> のファイルをESMとして扱う。 |- | Node.js v22以降 || CommonJSモジュールからESMを <code>require()</code> で読み込めるようになった。 |} </center> <br> Node.jsにおける <code>__dirname</code> の代替方法を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> // ESMでは __dirname が使用できないため、import.meta.url で代替する import { fileURLToPath } from 'url'; import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); console.log(__dirname); // 現在のファイルが存在するディレクトリのパス </syntaxhighlight> <br><br> == 関連情報 == * [[JavaScriptの基礎 - クラス]] * [[JavaScriptの基礎 - 関数宣言と関数式]] * [[JavaScriptの基礎 - パッケージ管理]] <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:Web]]
JavaScriptの基礎 - ESモジュール
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse