图片处理
本节来学习,如何在webpack中使用图片,并且能够让webpack打包图片。
实现图片的加载
图片的引用方式一般有三种
- 在js中创建图片来引入
- 在css中引入,比如 background('url')
- 在html中使用img标签引用,比如
<img src='xxx' alt=''>
在js中创建图片
修改index.js,先尝试通过字符串引用,是不会生效的
// webpack-dev-1\src\index.js
// 在js中创建图片来引用
let image = new Image()
image.src = './logo.png' // 如果直接通过字符串引用,是没有效果的
// 也会被看成是个字符串
document.body.appendChild(image)
我们可以打包看看一下效果
并没有真正的引用这张图片。因为图片并没有被打包。
如果想要被引用过来,需要有个导入关系,使用require语法,或者import,
再次修改index.js
// webpack-dev-1\src\index.js
import logo from './logo.png'
// 把图片引入,返回结果是一个新的图片地址
// 我们引的这个logo.png,内部发射出来一个新的文件名字,也是一个路径,是以hash戳的命名方式
console.log(logo);
// 在js中创建图片来引用
let image = new Image()
// image.src = './logo.png' // 如果直接通过字符串引用,是没有效果的
// 也会被看成是个字符串
image.src = logo
document.body.appendChild(image)
运行的话,会报错,告诉我们需要一个合适的loader去解析,
安装一下 file-loader,
yarn add file-loader@^3.0.1 -D
file-loader
file-loader的作用是会在内部生成一张新的图片到打包的目录中,然后把生成的图片名字返回过来。
修改配置文件
// webpack-dev-1\webpack.config.js
// webpack是node写出来的,所以使用node的语法
let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 引入插件
let OptimizeCss = require('optimize-css-assets-webpack-plugin') // 引入插件 压缩css的
let UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 压缩js文件的插件
module.exports = {
// 配置优化项
optimization: {
minimizer: [ // 是一个数组,还得优化js
new UglifyJsPlugin({
cache: true, // 是否用缓存
parallel: true, // 是否并发压缩
sourceMap: true,// 线上用来调试的映射文件
}),
new OptimizeCss(), // 开启优化css后,生产模式css文件也会被压缩,但是必须配置js压缩,如果不配置,js生产模式就不会被压缩了
]
},
devServer: { // 开发服务器的配置
port: 3000, // 默认端口是8080,这里可以改
progress: true, // 打包时候的进度条
contentBase: './build', // 以哪个文件夹作为服务的根目录
open: true, // 服务启动完毕后,直接打开浏览器
compress: true, // 启动gzip压缩
},
mode: 'development', // 模式,默认两种模式 production 和 development
entry: './src/index.js', // 入口
output: {
filename: 'bundle.js', // 打包后的文件名
path: path.resolve(__dirname, 'build'), // 打包后的路径,必须是一个绝对路径
},
plugins: [ // 是一个数组,放着所有的webpack插件
// 插件是一个类,通过new的方式来引用
new HtmlWebpackPlugin({
template: './src/index.html', // 告诉插件,是以这个目录下的index.html为模板
filename: 'index.html', // 告诉插件,打包后的文件叫什么名字,这里也叫index.html
hash: true, // 引用的时候可以加一个hash戳
}),
// 插件的使用就没有先后顺序了,随便放就行
// 引入抽离css样式的插件,
new MiniCssExtractPlugin({
filename: 'main.css', // 告诉插件,抽离出的样式文件的名字叫什么,这里叫main.css
}),
],
module: { // 模块
rules: [ // 规则,在这里面配置各种loader
{
test: /.(jpg|png|gif)$/, // 处理图片的loader
use: 'file-loader'
},
{
test: /\.js$/, // 匹配以js结尾的文件
use: {
loader: 'babel-loader',
options: { // 用babel-loader 需要把ES6转为ES5
// 配置可以写在这里,还可以写在外面
// 在这里添加一个预设
presets: [ // 这是一个大插件的集合
'@babel/preset-env', // 这个插件就可以把ES6转ES5
],
// 如果有一些预设的属性,需要配置一些小插件来转换还不是标准的js语法
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
['@babel/plugin-proposal-class-properties', { "loose": true }],
"@babel/plugin-transform-runtime"
]
}
},
include: path.resolve(__dirname, 'src'), // 只找src目录下的js 包括
exclude: /node_modules/ // node_modules文件夹下的文件不用找 排除
},
// css-loader 解析css文件,@import语法的
// style-loader 把解析后的css文件 插入到head标签中
// loader有个特点,希望单一,一个loader干一件事
/*
loader的用法
1. 只用字符串,就是只用一个loader
2. 多个loader,需要一个数组 [],数组里可以放字符串,或者对象,对象的话就可以配置loader的参数了
*/
// loader的顺序,默认是从右向左执行,从下往上执行
{
test: /\.css$/,
use: [
// 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
MiniCssExtractPlugin.loader,
'css-loader',
// 应该在解析css之前增加前缀
'postcss-loader',
]
},
{
test: /\.less$/,
use: [
// 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
MiniCssExtractPlugin.loader, // 若果想抽离多个文件,可以在new一个出来,一个抽离css一个抽离less都行
// 这里就用一个了
'css-loader', // 解析 @import语法 解析 css
// 应该在解析css之前增加前缀
'postcss-loader',
'less-loader' // 把less 转换为 css
]
},
],
}
}
我们打包看一下,发现带hash戳的新的图片已经生成到build目录了。
我们运行一下看看,成功了
在css文件中引入图片 background: url('xxx')
我们修改一下index.css文件
/* webpack-dev-1\src\index.css */
.bg-logo {
width: 100px;
height: 100px;
background: url('./logo.png');
}
因为之前我们已经使用过了css-loader,它会自动的将css中的background: url('./logo.png');
这种写法,改为require
的写法,所以最后也能找到打包后的图片。
修改index.html
<body>
<div>内容区域</div>
<div class="bg-logo"></div>
</body>
修改index.js
// webpack-dev-1\src\index.js
import './index.css' // 引入index.css
import logo from './logo.png'
// 把图片引入,返回结果是一个新的图片地址
// 我们引的这个logo.png,内部发射出来一个新的文件名字,也是一个路径,是以hash戳的命名方式
console.log(logo);
// 在js中创建图片来引用
let image = new Image()
// image.src = './logo.png' // 如果直接通过字符串引用,是没有效果的
// 也会被看成是个字符串
image.src = logo
document.body.appendChild(image)
运行一下看下效果,发现是好使的
直接在html中使用img标签引用
修改index.html
<body>
<img src="./logo.png" alt="">
<div>内容区域</div>
<div class="bg-logo"></div>
</body>
这样引的话,最后还是一串字符串,会找不到这个文件
并没有找到,需要另外一个loader,将html页面中的图片链接,也解析成require的形式,
html-withimg-loader
html-withimg-loader是一个中国人写的,就是专门干这件事的,将html页面中的img标签的图片解析成require后的路径。
安装一下
yarn add html-withimg-loader@^0.1.16 -D
修改配置文件,配置一下这个loader
// webpack-dev-1\webpack.config.js
// webpack是node写出来的,所以使用node的语法
let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 引入插件
let OptimizeCss = require('optimize-css-assets-webpack-plugin') // 引入插件 压缩css的
let UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 压缩js文件的插件
module.exports = {
// 配置优化项
optimization: {
minimizer: [ // 是一个数组,还得优化js
new UglifyJsPlugin({
cache: true, // 是否用缓存
parallel: true, // 是否并发压缩
sourceMap: true,// 线上用来调试的映射文件
}),
new OptimizeCss(), // 开启优化css后,生产模式css文件也会被压缩,但是必须配置js压缩,如果不配置,js生产模式就不会被压缩了
]
},
devServer: { // 开发服务器的配置
port: 3000, // 默认端口是8080,这里可以改
progress: true, // 打包时候的进度条
contentBase: './build', // 以哪个文件夹作为服务的根目录
open: true, // 服务启动完毕后,直接打开浏览器
compress: true, // 启动gzip压缩
},
mode: 'development', // 模式,默认两种模式 production 和 development
entry: './src/index.js', // 入口
output: {
filename: 'bundle.js', // 打包后的文件名
path: path.resolve(__dirname, 'build'), // 打包后的路径,必须是一个绝对路径
},
plugins: [ // 是一个数组,放着所有的webpack插件
// 插件是一个类,通过new的方式来引用
new HtmlWebpackPlugin({
template: './src/index.html', // 告诉插件,是以这个目录下的index.html为模板
filename: 'index.html', // 告诉插件,打包后的文件叫什么名字,这里也叫index.html
hash: true, // 引用的时候可以加一个hash戳
}),
// 插件的使用就没有先后顺序了,随便放就行
// 引入抽离css样式的插件,
new MiniCssExtractPlugin({
filename: 'main.css', // 告诉插件,抽离出的样式文件的名字叫什么,这里叫main.css
}),
],
module: { // 模块
rules: [ // 规则,在这里面配置各种loader
{
test: /\.html$/, // 解析html中的img标签图片路径
use: 'html-withimg-loader'
},
{
test: /.(jpg|png|gif)$/, // 处理图片的loader
use: 'file-loader'
},
{
test: /\.js$/, // 匹配以js结尾的文件
use: {
loader: 'babel-loader',
options: { // 用babel-loader 需要把ES6转为ES5
// 配置可以写在这里,还可以写在外面
// 在这里添加一个预设
presets: [ // 这是一个大插件的集合
'@babel/preset-env', // 这个插件就可以把ES6转ES5
],
// 如果有一些预设的属性,需要配置一些小插件来转换还不是标准的js语法
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
['@babel/plugin-proposal-class-properties', { "loose": true }],
"@babel/plugin-transform-runtime"
]
}
},
include: path.resolve(__dirname, 'src'), // 只找src目录下的js 包括
exclude: /node_modules/ // node_modules文件夹下的文件不用找 排除
},
// css-loader 解析css文件,@import语法的
// style-loader 把解析后的css文件 插入到head标签中
// loader有个特点,希望单一,一个loader干一件事
/*
loader的用法
1. 只用字符串,就是只用一个loader
2. 多个loader,需要一个数组 [],数组里可以放字符串,或者对象,对象的话就可以配置loader的参数了
*/
// loader的顺序,默认是从右向左执行,从下往上执行
{
test: /\.css$/,
use: [
// 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
MiniCssExtractPlugin.loader,
'css-loader',
// 应该在解析css之前增加前缀
'postcss-loader',
]
},
{
test: /\.less$/,
use: [
// 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
MiniCssExtractPlugin.loader, // 若果想抽离多个文件,可以在new一个出来,一个抽离css一个抽离less都行
// 这里就用一个了
'css-loader', // 解析 @import语法 解析 css
// 应该在解析css之前增加前缀
'postcss-loader',
'less-loader' // 把less 转换为 css
]
},
],
}
}
重新运行一下,发现好使了
图片加载的优化,小图片转base64
有时候我们不想因为图片的加载,向服务器发送那么多的http的请求,就可以在打包的时候将小的图片直接转换为base64,
这时候有个loader就可以干这件事,一般情况下,图片都是使用这个loader来加载的,并不会使用刚才的file-loader。
url-loader
安装一下
yarn add url-loader@^1.1.2 -D
修改配置文件,刚file-loader替换为url-loader
// webpack-dev-1\webpack.config.js
// webpack是node写出来的,所以使用node的语法
let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件
let MiniCssExtractPlugin = require('mini-css-extract-plugin') // 引入插件
let OptimizeCss = require('optimize-css-assets-webpack-plugin') // 引入插件 压缩css的
let UglifyJsPlugin = require('uglifyjs-webpack-plugin') // 压缩js文件的插件
module.exports = {
// 配置优化项
optimization: {
minimizer: [ // 是一个数组,还得优化js
new UglifyJsPlugin({
cache: true, // 是否用缓存
parallel: true, // 是否并发压缩
sourceMap: true,// 线上用来调试的映射文件
}),
new OptimizeCss(), // 开启优化css后,生产模式css文件也会被压缩,但是必须配置js压缩,如果不配置,js生产模式就不会被压缩了
]
},
devServer: { // 开发服务器的配置
port: 3000, // 默认端口是8080,这里可以改
progress: true, // 打包时候的进度条
contentBase: './build', // 以哪个文件夹作为服务的根目录
open: true, // 服务启动完毕后,直接打开浏览器
compress: true, // 启动gzip压缩
},
mode: 'development', // 模式,默认两种模式 production 和 development
entry: './src/index.js', // 入口
output: {
filename: 'bundle.js', // 打包后的文件名
path: path.resolve(__dirname, 'build'), // 打包后的路径,必须是一个绝对路径
},
plugins: [ // 是一个数组,放着所有的webpack插件
// 插件是一个类,通过new的方式来引用
new HtmlWebpackPlugin({
template: './src/index.html', // 告诉插件,是以这个目录下的index.html为模板
filename: 'index.html', // 告诉插件,打包后的文件叫什么名字,这里也叫index.html
hash: true, // 引用的时候可以加一个hash戳
}),
// 插件的使用就没有先后顺序了,随便放就行
// 引入抽离css样式的插件,
new MiniCssExtractPlugin({
filename: 'main.css', // 告诉插件,抽离出的样式文件的名字叫什么,这里叫main.css
}),
],
module: { // 模块
rules: [ // 规则,在这里面配置各种loader
{
test: /\.html$/, // 解析html中的img标签图片路径
use: 'html-withimg-loader'
},
{
test: /.(jpg|png|gif)$/,
// 做一个限制,当图片小于 多少k的时候,用base64来转化
// 如果大于这个限制,就会使用file-loader来去解析图片,将图片打包到build目录下
use: {
loader: 'url-loader',
options: {
limit: 200 * 1024, // 200K
// 如果图片小于200K的话,全部变为base64
// 否则使用file-loader 产出真实的图片
}
},
},
/* {
test: /.(jpg|png|gif)$/, // 处理图片的loader
use: 'file-loader'
}, */
{
test: /\.js$/, // 匹配以js结尾的文件
use: {
loader: 'babel-loader',
options: { // 用babel-loader 需要把ES6转为ES5
// 配置可以写在这里,还可以写在外面
// 在这里添加一个预设
presets: [ // 这是一个大插件的集合
'@babel/preset-env', // 这个插件就可以把ES6转ES5
],
// 如果有一些预设的属性,需要配置一些小插件来转换还不是标准的js语法
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
['@babel/plugin-proposal-class-properties', { "loose": true }],
"@babel/plugin-transform-runtime"
]
}
},
include: path.resolve(__dirname, 'src'), // 只找src目录下的js 包括
exclude: /node_modules/ // node_modules文件夹下的文件不用找 排除
},
// css-loader 解析css文件,@import语法的
// style-loader 把解析后的css文件 插入到head标签中
// loader有个特点,希望单一,一个loader干一件事
/*
loader的用法
1. 只用字符串,就是只用一个loader
2. 多个loader,需要一个数组 [],数组里可以放字符串,或者对象,对象的话就可以配置loader的参数了
*/
// loader的顺序,默认是从右向左执行,从下往上执行
{
test: /\.css$/,
use: [
// 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
MiniCssExtractPlugin.loader,
'css-loader',
// 应该在解析css之前增加前缀
'postcss-loader',
]
},
{
test: /\.less$/,
use: [
// 这个插件上有个loader,我们不想再用style-loader把样式放在style标签里了,所以就用它的loader
MiniCssExtractPlugin.loader, // 若果想抽离多个文件,可以在new一个出来,一个抽离css一个抽离less都行
// 这里就用一个了
'css-loader', // 解析 @import语法 解析 css
// 应该在解析css之前增加前缀
'postcss-loader',
'less-loader' // 把less 转换为 css
]
},
],
}
}
我们打包来看一下结果,发现都变为了base64格式,配置成功。
base64的优缺点
不会去请求服务器了,减少服务请求。
但是源文件会比之前大三分之一。
总结
在webpack中加载图片资源的三种方式
- 使用js创建图片,对应的src应该使用require新生成的路径,并且需要配置file-loader
- file-loader会将原来的图片在打包后的目录中新生成一份,并返回新图片的路径,以hash戳来命名的。
- 在css文件中引入的图片,比如background: url('xx')
- 之前配置的css-loader会将路径解析成require之后的新路径,所以打包后也能访问到
- 在html文件中使用img标签来访问
- 需要配置html-withimg-loader,会将img标签中的路径解析成require后的路径,所以最终也能访问到
- 一般来说,我们打包图片都会使用 url-loader
- url-loader可以配置一个属性,对于小于多少K的图片可以转换为base64格式,超过这个大小的图片会使用file-loader打包
- 所以可以对图片请求做一次优化,减少http请求。
- 但是base64会比源文件大三分之一。
参考
https://www.bilibili.com/video/BV1a4411e7Bz?p=10&spm_id_from=pageDriver