資源模組允許使用資源檔案(字型、圖示等),而無需設定其他載入器。
在 webpack 5 之前,通常使用
raw-loader
將檔案匯入為字串url-loader
將檔案內嵌到套件中,作為資料 URIfile-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'],
};
或者,您可以在您的 App.js
中執行下列動作,而無需修改您的 webpack 組態。唯一的缺點是您必須在此強制執行順序,而這可能會與某些程式碼檢查工具發生衝突。
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);
根據設定中的 target
,webpack 會將上述程式碼編譯成不同的結果
// 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 條件來模擬內嵌語法的功能。
例如,在用 asset/source
類型取代 raw-loader
的情況下
- import myModule from 'raw-loader!my-module';
+ import myModule from 'my-module?raw';
以及在 webpack 組態中
module: {
rules: [
// ...
+ {
+ resourceQuery: /raw/,
+ type: 'asset/source',
+ }
]
},
如果您想排除未處理的原始資產由其他載入器處理,請使用否定條件
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,
},
},
],
},
};