资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。
在 webpack 5 之前,通常使用:
-
raw-loader
将文件导入为字符串 -
url-loader
将文件作为 data URI 内联到 bundle 中 -
file-loader
将文件发送到输出目录
资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:
-
asset/resource
发送一个单独的文件并导出 URL。之前通过使用 file-loader
实现。 -
asset/inline
导出一个资源的 data URI。之前通过使用 url-loader
实现。 -
asset/source
导出资源的源代码。之前通过使用 raw-loader
实现。 -
asset
在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader
,并且配置资源体积限制实现。
当在 webpack 5 中使用旧的 assets loader(如 file-loader
/url-loader
/raw-loader
等)和 asset 模块时,你可能想停止当前 asset 模块的处理,并再次启动处理,这可能会导致 asset 重复,你可以通过将 asset 模块的类型设置为 javascript/auto
来解决。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /.(png|jpg|gif)$/i,
use: [
{
loader: url-loader,
options: {
limit: 8192,
}
},
],
+ type: javascript/auto
},
]
},
}
如需从 asset loader 中排除来自新 URL 处理的 asset,请添加 dependency: { not: [url] }
到 loader 配置中。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /.(png|jpg|gif)$/i,
+ dependency: { not: [url] },
use: [
{
loader: url-loader,
options: {
limit: 8192,
},
},
],
},
],
}
}
Resource 资源
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
文件都将被发送到输出目录,并且其路径将被注入到 bundle 中,除此之外,你可以为它们自定义 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
模块类型。
inline 资源(inlining asset)
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
文件都将作为 data URI 注入到 bundle 中。
自定义 data URI 生成器
webpack 输出的 data 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
包进行编码。
source 资源(source asset)
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 文件将原样注入到 bundle 中。
URL 资源
当使用 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 起,Data URLs 也支持在 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 配置的 module rule 层级中,设置 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
+ }
+ }
}
]
},
};
还可以 指定一个函数 来决定是否 inline 模块。
变更内联 loader 的语法
在 asset 模块和 webpack 5 之前,可以使用内联语法与上述传统的 loader 结合使用。
现在建议去掉所有的内联 loader 的语法,使用资源查询条件来模仿内联语法的功能。
示例,将 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,
+ }
]
},
如果你想把原始资源排除在其他 loader 的处理范围以外,请使用使用取反的正则:
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,
},
},
],
},
};
Further Reading
作者:admin,如若转载,请注明出处:https://www.web176.com/webpack/22679.html