前言
本文主要分享配置加载静态资源的几种方式,主要结合慕课专栏以及极客时间的相关专栏。
图片加载方式
地址
线上地址
如果是比较固定的资源,可以直接使用线上地址,或者用上传工具上传到一个公共资源的地址,然后固定使用,比如图片可以这样。
备注:这种的缺点也比较明显,文件的地址不便识别,不方便更新,当我们需要更新时,要手动上传,然后得到其最新地址再覆盖更新,在多个图片有替换需求时,这个操作比较不方便。
<img src="http://s.bxstatic.com/foo/bar.png" />
相对地址
但一般情况下还是相对地址更常见,我们一般都是将图片分两种情况存放,一种是就近存放,还有一种是按照静态资源的方式,都存储到assets目录下。
.bg-img {background: url(./foo/bar.png) no-repeat;}.bg-img {background: url(../../assets/foo/bar.png) no-repeat;}
问题出现在当使用assets目录的时候,实际上与当前使用的地址的相对关系不方便查找,但其从项目根路径位置查找是方便的,而且是固定的,因此我们可以使用别名来提升这一使用的效率。
// webpack.confg.js
module.exports = {
resolve: {
alias: {
'@assets': path.resolve('./src/assets')
}
}
};
这样配置的别名,不但在css,js,在html中也是可以使用的。
<img src="@assets/foo/bar.png" />
提示:特别注意的是在html以及css中使用别名,可能要增加~,否则可能找不到对应资源
loader配置
如何让webpack识别这类资源呢?在module中增加对应的loader配置即可。这里有两个 loader 可以使用:file-loader和url-loader。file-loader和url-loader是经常在一些 Webpack 配置中看到的两个 loader,并且两个 loader 在一定应用场景上是可以相互替代的,但是对于两者的区别,很少有人能够说得清楚,下面介绍下两者的区别。
file-loader:能够根据配置项复制使用到的资源(不局限于图片)到构建之后的文件夹,并且能够更改对应的链接;url-loader:包含 file-loader 的全部功能,并且能够根据配置将符合配置的文件转换成 Base64 方式引入,将小体积的图片 Base64 引入项目可以减少 http 请求,也是一个前端常用的优化方式。
下面以url-loader为例说明下 Webpack 中使用方法。首先是安装对应的 loader:npm install -D url-loader。
// webpack.config.js
const HTMLPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
devtool: false,
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: {
loader: 'url-loader'
}
}
]
},
plugins: [
new HTMLPlugin({
template: './src/index.html'
})
]
};
打包之后,发现图片被默认转成base64了,虽然减少了资源请求,但是这个转变之后的体积可能在容许之外,所以我们对其转为base64的配置一个限制大小,超出这个大小,就不会变为base64的地址。
{
test: /\.(png|svg|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 3*1024 // 3k
}
}
}
特殊的svg-loader
svg-url-loader 的工作原理类似于 url-loader,除了它利用 URL encoding 而不是 Base64 对文件编码。对于 SVG 图片这是有效的,因为 SVG 文件恰好是纯文本,这种编码规模效应更加明显,使用方法如下:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
loader: 'svg-url-loader',
options: {
// 小于 10kB(10240字节)的内联文件
limit: 10 * 1024,
// 移除 url 中的引号
// (在大多数情况下它们都不是必要的)
noquotes: true
}
}
]
}
};
Tips:svg-url-loader 拥有改善 IE 浏览器支持的选项,但是在其他浏览器中更糟糕。如果你需要兼容 IE 浏览器,设置
iesafe: true选项。
配置cdn
一般静态资源上线的时候都会放到 CDN,假设我们的 CDN 域名和路径为:http://bd.bxstatic.com/img/,这时候只需要修改output.publicPath即可:
module.exports = {
//..
output: {
publicPath: 'http://bd.bxstatic.com/img/'
}
//..
};
修改后执行webpack打包后的结果如下:
<body>
<img src="http://bd.bxstatic.com/img/ad19429dc9b3ac2745c760bb1f460892.png" alt="背景图" />
<script src="http://bd.bxstatic.com/img/main.js"></script>
</body>
说明 Webpack 为我们自动替换了路径,并且加上了 CDN 域名。
图片优化
image-webpack-loader
在 Webpack 中可以借助img-webpack-loader来对使用到的图片进行优化。它支持 JPG、PNG、GIF 和 SVG 格式的图片,因此我们在碰到所有这些类型的图片都会使用它。
# 安装
npm install image-webpack-loader --save-dev
image-webpack-loader这个 loader 不能将图片嵌入应用,所以它必须和 url-loader 以及 svg-url-loader 一起使用。为了避免同时将它复制粘贴到两个规则中(一个针对 JPG/PNG/GIF 图片, 另一个针对 SVG ),我们使用 enforce: 'pre' 作为单独的规则涵盖在这个 loader:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'image-webpack-loader',
// 这会应用该 loader,在其它之前
enforce: 'pre'
}
]
}
};
通过enforce: 'pre'我们提高了 img-webpack-loader 的优先级,保证在url-loader和svg-url-loader之前就完成了图片的优化。
另外img-webpack-loader默认的配置就已经适用于日常开发图片的压缩优化需求了,但是如果你想更进一步去配置它,参考插件选项。要选择指定选项,请查看国外牛人写的一个图像优化指南。
配置雪碧图
合并图片,减少请求
CSS 使用小图标图片的时候,我们经常做的优化项目是将小图标的图片合并成雪碧图(CSS Sprite),雪碧图的好处是将页面用到的小图片合并到一张大图中,然后使用background-position重新定位,这样节省了 HTTP 的请求数。
在 Webpack 中我们可以借助 PostCSS 来给图片做雪碧图,经过简单的配置之后,生成雪碧图就是全自动的过程了。下面来看看怎么操作。
首先安装 postcss-sprites
npm install postcss-sprites -D
# 如果没有安装 postcss-loader 那么也安装它
npm install postcss-loader -D
然后修改 PostCSS 的postcss.config.js,增加插件的调用:
// postcss.config.js
const postcssSprites = require('postcss-sprites');
module.exports = {
plugins: [
postcssSprites({
// 在这里制定了从哪里加载的图片被主动使用css sprite
// 可以约定好一个目录名称规范,防止全部图片都被处理
spritePath: './src/assets/img/'
})
]
};
然后修改webpack.config.js在css-loader之前配置上postcss-loader(注意 loader 加载顺序,从后往前):
//webpack.config.js
// rules
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader'
}
]
}
好了,下面我们的 CSS 中使用了spritePath: './src/assets/img/'路径的图片就会被处理了。
其他资源
字体,媒体
对于字体、富媒体等静态资源,可以直接使用url-loader或者file-loader进行配置即可,不需要额外的操作,具体配置内容如下:
{
// 文件解析
test: /\.(eot|woff|ttf|woff2|appcache|mp4|pdf)(\?|$)/,
loader: 'file-loader',
query: {
// 这么多文件,ext不同,所以需要使用[ext]
name: 'assets/[name].[hash:7].[ext]'
}
},
数据
如果我们项目需要加载的类似 JSON、CSV、TSV 和 XML 等数据,那么我们需要单独给它们配置相应的 loader。对 JSON 的支持实际上是内置的,类似于 Node.js,这意味着import Data from'./data.json'导入数据默认情况将起作用。要导入 CSV,TSV 和 XML,可以使用csv-loader和xml-loader。
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
{
test: /\.xml$/,
use: [
'xml-loader'
]
}
小结
以上是针对资源的常规加载配置以及优化方式,可以作为常用配置以及优化的兜底方案。
但如果在项目允许范围内,尽量在提供给项目时就比较优质并且合适的资源。
