Webpackの使い方と共通設定
1. Webpackの概念
基本的に、webpack は最新の JavaScript アプリケーション用の静的モジュール バンドラーです。Webpack がアプリケーションを処理するとき、Webpack は1 つ以上のエントリ ポイントから依存関係グラフを内部的に構築し、プロジェクト内で必要な各モジュールを 1 つ以上のバンドルに結合します。バンドルは、コンテンツを披露するための静的リソースです。
v4.0.0 以降、webpack は構成ファイルを導入せずにプロジェクトをパッケージ化できるようになりましたが、依然として高度な構成が可能であり、ニーズを十分に満たすことができます。開始する前に、いくつかの中心的な概念
を理解する必要があります。
- エントリ
- 出力
- ローダ
- プラグイン
- モード
- ブラウザの互換性
- 環境
1.1. エントリー
エントリ ポイントは、 Webpack が内部依存関係グラフを構築するための開始点としてどのモジュールを使用する必要があるかを示します。エントリ ポイントを入力すると、webpack はどのモジュールとライブラリがエントリ ポイント (直接および間接) の依存関係であるかを調べます。
デフォルトは ./src/index.js ですが、Webpack 設定のエントリ プロパティを設定することで 1 つ (または複数) の異なるエントリ ポイントを指定できます。例えば:
webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js',
};
1.2、出力(出力)
Output属性は、Webpack が作成するバンドルをどこに出力するかを指示します。これらのファイルに名前を付ける方法についても説明します。メイン出力ファイルのデフォルトは「./dist/main.js」で、その他の生成されたファイルはデフォルトで「./dist.js」フォルダーに配置されます。
構成で出力フィールドを指定することで、これらのプロセスを構成できます。
webpack.config.js
const path = require('path')
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'), // bundle生成(emit)到哪里
filename: 'my-first-webpack.bundle.js', // 告诉webpack bundle的名称
……
}
}
1.3、ローダー
webpack は JavaScript と JSON ファイルのみを理解できます。これは、すぐに使用できる webpack の組み込み機能です。ローダーを使用すると、Webpack が他のタイプのファイルを処理し、有効なファイルに変換できるようになります。レンプレート、アプリケーションによって使用され、依存関係グラフに追加されます。
Warnig
Webpack の強力な機能の 1 つは、他のパッカーやエグゼキュータではサポートされていない可能性がある任意のタイプのテンプレート (.css ファイルなど) をインポートできることです。この言語拡張は、開発者がより正確な依存関係グラフを作成できるようにするために必要であると考えています。
大まかに言うと、Webpack 設定では、ローダーには2 つのプロパティがあります。
- テスト属性。どのファイルが変換されるかを識別します。
- 使用変換時にどのローダーを使用するかを定義する属性。
webpack.config.js
moudle.exports = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [{
test:/\.txt$/, use: 'raw-loader'}]
}
}
上記の構成では、単一のモジュール オブジェクトが定義されていますルール属性。test と use という 2 つの必須属性が含まれます。Webpack コンパイラー (コンパイラー) に次の情報を伝えます。
require()/import ステートメントで .txt パスとして解析される場合は、パッケージ化する前に use (use) raw-loader を使用して変換します。
警告
重要: Webpack 設定でルールを定義する場合は、ルールではなく module.rules でルールを定義します。わかりやすくするために、Webpack は正しい方法で実行しないと警告を出します。
警告
正規表現を使用してファイルを照合する場合は、ファイルを引用符で囲まないでください。つまり、/.txt/と '/t ˙ xt/ と '/\.txt/付き' /t˙ xt/' または "/.txt$/" は同じではありません。前者は webpack に .txt で終わるファイルと一致するように指示し、後者は webpack に絶対パス '.txt' を持つ単一のファイルと一致するように指示しますが、これは意図したものではない可能性があります。
1.4、プラグイン(プラグイン)
ローダーは特定の種類のモジュールを変換するために使用されますが、プラグインはより広範囲のタスクを実行するために使用できます。パッケージ化の最適化、リソース管理、環境変数の挿入などが含まれます。
プラグインを使用するには、プラグインを require() して plugins 配列に追加するだけです。ほとんどのプラグインはオプションを通じてカスタマイズできます。構成ファイル内の異なる目的で同じプラグインを複数回使用することもできます。この場合、new 演算子を使用してプラグイン インスタンスを作成する必要があります。
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack') // 用于访问内直插件
module.exports = {
module: [{
test: /\.txt$/, use: 'raw-loader'}],
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'})]
}
上記の例では、html-webpack-plugin はアプリケーションの HTML ファイルを生成し、生成されたすべてのバンドルをこのファイルに自動的に挿入します。
1.5、モード(モード)
mode パラメーターをdevelopmentmemt 、production 、または none のいずれかに設定すると、その環境に対して webpack に組み込まれた最適化を有効にすることができます。デフォルト値は実稼働です。
module.exports = {
mode: 'production',
}
1.6. ブラウザの互換性
Webpack は、ES5 準拠のブラウザをすべてサポートしています (IE8 以下はサポートされていません)。
webpack の import() と require.ensure() には Promise が必要です。古いブラウザをサポートしたい場合は、これらの式を使用する前にポリフィルを事前にロードしてください。
1.7、環境(環境)
Webpack5 は Node.js v10.13.0 以降で動作します
2. エントリーポイント
2.1. 単一エントリ (短縮) 構文
用法:entry: string | [string]
webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js'
}
エントリ属性の単一エントリ構文は、次の短縮形です。
module.exports = {
entry: {
main: './path/to/my/entry/file.js'
}
}
ファイル パスの配列をエントリ属性に渡すこともできます。これにより、いわゆる「マルチメイン エントリ」が作成されます。これは、複数の依存ファイルを一度に挿入し、それらの依存関係を「チャンク」にマップする場合に便利です。
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],
output: {
filename: 'bundle.js',
},
};
2.2、オブジェクト構文
使用法:
entry: {
<entryChunkName> string | [string] } | {
}
module.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js'
}
}
オブジェクトの構文は複雑になる場合があります。ただし、これはアプリケーションでエントリを定義する最もスケーラブルな方法です。
ヒント
「Webpack 構成の拡張性」は、これらの構成を再利用したり、他の構成と組み合わせたりできることを意味します。これは、環境、ビルド ターゲット、およびランタイムから懸念事項を分離するための一般的な手法です。これらは、webpack-merge などの特殊なツールを使用してマージされます。
「ヒント」
プラグインを通じてエントリを生成する場合、空のオブジェクト {} をエントリに渡すことができます。
2.2.1. エントリを記述するオブジェクト
エントリを説明するために使用されるオブジェクト。次のプロパティを使用できます。
- dependOn: 現在のエントリが依存するエントリ。これらは、エントリがロードされる前にロードする必要があります。
- import: 起動時にロードする必要があるモジュール。
- library: 現在のエントリのライブラリを構築するには、ライブラリ オプションを指定します。
- runtime: 実行時のチャンクの名前。設定すると、新しいランタイム チャンクが作成されます。Webpack 5.43.0 以降では、これを false に設定して、新しいランタイム チャンクを回避できます。
- publicPath: このエントリの出力ファイルをブラウザで参照する場合、その出力ファイルのパブリック URL アドレスを指定します。「output.publicPath」を表示します。
runtime と dependOn を同じエントリで使用しないでください。そのため、次の構成は無効であり、エラーがスローされます。module.exports = { entry: { a2: 'dependingfile.js', b2: { dependOn: 'a2', import: './src/app.js' } } }
ランタイムが既存のエントリ名を指すことができないことを確認してください。たとえば、次の構成ではエラーがスローされます。module.exports = { entry: { a2: './a', b2: { runtime: 'x2', dependOn: 'a2', import: './b', }, }, };
さらに、dependOn は循環参照できず、次の例でもエラーが発生します。module.exports = { entry: { a1: './a', b1: { runtime: 'a1', import: './b' } } }
module.exports = { entry: { a3: { import: './a', dependOn: 'b3', }, b3: { import: './b', dependOn: 'a3' } } }
2.3 一般的なシナリオ
いくつかのエントリ構成とその実際の使用例を以下に示します。
2.3.1. アプリとベンダー (サードパーティ ライブラリ) の入り口を分ける
// webpack.config.js
module.exports = {
module.exports = {
entry: {
main: './src/app.js',
vendor: './src/vendor.js',
}
}
}
// webpack.prod.js
module.exports = {
output: {
filename: '[name].[contenthash].bundle.js,
}
}
// webpack.dev.js
module.exports = {
module.exports = {
filename: '[name].bundle.js'
}
}
これは、webpack に 2 つの別々のエントリ ポイントを設定するように指示しています (上記の例のように)。
このようにして、変更されていない必要なライブラリまたはファイル (Bootstrap、JQuery、画像など) を Vendor.js に保存し、別のチャンクにまとめてパッケージ化できます。コンテンツのハッシュは変わらないため、ブラウザーはコンテンツのハッシュを個別にキャッシュできるため、読み込み時間が短縮されます。
ヒント
これは webpack < 4 では推奨されません。通常、ベンダーはエントリ オプションに別のエントリ ポイントとして追加され、(CommonsChunkPlugin と組み合わせて) 単一のファイルにコンパイルされます。
これは webpack 4 では推奨されません。代わりに、optimization.splitChunks オプションを使用してベンダー モジュールとアプリ モジュールを分離し、それらに別個のファイルを作成します。実行の開始点ではないベンダーまたはその他のエントリを作成しないでください。
2.3.2. 複数ページのアプリケーション
module.exports = {
entry: {
pageOne: './src/pageone/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
}
(上の例のように) 3 つの個別の依存関係グラフを想定するように webpack に指示します。
理由: マルチページ アプリケーションでは、サーバーは新しい HTML ドキュメントをクライアントにプルします。ページがこの新しいドキュメントで再ロードされ、リソースが再ダウンロードされます。ただし、これにより、optimization.splitChunks を使用してページ間で共有されるアプリケーション コードのバンドルを作成するなどのことを行う特別な機会が得られます。エントリ ポイントの数が増加したため、マルチページ アプリケーションは、複数のエントリ ポイント間で大量のコード/モジュールを再利用できるため、これらの技術から大きな恩恵を受けることができます。
経験則として、HTML ドキュメントごとにエントリ ポイントを 1 つだけ使用します。
3. 出力
出力オプションを設定して、コンパイルされたファイルをハードディスクに書き込む方法を webpack に指示できます。複数の入力元が存在する場合でも、指定できる出力構成は 1 つだけであることに注意してください。
3.1. 使用方法
Webpack 構成では、出力プロパティの最小要件は、その値をオブジェクトに設定し、出力ファイル名を output.filename として構成することです。
module.exports = {
output: {
filename: 'bundle.js'
}
}
この構成では、単一の Bundle.js ファイルが dist ディレクトリに出力されます。
3.2. 複数のエントリポイント
構成内に複数の「チャンク」が作成される場合 (たとえば、複数のエントリ ポイントを使用するか、CommonsChunkPlugin などのプラグインを使用する場合)、置換を使用して各ファイルが一意の名前を持つようにする必要があります。
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
// 写入到硬盘:./dist/app.js, ./dist/search.js
3.3 高度な高度
CDN とリソースのハッシュを使用した複雑な例を次に示します:
config.js
module.exports = {
output: {
path: '/home/proj/cdn/assets/[fullhash]',
publicPath: 'https://cdn.example.com/assets/[fullhash]'
}
}
コンパイル時に最終出力ファイルの publicPath アドレスがわからない場合は、空白のままにし、実行時にエントリ ポイント ファイルの __webpack_public_path__ を通じて動的に設定できます。
__webpack_public_path__ = myRuntimePublicPath
4、ローダー
ローダーは、モジュールのソース コードを変換するために使用されます。ローダーを使用すると、モジュールをインポートまたは「ロード」するときにファイルを前処理できます。したがって、ローダーは他のビルド ツールの「タスク」に似ており、フロントエンドのビルド ステップを処理する強力な方法を提供します。ローダーは、さまざまな言語 (TypeScript など) のファイルを JavaScript に変換したり、インライン画像をデータ URL に変換したりできます。ローダーを使用すると、CSS ファイルを JavaScript テンプレートに直接インポートすることもできます。
4.1. 例
たとえば、ローダーを使用して、webpack に CSS ファイルをロードするように指示したり、TypeScript を JavaScript に変換したりすることができます。これを行うには、まず対応するローダーをインストールします。
npm install --save-dev css-loader ts-loader
次に、各 .css ファイルに css-loader を使用し、すべての .ts ファイルに ts-loader を使用するように webpack に指示します:
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/, use: 'css-loader'},
{
test: /\.ts$/, use: 'ts-loader'}
]
}
}
4.2. ローダーの使用
アプリケーションでは、ローダーを使用する方法が 2 つあります。
- 設定方法(推奨): webpack.config.js ファイルでローダーを指定します。
- インラインメソッド: 各 import ステートメントで指定されたローダーを表示します。
ローダーは webpack v4 では CLI 経由で利用できましたが、webpack v5 では非推奨になっていることに注意してください。
4.3、設定
module.rules を使用すると、Webpack 構成で複数のローダーを指定できます。このアプローチはローダーを提示する簡潔な方法であり、コードをクリーンで保守しやすく保つのに役立ちます。同時に、各ローダーの全体的な概要を把握できます。
ローダーは、sass-loader から始まり、css-loader の実行を続け、最後に style-loader で終わるように、右から左に実行されます。
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: [
{
loader: 'style-loader'},
{
loader: 'css-loader',
options: {
modules: true,
}
},
{
loader: 'sass-loader' }
]
}]
}
}
4.4. インラインモード
ローダーは、インポート ステートメントまたはインポート メソッドと同等の参照で指定できます。使用!ローダーをリソースから分離します。各部分は現在のディレクトリの解像度に相当します。
import Styles from 'style-loader!css-loader?modules!./styles.css';
構成内のすべてのローダー、preLoader、postLoader は、インラインインポートステートメントの前に付けることでオーバーライドできます。
- 使用!プレフィックスは、設定されているすべての通常のローダー (通常のローダー) を無効にします。
import Styles from '!style-loader!css-loader?modules!./styles.css'
- 使用!!プレフィックスは、設定されているすべてのローダー (preLoader、loader、postLoader) を無効にします。
import Styles from '!!style-loader!css-loader?modules!./styles.css'
- -! プレフィックスを使用すると、設定されているすべての preLoader とローダーが無効になりますが、postLoader は無効になりません
import Styles from '-!style-loader!css-loader?modules!./styles.css'
オプションでは、? などのクエリ パラメータを渡すことができます。key=value&foo=bar、または ? などの JSON オブジェクト {'キー': '値', 'foo': 'バー'}
ヒント
module.rules をできる限り使用してください。これにより、ソース コード内のボイラープレート コードの量が減り、エラーが発生したときにローダー内でより迅速にデバッグして問題を特定できるようになります。
4.5、ローダー特性
- ローダーはチェーン呼び出しをサポートしています。チェーン内の各ローダーは、処理されたリソースに変換を適用します。一連のチェーンされたローダーは逆の順序で実行されます。チェーン内の最初のローダーは、その結果 (つまり、変換が適用されたリソース) を次のローダーに渡します。最後に、チェーン内の最後のローダーは、webpack が期待する Javascript を返します。
- ローダーは同期または非同期のいずれかになります。
- ローダーは Node.js で実行され、あらゆる操作を実行できます。
- ローダーは、オプション オブジェクトを通じて構成できます (オプションを設定するためのクエリ パラメーターは引き続きサポートされていますが、このメソッドは非推奨になりました)。
- npm モジュールをローダーとしてエクスポートするための一般的な package.json メインに加えて、module.rules のローダー フィールドを使用してモジュールを直接参照することもできます。
- プラグイン (プラグイン) は、ローダーにさらに多くの機能を提供できます。
- ローダーは追加の任意のファイルを生成できます。
ローダーの前処理機能により、JavaScript エコシステムにより多くの機能を提供できます。ユーザーは、圧縮、パッケージ化、言語翻訳 (またはコンパイル)、その他多くの機能などのきめ細かいロジックをより柔軟に導入できるようになりました。
4.6. ローダーを解析する
ローダーは、標準のモジュール解決ルールに従います。ほとんどの場合、ローダーはモジュール パス (通常は npm install、node_modules) からロードされます。
ローダー モジュールは関数としてエクスポートされ、Node.js 互換の Javascript として記述されることが期待されます。通常、npm はローダーの管理に使用されますが、アプリケーション内のファイルをカスタム ローダーとして使用することもできます。規制に従って、ローダーは通常 xxx-loader (例: json-loader) という名前になります。
5、プラグイン
プラグインはWebpack のバックボーンです。Webpack 自体は、 Webpack 構成で使用するのと同じプラグイン システム上に構築されます。
プラグインの目的は、ローダーが達成できないその他のことを解決することです。webpack は、すぐに使える多くのプラグインを提供します。
ヒント
プラグインで webpack-sources パッケージを使用する場合は、永続的なキャッシュ バージョンの競合を避けるために、require('webpack-source') の代わりに require('webpack').source を使用してください。
5.1. 分析
Webpackプラグインは、 apply メソッドを備えた Javascript オブジェクトです。apply メソッドは webpack コンパイラによって呼び出され、コンパイラ オブジェクトはコンパイル ライフサイクル全体を通じてアクセスできます。
ConsoleLogOnBuildWebpackPlugin.js
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('webpack 构建正在启动');
})
}
}
module.exports = ConsoleLogOnBuildwebpackPlugin;
コンパイラフックのタップメソッドの最初のパラメータは、キャメルケースのプラグイン名である必要があります。すべてのフックで再利用できるように、これには定数を使用することをお勧めします。
5.2 使用法
プラグインはパラメータ/オプションを運ぶことができるため、Webpack 設定の plugins プロパティに新しいインスタンスを渡す必要があります。
Webpack の使用状況に応じて、プラグインを使用するさまざまな方法があります。
5.3 設定方法
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack'); // 访问内置的插件
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rule: [
{
test: /\.(js|jsx)$/,
use: 'bable-loader',
}
]
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({
tempalte: './src/index.html'})
]
}
ProgressPlugin は、コンパイル プロセス中に進行状況レポートをカスタマイズするために使用されます。HtmlWebpackPlugin は HTML ファイルを生成し、スクリプトを使用してその中に my-first-webpack.bundle.js という名前の JS ファイルを導入します。
5.4. ノードAPIメソッド
Node API を使用する場合、構成内の plugins 属性を通じてプラグインを渡すこともできます。
some-node-script.js
const webpack = require('webpack'); // 访问webpack运行时(runtime)
const configuration = require('./webpack.config.js')
let compiler = webpack('configuration');
new webpack.ProgressPlugin().apply(compiler)
compiler.run(function(err, stats) {
// ...
})
6. 構成
オンライン構成の例: https://createapp.dev/webpack/no-library–html-webpack-plugin
まったく同じに見える Webpack 構成はほとんどないことに気づいたかもしれません。これは、webpack の設定ファイルが Javascript ファイルであり、webpack 設定オブジェクトがファイル内にエクスポートされるためです。webpack は、この設定で定義されたプロパティに従って処理します。
webpack は Commonjs テンプレート仕様に従っているため、構成で使用できます。
- require(...) を通じて他のファイルを導入する
- npm によって require(…) を通じてダウンロードされたユーティリティ関数を使用します。
- ? などの Javascript 制御フロー式を使用します。: 演算子
- 値に定数または変数の代入を使用する
- 関数を作成して実行して部分構成を生成する
適切なシナリオでこれらの機能を使用してください。
技術的には可能ですが、次のことは避けてください。
- webpack CLI ツールを使用する場合は、CLI 引数にアクセスします (代わりに独自の CLI ツールを作成するか、--dev を使用する必要があります)
- 不確定な結果をエクスポートします (webpack を 2 回呼び出すと、同じ出力ファイルが生成されます)
- 長い構成を作成します (構成ファイルは複数に分割する必要があります)
ヒント
このドキュメントから得られる最も重要な点は、Webpack 設定にはさまざまなスタイルとフレーバーを含めることができるということです。重要なのは、これらの構成を保守しやすく理解しやすくするには、チーム内で一貫性を保つ必要があるということです。
次の例では、Webpack 構成をどのように表現し、柔軟に構成できるかを示しています。これは主に、構成がコードであるという事実によるものです。
6.1. 基本構成
webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'foo.bundle.js',
}
}
6.2、複数のターゲット
単一の構成をオブジェクト、関数、または Promise としてエクスポートするだけでなく、複数の構成としてエクスポートすることもできます。
6.3. 他の設定言語の使用
Webpack は、さまざまなプログラミングおよびデータ言語で記述された構成ファイルをサポートします。
7. モジュール
モジュール型プログラミングでは、開発者はプログラムを機能的に個別のチャンクに分解し、これをモジュールと呼びます。
各モジュールのサイズは完全なプログラムよりも小さいため、検証、デバッグ、テストが簡単になります。適切に作成されたモジュールは、確実な抽象化とカプセル化の境界を提供するため、アプリケーション内の各モジュールは一貫した設計と明確な目的を持つようになります。
Node.js は当初からモジュール型プログラミングをサポートしていました。ただし、Web のモジュール化は徐々にサポートされています。Web の世界には Javascript のモジュール化をサポートするさまざまなツールがあり、これらのツールにはそれぞれ利点と制限があります。Webpack はこれらのシステムから学んだ教訓を活かし、モジュールの概念をプロジェクト内のあらゆるファイルに適用します。
7.1. Webpack モジュールとは
Node.js モジュールと比較して、webpack モジュールはさまざまな方法で依存関係を表現できます。ここではいくつかの例を示します。
- ES2015 インポート ステートメント
- CommonJS require() ステートメント
- AMDのdefineステートメントとrequireステートメント
- css/sass/less ファイルの @import ステートメント
- stylesheet url(…) または HTML img src=… ファイル内の画像へのリンク。
7.2. サポートされるモジュールの種類
Webpack は、次のモジュール タイプをネイティブにサポートします。
- ECMAScript モジュール
- CommonJS モジュール
- AMDモジュール
- 資産
- WebAssembly モジュール
ローダーを通じて、webpack は複数の言語とプリプロセッサ構文で書かれたモジュールをサポートできます。ローダーは、非ネイティブ モジュールの処理方法を Webpack に記述し、関連する依存関係をバンドルに導入します。webpack コミュニティは、次のようなさまざまな一般的な言語およびプリプロセッサ用のローダーを作成しました。
- コーヒースクリプト
- TypeScript
- ESNext(ベイブル)
- サス
- 以下
- スタイラス
- エルム
- …
全体として、webpack は、開発、テスト、運用環境での非侵入的なワークフローをサポートしながら、あらゆるテクノロジー スタックでの使用を可能にする、カスタマイズ可能で強力かつ豊富な API を提供します。
8. モジュールの解像度
solver は、モジュールの絶対パスを検索するのに役立つライブラリです。次のように、モジュールを別のモジュールの依存モジュールとして使用し、後者から参照できます。
import foo from 'path/to/module';
// 或者
require('path/to/module')
依存モジュールは、アプリケーションまたはサードパーティ ライブラリのコードにすることができます。リゾルバーは、webpack が各 require/import ステートメントからバンドルに導入する必要があるモジュール コードを見つけるのに役立ちます。モジュールをバンドルするとき、webpack は拡張解像度を使用してファイル パスを解決します。
8.1. Webpack での解析ルール
拡張解像度を使用すると、webpack は 3 つのファイル パスを解決できます:
絶対パス
import '/home/me/file';
import 'c:\\Users\\me\\file';
ファイルの絶対パスが取得されているため、それ以上の解析は必要ありません。
相対パス
import '../src/file1';
import './file2';
この場合、importまたはrequireを使用したソースファイルが存在するディレクトリがコンテキストディレクトリとみなされ、import/requireで指定された相対パスがこのコンテキストパスと結合されてモジュールの絶対パスが生成されます。
モジュールパス
import 'module';
import 'module/lib/file';
solve.modules で指定されたすべてのディレクトリ内のモジュールを取得します。エイリアスを設定することで初期モジュール パスを置き換えることができます。詳細については、resolve.alias 設定オプションを参照してください。
- パッケージに package.json ファイルが含まれている場合、resolve.exportsFields 構成オプションで指定されたフィールドが順番に検索され、package.json の最初のフィールドで、パッケージのエクスポート仕様に従ってパッケージで使用可能なエクスポートが確認されます。
上記のルールに従ってパスが解決されると、リゾルバーはパスがファイルを指しているかフォルダーを指しているかを確認します。パスがファイルを指している場合:
- ファイルに拡張子がある場合、ファイルは直接パックされます。
- それ以外の場合、ファイル拡張子は、どの拡張子が受け入れられるかをパーサーに指示するresolve.extensionsオプションを使用して解決されます(例: .js、.jsx)。
パスがフォルダーを指している場合は、次の手順に従って正しい拡張子を持つファイルを見つけます。
- フォルダーに package.json ファイルが含まれている場合、resolve.mainFields 構成のフィールド順序に従ってファイルが検索され
、構成要件を満たす package.json 内の最初のフィールドに従ってファイル パスが決定されます。 - package.json ファイルがないか、resolve.mainFields が有効なパスを返さない場合は、resolve.mainFiles 構成オプションで指定されたファイル名の順序に従って検索し、import/ ファイル内で既存のファイル名が一致するかどうかを確認します。ディレクトリが必要です。
- ファイル拡張子は、resolve.extensions オプションを使用して同様の方法で解決されます。
Webpack は、ビルド ターゲットに応じて、これらのオプションに適切なデフォルトを提供します。
8.2. ローダーの解析
ローダーの解析ルールも特定の仕様に従います。ただし、resolveLoader 構成アイテムでは、ローダーに独立した解析ルールを設定できます。
8.3. キャッシュ
ファイルへのすべてのファイルシステム アクセスはキャッシュされるため、同じファイルに対する複数の並列または直列リクエストをより高速に実行できます。監視モードでは、変更されたファイルのみがキャッシュから削除されます。監視モードがオフになっている場合、キャッシュは各コンパイルの前にクリアされます。
9、モジュールフェデレーション
9.1. 動機
複数の独立したビルドでアプリケーションを構成できます。これらの独立したビルド間に依存関係があってはなりません。そのため、独立して開発およびデプロイできます。
9.2、基礎となる概念
ローカル モジュールとリモート モジュールを区別します。ローカル モジュールは、現在のビルドの一部である通常のモジュールです。リモート モジュールは現在のビルドの一部ではなく、実行時にいわゆるコンテナからロードされます。
リモート モジュールのロードは非同期操作とみなされます。リモート モジュールを使用する場合、これらの非同期操作は、リモート モジュールとエントリの間の次のチャンクのロード操作に配置されます。リモート モジュールは、チャンク ロード操作なしでは使用できません。
チャンクのロードは通常、import() を呼び出すことによって行われますが、require.ensure や require([…]) サブクラスなどの古い構文もサポートされています。
コンテナは、特定のモジュールへの非同期アクセスを公開するコンテナ エントリを使用して作成されます。公開アクセスは 2 つのステップに分かれています。
- モジュールをロードします (非同期)
- モジュールの実行 (同期)
ステップ 1 はチャンクのロード中に実行されます。ステップ 2 は、他の (ローカルおよびリモート) モジュールとのインターリーブ実行中に実行されます。こうすることで、実行順序は、ローカルからリモート、またはリモートからローカルへのモジュールの変換の影響を受けません。
コンテナはネストでき、コンテナは他のコンテナのモジュールを使用できます。コンテナー間に循環依存関係が存在する場合もあります。
9.3 高度な概念
各ビルドはコンテナーとして機能し、他のビルドをコンテナーとして含めることもできます。このようにして、各ビルドは、対応するコンテナーからモジュールをロードすることによって、他のコンテナーによって公開されるモジュールにアクセスできます。
共有モジュールは、書き換え可能であり、ネストされたコンテナーへの書き換えを提供するモジュールです。これらは通常、同じライブラリなど、各ビルドの同じモジュールを指します。
packageName オプションを使用すると、パッケージ名を設定して必要なバージョンを見つけることができます。デフォルトでは、モジュールリクエストは自動的に推論されます。自動推論を無効にしたい場合は、requiredVersion を false に設定してください。
9.4. ビルディングブロック
ContainerPlugin (低レベル)
このプラグインは、指定されたパブリック モジュールを使用して追加のコンテナ エントリを作成します。
ContainerReferencePlugin (低レベル)
このプラグインは、コンテナに外部として特定の参照を追加し、これらのコンテナからリモート モジュールをインポートできるようにします。また、これらのコンテナーのオーバーライド API を呼び出してオーバーロードを提供し (ビルドもコンテナーである場合は __webpack__override__ またはオーバーライド API を介して)、指定されたオーバーロードが参照されるすべてのコンテナーに提供されます。
ModuleFederationPlugin(高レベル)
ModuleFederation は ContainerPlugin と ContainerReferencePlugin を組み合わせたものです。
9.5. 概念的な目標
- Webpack でサポートされている任意のモジュール タイプを公開および使用できます。
- チャンクロードでは、必要なものすべてを並行してロードする必要があります (Web: サーバーへの 1 往復)。
- ユーザーからコンテナへの制御
- モジュールの書き換えは一方向の操作です
- 兄弟コンテナは互いのモジュールをオーバーライドできません
- コンセプトは環境に関係なく適用されます
- Web、Node.jsなどで利用可能。
- 株式の相対リクエストと絶対リクエスト
- 使用されない場合でも常に提供されます
- config.context への相対パスを解決します。
- requiredVersion はデフォルトでは使用されません
- 共有のモジュールリクエスト
- 使用時のみ利用可能
- ビルドで使用されるすべての同等のモジュールリクエストと一致します
- 一致するすべてのモジュールを提供します
- requiredVersion は、図のこの場所にある package.json から抽出されます。
- ネストされたnode_modulesがある場合、複数の異なるバージョンを提供して使用できます。
- 共有内の末尾に / があるモジュール リクエストは、このプレフィックスを持つすべてのモジュール リクエストと一致します。
9.6. 使用例
各ページは個別に構築される
シングル ページ アプリケーションの各ページは、個別のビルドでコンテナから公開されます。メイン アプリケーション (アプリケーション シェル) も独立して構築され、すべてのページをリモート モジュールとして参照します。このようにして、各ページを個別に展開できます。メイン アプリケーションは、ルートが更新されるか、新しいルートが追加されるときにデプロイされます。メイン アプリケーションは、ページ構築時の重複を避けるために、共通ライブラリを共有モジュールとして定義します。
コンテナとしてのコンポーネント ライブラリ
多くのアプリケーションは、すべてのコンポーネントを公開するコンテナとして構築できる共通のコンポーネント ライブラリを共有します。各アプリケーションは、コンポーネント ライブラリ コンテナーのコンポーネントを使用します。コンポーネント ライブラリへの変更は、すべてのアプリケーションを再デプロイしなくても、個別にデプロイできます。アプリケーションは、コンポーネント ライブラリの最新バージョンを自動的に使用します。
動的リモート コンテナ コンテナ
インターフェイスは、get メソッドと init メソッドをサポートします。init は非同期互換のメソッドであり、呼び出されたときに含まれるパラメータは共有スコープ オブジェクト 1 つだけです。このオブジェクトはリモート コンテナーの共有スコープとして使用され、ホストによって提供されるモジュールによって設定されます。これを使用すると、実行時にリモート コンテナをホスト コンテナに動的に接続できます。
(async () => {
// 初始化共享作用域(shared scope)用提供的已知此构建和所有远程的模块填充它
await __webpack_init_sharing__('default');
const container = window.someContainer; // 或从其他地方获取容器
// 初始化容器 它可能提供共享模块
await container.init(__webpack_share_scopes__.default);
const module = await container.get('./module');
})();
コンテナーは共有モジュールを提供しようとしますが、共有モジュールがすでに使用されている場合は警告し、提供された共有モジュールを無視します。コンテナはこれをダウングレード モジュールとして引き続き使用できます。
共有モジュールのさまざまなバージョンを動的にロードすることで、A/B テストを実装できます。
ヒント
リモート コンテナに動的に接続する前に、コンテナがロードされていることを確認してください。
例:
init.js
function loadComponent(scope, module) {
return async () => {
// 初始化共享作用域(shared scope)用提供的已知此构建和所有远程的模块填充它
await __webpack_init_sharing__('default');
const container = window[scope]; // 或从其他地方获取容器
// 初始化容器 它可能提供共享模块
await container.init(__webpack_share_scopes__.default);
const factory = await window[scope].get(module);
const Module = factory();
return Module;
};
}
loadComponent('abtests', 'test123');
9.7、Promise に基づく動的リモート
一般に、リモートは URL を使用して設定されます。例は次のとおりです。
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: ''
}
})
]
}
ただし、実行時に呼び出されるプロミスをリモートに渡すこともできます。この Promise は、上記の get/init インターフェイスに準拠するテンプレートを使用して呼び出す必要があります。たとえば、使用するフェデレーション モジュールのバージョンを渡したい場合は、クエリ パラメーターを介して何かを行うことができます。
9.8. 動的パブリックパス
publicPath を設定するホスト API を提供すると、
ホストはリモート モジュールのメソッドを公開することで、実行時にリモート モジュールの publicPath を設定できるようになります。
この方法は、個別にデプロイされたサブアプリケーションをホスト ドメインのサブパスにマウントする場合に特に便利です。
シナリオ:
https://my-host.com/app/* にホスト アプリがあり、https://foo-app.com にサブアプリがあります。サブアプリもホスト ドメインにマウントされるため、https://my-host.com/app/foo-app および https://my-host.com 経由で https://foo-app.com にアクセスできます。 /app/foo-app/* はプロキシ経由で https://foo-app.com/* にリダイレクトできます。
例:
webpack.config.js (リモート)
module.exports = {
entry: {
remote: './public-path',
},
plugins: [
new ModuleFederationPlugin({
name: 'remote', // 该名称必须与入口名称相匹配
exposes: ['./public-path'],
// ...
}),
],
};
public-path.js (リモート)
export function set(value) {
__webpack_public_path__ = value;
}
src/index.js (ホスト)
const publicPath = await import('remote/public-path');
publicPath.set('/your-public-path');
//bootstrap app e.g. import('./bootstrap.js')