アセットモジュールを使用すると、追加のローダーを構成することなく、アセットファイル(フォント、アイコンなど)を使用できます。
webpack 5より前は、一般的に使用されていました。
raw-loader
は、ファイルを文字列としてインポートしますurl-loader
は、ファイルをデータURIとしてバンドルにインライン化しますfile-loader
は、ファイルを出力ディレクトリに排出しますアセットモジュールタイプは、4つの新しいモジュールタイプを追加することで、これらのすべてのローダーを置き換えます
asset/resource
は、別のファイルを排出し、URLをエクスポートします。以前は、file-loader
を使用することで実現できました。asset/inline
は、アセットのデータURIをエクスポートします。以前は、url-loader
を使用することで実現できました。asset/source
は、アセットのソースコードをエクスポートします。以前は、raw-loader
を使用することで実現できました。asset
は、データURIのエクスポートと別のファイルの排出の間で自動的に選択します。以前は、アセットサイズ制限付きのurl-loader
を使用することで実現できました。webpack 5で、古いアセットローダー(つまり、file-loader
/url-loader
/raw-loader
)をアセットモジュールと一緒に使用すると、アセットの重複につながるため、アセットモジュールがアセットを再び処理しないようにする必要があります。これは、アセットのモジュールタイプを'javascript/auto'
に設定することで実行できます。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
}
},
],
+ type: 'javascript/auto'
},
]
},
}
新しいURL呼び出しから発生したアセットをアセットローダーから除外するには、ローダー構成にdependency: { not: ['url'] }
を追加します。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
+ dependency: { not: ['url'] },
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
},
},
],
},
],
}
}
デフォルトでは、内部的には、asset
タイプは__webpack_public_path__ + import.meta
を実行します。つまり、構成でoutput.publicPath
を設定すると、asset
がロードされるURLをオーバーライドできます。
コードで__webpack_public_path__
を設定する場合、asset
のロードロジックを壊さないように達成する必要がある方法は、アプリの最初のコードとして実行し、関数を使用しないようにすることです。この例として、publicPath.js
というファイルがあり、コンテンツは次のようになります。
__webpack_public_path__ = 'https://cdn.url.com';
次に、webpack.config.js
でentry
フィールドを次のように更新します。
module.exports = {
entry: ['./publicPath.js', './App.js'],
};
あるいは、webpackの設定を変更せずに、App.js
内で以下のように記述することもできます。唯一の欠点は、ここで順序を強制する必要があり、一部のリンティングツールと衝突する可能性があることです。
import './publicPath.js';
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
+ module: {
+ rules: [
+ {
+ test: /\.png/,
+ type: 'asset/resource'
+ }
+ ]
+ },
};
src/index.js
import mainImage from './images/main.png';
img.src = mainImage; // '/dist/151cfcfa1bd74779aadb.png'
すべての.png
ファイルは出力ディレクトリに出力され、そのパスはバンドルに注入されます。さらに、outputPath
と publicPath
をカスタマイズできます。
デフォルトでは、asset/resource
モジュールは、[hash][ext][query]
というファイル名で出力ディレクトリに出力されます。
このテンプレートは、webpack設定で output.assetModuleFilename
を設定することで変更できます。
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
+ assetModuleFilename: 'images/[hash][ext][query]'
},
module: {
rules: [
{
test: /\.png/,
type: 'asset/resource'
}
]
},
};
出力ファイル名をカスタマイズするもう一つのケースは、特定の種類のアセットを指定されたディレクトリに出力することです。
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
+ assetModuleFilename: 'images/[hash][ext][query]'
},
module: {
rules: [
{
test: /\.png/,
type: 'asset/resource'
- }
+ },
+ {
+ test: /\.html/,
+ type: 'asset/resource',
+ generator: {
+ filename: 'static/[hash][ext][query]'
+ }
+ }
]
},
};
この設定では、すべてのhtml
ファイルが出力ディレクトリ内のstatic
ディレクトリに出力されます。
Rule.generator.filename
は output.assetModuleFilename
と同じで、asset
とasset/resource
のモジュールタイプでのみ機能します。
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
- assetModuleFilename: 'images/[hash][ext][query]'
},
module: {
rules: [
{
- test: /\.png/,
- type: 'asset/resource'
+ test: /\.svg/,
+ type: 'asset/inline'
- },
+ }
- {
- test: /\.html/,
- type: 'asset/resource',
- generator: {
- filename: 'static/[hash][ext][query]'
- }
- }
]
}
};
src/index.js
- import mainImage from './images/main.png';
+ import metroMap from './images/metro.svg';
- img.src = mainImage; // '/dist/151cfcfa1bd74779aadb.png'
+ block.style.background = `url(${metroMap})`; // url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo...vc3ZnPgo=)
すべての.svg
ファイルは、データURIとしてバンドルに注入されます。
デフォルトでは、webpackによって出力されるデータURIは、Base64アルゴリズムを使用してエンコードされたファイルの内容を表します。
カスタムエンコードアルゴリズムを使用したい場合は、ファイルの内容をエンコードするカスタム関数を指定できます。
webpack.config.js
const path = require('path');
+ const svgToMiniDataURI = require('mini-svg-data-uri');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.svg/,
type: 'asset/inline',
+ generator: {
+ dataUrl: content => {
+ content = content.toString();
+ return svgToMiniDataURI(content);
+ }
+ }
}
]
},
};
これで、すべての.svg
ファイルはmini-svg-data-uri
パッケージによってエンコードされます。
webpack.config.js
const path = require('path');
- const svgToMiniDataURI = require('mini-svg-data-uri');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
- test: /\.svg/,
- type: 'asset/inline',
- generator: {
- dataUrl: content => {
- content = content.toString();
- return svgToMiniDataURI(content);
- }
- }
+ test: /\.txt/,
+ type: 'asset/source',
}
]
},
};
src/example.txt
Hello world
src/index.js
- import metroMap from './images/metro.svg';
+ import exampleText from './example.txt';
- block.style.background = `url(${metroMap}); // url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo...vc3ZnPgo=)
+ block.textContent = exampleText; // 'Hello world'
すべての.txt
ファイルは、そのままの状態でバンドルに注入されます。
new URL('./path/to/asset', import.meta.url)
を使用すると、webpackもアセットモジュールを作成します。
src/index.js
const logo = new URL('./logo.svg', import.meta.url);
webpackは設定のtarget
に応じて、上記のコードを異なる結果にコンパイルします。
// target: web
new URL(
__webpack_public_path__ + 'logo.svg',
document.baseURI || self.location.href
);
// target: webworker
new URL(__webpack_public_path__ + 'logo.svg', self.location);
// target: node, node-webkit, nwjs, electron-main, electron-renderer, electron-preload, async-node
new URL(
__webpack_public_path__ + 'logo.svg',
require('url').pathToFileUrl(__filename)
);
webpack 5.38.0の時点では、データURLもnew URL()
でサポートされています。
src/index.js
const url = new URL('data:,', import.meta.url);
console.log(url.href === 'data:,');
console.log(url.protocol === 'data:');
console.log(url.pathname === ',');
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
+ test: /\.txt/,
+ type: 'asset',
}
]
},
};
webpackはデフォルトの条件に従って、resource
とinline
を自動的に選択するようになります。8kb未満のサイズのファイルはinline
モジュールタイプとして扱われ、それ以外の場合はresource
モジュールタイプとして扱われます。
この条件は、webpack設定のモジュールルールレベルでRule.parser.dataUrlCondition.maxSize
オプションを設定することで変更できます。
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.txt/,
type: 'asset',
+ parser: {
+ dataUrlCondition: {
+ maxSize: 4 * 1024 // 4kb
+ }
+ }
}
]
},
};
また、モジュールをインライン化するかどうかを決定するために、関数を指定することもできます。
アセットモジュールとWebpack 5以前は、上記のレガシーローダーでインライン構文を使用することができました。
現在は、すべてのインラインローダー構文を削除し、インライン構文の機能を模倣するためにresourceQuery条件を使用することが推奨されています。
たとえば、raw-loader
をasset/source
タイプに置き換える場合
- import myModule from 'raw-loader!my-module';
+ import myModule from 'my-module?raw';
webpackの設定では
module: {
rules: [
// ...
+ {
+ resourceQuery: /raw/,
+ type: 'asset/source',
+ }
]
},
他のローダーによる処理からrawアセットを除外したい場合は、否定条件を使用します。
module: {
rules: [
// ...
+ {
+ test: /\.m?js$/,
+ resourceQuery: { not: [/raw/] },
+ use: [ ... ]
+ },
{
resourceQuery: /raw/,
type: 'asset/source',
}
]
},
または、ルールのoneOf
リストを使用します。ここでは、最初に一致するルールのみが適用されます。
module: {
rules: [
// ...
+ { oneOf: [
{
resourceQuery: /raw/,
type: 'asset/source',
},
+ {
+ test: /\.m?js$/,
+ use: [ ... ]
+ },
+ ] }
]
},
サーバーサイドレンダリングのようなユースケースでは、アセットの出力を無効にしたい場合があります。これは、Rule.generator
のemit
オプションで実現できます。
module.exports = {
// …
module: {
rules: [
{
test: /\.png$/i,
type: 'asset/resource',
generator: {
emit: false,
},
},
],
},
};