加载图片案例准备
为了演示我们项目中可以加载图片,我们需要在项目中使用图片,比较常见的使用图片的方式是两种:
.image-bg {
background-image: url("../image/3.jpg");
width: 300px;
height: 300px;
}
// 导入背景图片的样式
import '../css/index.css'
import myImg from '../image/1.JPG'
// 设置背景图片
const bgDiv = document.createElement('div');
bgDiv.className = 'image-bg';
// 设置img标签的src属性
const img = document.createElement('img');
img.src = myImg;
document.body.appendChild(bgDiv);
document.body.appendChild(img);
这个时候,打包会报错
报错了,并且提示我们可以需要一个loader来解决图片的问题。
要处理jpg、png等格式的图片,我们也需要有对应的loader:file-loader
安装file-loader:
npm i file-loader -D
配置处理图片的Rule:
// 配置打包图片资源的规则
{
test: /\.(jpg|png|jpeg|JPG)$/,
use: 'file-loader'
}
我们会发现图片也被打包了。
有时候我们处理后的文件名称按照一定的规则进行显示:
这个时候我们可以使用PlaceHolders来完成,webpack给我们提供了大量的PlaceHolders来显示不同的内容:
我们这里介绍几个最常用的placeholder:
那么我们可以按照如下的格式编写:这个也是vue的写法;
{
test: /\.(jpg|png|jpeg|JPG)$/,
use: {
loader: 'file-loader',
// file-loader的参数配置
options: {
// 打包后图片文件所在的路径
// outputPath: 'image',
// 打包后生成文件的名称
// [name] 源文件的名称(不含拓展名)
// 我们发现不写配置时,文件的名称过长(且文件名是通过hash算法算出来的,为了防止重名)
// [hash:6] 默认生成文件名称的hash算法,32位,取前六位
// [ext] 使用原来文件的拓展名
// name: '[name]_[hash:6].[ext]'
// 当然:我们也可以把图片存放的路径和图片名称合在一起
name: 'image/[name]-[hash:6].[ext]'
}
}
}
当然,我们刚才通过 img/ 已经设置了文件夹,这个也是vue、react脚手架中常见的设置方式:
url-loader和file-loader的工作方式是相似的,但是可以将较小的文件,转成base64的URI。
安装url-loader:
npm i url-loader -D
{
test: /\.(jpe?g|JPG|png)$/,
use: {
loader: 'url-loader',
options: {
name: 'image/[name]-[hash:6].[ext]',
// 设置图片大小的限制,只有小于多少kb的图片我们才会转为base64格式
// 如果大于这个限制 我们就不会转为base64格式。而是继续采用上面的path和name的形式打包,还是保持图片的形式不变
limit: 100 * 1024 // 小于100kb的文件才会转为base64格式
}
}
}
显示结果是一样的,并且图片可以正常显示;
但是在dist文件夹中,我们会看不到 大于100kb 图片文件:
可以看见bundle.js文件里面的确有base64格式的字符串
但是开发中我们往往是小的图片需要转换,但是大的图片直接使用图片即可
那么,我们如何可以限制哪些大小的图片转换和不转换呢?
我们当前使用的webpack版本是webpack5:
资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:
比如加载图片,我们可以使用下面的方式:
发现依然打包成功!
但是,如何可以自定义文件的输出路径和文件名呢?
方式一:修改output,添加assetModuleFilename属性; (了解即可)
方式二:在Rule中,添加一个generator属性,并且设置filename;
{
test: /\.(JPG|jpe?g|png)$/,
// 这里不在使用use属性 而是type属性
// 使用asset/resource 来代替 file-loader
// type:'asset/resource'
// 比较常用的我们一般直接写成 asset
type: 'asset',
// 下面的配置也可以放在 output里面(了解)
// generator属性 生成 也就是打包后的图片存放时相关的配置
generator: {
// 配置图片名称和图片位置
// 这里的 [ext] 拿到的文件拓展名包含 .
filename: 'image/[name]-[hash:6][ext]'
}
}
我们需要两个步骤来实现:
{
test: /\.(JPG|jpe?g|png)$/,
// 比较常用的我们一般直接写成 asset
type: 'asset',
// 配置相关的asset参数 使用parser属性
parser: {
// 数据url条件
dataUrlCondition: {
// 最大不超过多少kb的图片 我们转为 base64格式
maxSize: 100 * 1024
}
},
generator: {
filename: 'image/[name]-[hash:6][ext]'
}
}
发现打包的只有一个图片文件了。较小的那个已经转为base64格式了
如果我们需要使用某些特殊的字体或者字体图标,那么我们会引入很多字体相关的文件,这些文件的处理也是一样 的
首先,我从阿里图标库中下载了几个字体图标:
然后在font.js里面引入,并设置一个 i
标签用于显示字体图标
// 引入并使用字体图标
// 加载字体图标的文件
import '../font/iconfont.css'
// i标签
const i = document.createElement('i');
i.className = 'iconfont icon-ashbin';
document.body.appendChild(i);
然后我们开始打包
毫无疑问,必然报错,因为我们使用了webpack并不认识的模块。并且webpack也提醒我们需要使用一个loader来解决。
这个时候打包会报错,因为无法正确的处理eot、ttf、woff等文件:
我们可以选择使用file-loader来处理,也可以选择直接使用webpack5的资源模块类型来处理;
// 配置字体和字体图标等文件打包时的规则
{
test: /\.(eot|ttf|woff2?)$/,
use:{
loader: 'file-loader',
options:{
name: 'font/[name]-[hash:6].[ext]'
}
}
}
打包之后,发现不会报错,字体图标正常显示。
使用webpack5提供的资源模块类型也可以。
// 也可以使用webpack提供的资源模块类型
{
test: /\.(eot|ttf|woff2?)$/,
type: 'asset/resource',
generator:{
filename: 'font/[name]-[hash:6][ext]'
}
}
Webpack的另一个核心是Plugin,官方有这样一段对Plugin的描述:
While loaders are used to transform certain types of modules, plugins can be leveraged to perform a wider range of tasks like bundle optimization, asset management and injection of environment variables.
上面表达的含义翻译过来就是:
前面我们演示的过程中,每次修改了一些配置,重新打包时,都需要手动删除dist文件夹:
我们可以借助于一个插件来帮助我们完成,这个插件就是CleanWebpackPlugin;
首先,我们先安装这个插件:
npm i clean-webpack-plugin -D
之后在插件中配置:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
// 提供 plugins属性来配置插件
// plugins属性是数组,数组元素是一个个的插件对象
plugins: [
new CleanWebpackPlugin()
]
}
然后可以发现每次都会帮我们把上次打包的文件夹先删除,然后在进行重新打包。
另外还有一个不太规范的地方:
对HTML进行打包处理我们可以使用另外一个插件:HtmlWebpackPlugin;
npm i html-webpack-plugin -D
我们会发现,现在自动在build文件夹中,生成了一个index.html的文件:
该文件中也自动添加了我们打包的bundle.js文件;
这个文件是如何生成的呢?
如果我们想在自己的模块中加入一些比较特别的内容:
比如添加一个noscript标签,在用户的JavaScript被关闭时,给予响应的提示;
比如在开发vue或者react项目时,我们需要一个可以挂载后续组件的根标签
;
这个我们需要一个属于自己的index.html模块:
下面是模板代码(使用Vue-cli脚手架开发时的默认的模板就是这个)
DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %>title>
head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
noscript>
<div id="app">div>
body>
html>
但是:使用这个模板直接进行打包的时候:会发现打包失败!!(使用html-webpack-plugin插件的时候需要指定该模板)
上面的代码中,会有一些类似这样的语法**<% 变量 %>**,这个是EJS模块填充数据的方式。
在配置HtmlWebpackPlugin时,我们可以添加如下配置:
但是,我们会发现,即使配置了模板啊,标题啊,仍然打包还是报错。
不要着急,我们可以使用webpack内置的一个插件来进行解决。
我们上面指定了模板以后,发现仍然还是报错。报错的原因是什么呢?
因为在我们的模块中还使用到一个BASE_URL的常量:
这是因为在编译template模块时,有一个BASE_URL:
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
但是我们并没有设置过这个常量值,所以会出现没有定义的错误;
这个时候我们可以使用DefinePlugin插件;
DefinePlugin允许在编译时创建配置的全局常量,是一个webpack内置的插件(不需要单独安装):
// 导入 DefinePlugin 插件 解决常量 BASE_URL 的问题
const { DefinePlugin } = require('webpack');
module.exports = {
// 提供 plugins属性来配置插件
// plugins属性是数组,数组元素是一个个的插件对象
plugins: [
// 使用 DefinePlugin 插件来定义 常量
new DefinePlugin({
BASE_URL: "'./'"
})
]
这个时候,编译template就可以正确的编译了,会读取到BASE_URL的值;
new DefinePlugin({
// BASE_URL 会根据后面给的属性值 去本文件上下文中找这个变量
// 比如我这里给的是字符串 "filepath"
// 也会去上下文中找叫做 filepath 的变量
// 如果我们想直接给一个字符串的值
// 我们需要在双引号里面嵌套单引号赋值
// 当然 单引号里面嵌套双引号赋值也是可以的
// BASE_URL: "filepath",
BASE_URL: "'./'"
})
在vue的打包过程中,如果我们将一些文件放到public的目录下,那么这个目录会被复制到dist文件夹中。这个复制的功能,我们可以使用CopyWebpackPlugin来完成;
安装CopyWebpackPlugin插件:
npm i copy-webpack-plugin -D
接下来配置CopyWebpackPlugin即可:
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
plugins:[
// 其他省略
new CopyWebpackPlugin({
patterns: [
{
// 复制的来源
from: 'public',
to: '',
// 全局配置 globOptions
globOptions: {
ignore: '**/index.html'
}
}
]
})
]
}
可以看到效果和我们的配置的一样。
前面我们一直没有讲mode。
Mode配置选项,可以告知webpack使用响应模式的内置优化:
选项 | 描述 |
---|---|
development | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development . 为模块和 chunk 启用有效的名。 |
production | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production 。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin ,FlagIncludedChunksPlugin ,ModuleConcatenationPlugin ,NoEmitOnErrorsPlugin 和 TerserPlugin 。 |
none | 不使用任何默认优化选项 |
如果没有设置,webpack 会给 mode
的默认值设置为 production
。
如果 mode
未通过配置或 CLI 赋值,CLI 将使用可能有效的 NODE_ENV
值作为 mode
。当然这是后话了。我们学习CLI的时候再来说。
只要设置了mode属性,webpack就会默认帮我们设置很多属性。不需要我们手动再去配置。
这里顺手补充一波devtool。
devtool也是和mode同级别的配置。默认值是eval。设置开发时的工具
此选项控制是否生成,以及如何生成 source map。
在默认值的情况下:默认会使用 eval函数对源代码进行包裹
// devtool 属性 :设置开发时的工具 默认值是 eval
// 默认会使用 eval函数对源代码进行包裹
devtool: 'eval'
发现我们的打包后的代码全都被eval函数包裹
把属性设置为source-map。出现错误就可以定位源码。
// 如果想查看源码:可以设置值为 source-map
// 设置为这个属性 会生成对应的打包后的代码和源码映射的文件
// 出现错误可以映射到我们书写的源代码
devtool: 'source-map'
发现代码并不是我们自己写的源码。不好辨别具体是那个文件出现错误。
出现错误,可以直接定位到具体是哪一个源文件。很nice。
devtool | performance | production | quality | comment |
---|---|---|---|---|
(none) | build: fastest rebuild: fastest | yes | bundle | Recommended choice for production builds with maximum performance. |
eval |
build: fast rebuild: fastest | no | generated | Recommended choice for development builds with maximum performance. |
eval-cheap-source-map |
build: ok rebuild: fast | no | transformed | Tradeoff choice for development builds. |
eval-cheap-module-source-map |
build: slow rebuild: fast | no | original lines | Tradeoff choice for development builds. |
eval-source-map |
build: slowest rebuild: ok | no | original | Recommended choice for development builds with high quality SourceMaps. |
cheap-source-map |
build: ok rebuild: slow | no | transformed | |
cheap-module-source-map |
build: slow rebuild: slow | no | original lines | |
source-map |
build: slowest rebuild: slowest | yes | original | Recommended choice for production builds with high quality SourceMaps. |
inline-cheap-source-map |
build: ok rebuild: slow | no | transformed | |
inline-cheap-module-source-map |
build: slow rebuild: slow | no | original lines | |
inline-source-map |
build: slowest rebuild: slowest | no | original | Possible choice when publishing a single file |
eval-nosources-cheap-source-map |
build: ok rebuild: fast | no | transformed | source code not included |
eval-nosources-cheap-module-source-map |
build: slow rebuild: fast | no | original lines | source code not included |
eval-nosources-source-map |
build: slowest rebuild: ok | no | original | source code not included |
inline-nosources-cheap-source-map |
build: ok rebuild: slow | no | transformed | source code not included |
inline-nosources-cheap-module-source-map |
build: slow rebuild: slow | no | original lines | source code not included |
inline-nosources-source-map |
build: slowest rebuild: slowest | no | original | source code not included |
nosources-cheap-source-map |
build: ok rebuild: slow | no | transformed | source code not included |
nosources-cheap-module-source-map |
build: slow rebuild: slow | no | original lines | source code not included |
nosources-source-map |
build: slowest rebuild: slowest | yes | original | source code not included |
hidden-nosources-cheap-source-map |
build: ok rebuild: slow | no | transformed | no reference, source code not included |
hidden-nosources-cheap-module-source-map |
build: slow rebuild: slow | no | original lines | no reference, source code not included |
hidden-nosources-source-map |
build: slowest rebuild: slowest | yes | original | no reference, source code not included |
hidden-cheap-source-map |
build: ok rebuild: slow | no | transformed | no reference |
hidden-cheap-module-source-map |
build: slow rebuild: slow | no | original lines | no reference |
hidden-source-map |
build: slowest rebuild: slowest | yes | original | no reference. Possible choice when using SourceMap only for error reporting purposes. |
const path = require('path');
module.exports = {
entry: path.join(__dirname, "./src/index.js"),
output: {
path: path.join(__dirname, "./build"),
filename: 'bundle.js',
// 使用asset打包的图片不转为base64格式的时候,图片存放的位置以及名称
// assetModuleFilename: 'image/[name]-[hash:6][ext]'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
// 配置打包图片资源的规则
// {
// test: /\.(jpg|png|jpeg|JPG)$/,
// use: 'file-loader'
// }
/* {
test: /\.(jpg|png|jpeg|JPG)$/,
use: {
loader: 'file-loader',
// file-loader的参数配置
options: {
// 打包后图片文件所在的路径
// outputPath: 'image',
// 打包后生成文件的名称
// [name] 源文件的名称(不含拓展名)
// 我们发现不写配置时,文件的名称过长(且文件名是通过hash算法算出来的,为了防止重名)
// [hash:6] 默认生成文件名称的hash算法,32位,取前六位
// [ext] 使用原来文件的拓展名
// name: '[name]_[hash:6].[ext]'
// 当然:我们也可以把图片存放的路径和图片名称合在一起
name: 'image/[name]-[hash:6].[ext]'
}
}
} , */
// 注意: 使用file-loader就不要使用url-loader
// 使用url-loader也不需要使用file-loader
// 配置url-loader 设置图片大小的限制,小于某个范围的图片转为base64格式
// {
// test: /\.(jpe?g|JPG|png)$/,
// use: {
// loader: 'url-loader',
// options: {
// name: 'image/[name]-[hash:6].[ext]',
// // 设置图片大小的限制,只有小于多少kb的图片我们才会转为base64格式
// // 如果大于这个限制 我们就不会转为base64格式。而是继续采用上面的path和name的形式打包,还是保持图片的形式不变
// limit: 100 * 1024 // 小于100kb的文件才会转为base64格式
// }
// }
// }
// webpack5开始 可以不在使用file-loader和url-loader来进行打包图片了
// 我们直接使用 asset module type 资源模块类型 来替换上面loader
// 注意:asset是webpack5自带的
{
test: /\.(JPG|jpe?g|png)$/,
// 这里不在使用use属性 而是type属性
// 使用asset/resource 来代替 file-loader
// type:'asset/resource'
// 比较常用的我们一般直接写成 asset
type: 'asset',
// 配置相关的asset参数 使用parser属性
parser: {
// 数据url条件
dataUrlCondition: {
// 最大不超过多少kb的图片 我们转为 base64格式
maxSize: 100 * 1024
}
},
// 下面的配置也可以放在 output里面(了解)
// generator属性 生成 也就是打包后的图片存放时相关的配置
generator: {
// 配置图片名称和图片位置
// 这里的 [ext] 拿到的文件拓展名包含 .
filename: 'image/[name]-[hash:6][ext]'
}
},
// 配置字体和字体图标等文件打包时的规则
// {
// test: /\.(eot|ttf|woff2?)$/,
// use:{
// loader: 'file-loader',
// options:{
// // 这里是name属性 不是filename
// name: 'font/[name]-[hash:6].[ext]'
// }
// }
// },
// 也可以使用webpack提供的资源模块类型
{
test: /\.(eot|ttf|woff2?)$/,
type: 'asset/resource',
generator: {
// 这里使用的是filename属性 别忘了!!!!!
filename: 'font/[name]-[hash:6][ext]'
}
}
]
}
}
const path = require('path');
// 注意:所有的插件都需要导入的,loader不需要
// 导入 clean-webpack-plugin 插件
// 该插件导出的是一个对象,我们需要从对象里面按需获取 CleanWebpackPlugin 这个类
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 导入 html-webpack-plugin插件 这个插件导出的就是一个类 不需要解构
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 导入 DefinePlugin 插件 解决常量 BASE_URL 的问题
const { DefinePlugin } = require('webpack');
// 导入 CopyWebpackPlugin 插件 该插件导出的也是一个类
// 用来完成文件的复制工作
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
// 模式配置 mode
// development 生产模式 打包的代码不会压缩 易于阅读
mode:"development",
// 开发模式 代码会被压缩 减小体积
// mode:"production",
// devtool 属性 :设置开发时的工具 默认值是 eval
// 默认会使用 eval函数对源代码进行包裹
// devtool: 'eval',
// 如果想查看源码:可以设置值为 source-map
// 设置为这个属性 会生成对应的打包后的代码和源码映射的文件
// 出现错误可以映射到我们书写的源代码
devtool: 'source-map',
// 提供 plugins属性来配置插件
// plugins属性是数组,数组元素是一个个的插件对象
// 插件是书写没有先后顺序!!!!!!!!!!
plugins: [
// 使用 CleanWebpackPlugin 插件对象
// 因为 CleanWebpackPlugin 是一个class类,我们需要 new 实例化成对象
// CleanWebpackPlugin 插件会删除我们生成的打包后的那么文件夹,然后重新打包
new CleanWebpackPlugin(),
// 使用 HtmlWebpackPlugin 插件
// new HtmlWebpackPlugin(),
// 使用 HtmlWebpackPlugin 插件 并指定html的模板
new HtmlWebpackPlugin({
// 按照这个html文件的模板来进行打包,生成的index.html和这个模板一样
template: './public/index.html',
title: 'webpack-plugin 的学习'
}),
// 使用 DefinePlugin 插件来定义 常量
new DefinePlugin({
// BASE_URL 会根据后面给的属性值 去本文件上下文中找这个变量
// 比如我这里给的是字符串 "filepath"
// 也会去上下文中找叫做 filepath 的变量
// 如果我们想直接给一个字符串的值
// 我们需要在双引号里面嵌套单引号赋值
// 当然 单引号里面嵌套双引号赋值也是可以的
// BASE_URL: "filepath",
BASE_URL: "'./'"
}),
// 使用 CopyWebpackPlugin 插件
new CopyWebpackPlugin({
// patterns属性: 匹配规则 数组
patterns: [
{
// 复制的来源
from: 'public',
// 复制后放到哪里
// 不写,或者给空字符串 最后都是把拷贝的文件放在打包后的根目录下
to: '',
// 全局配置 globOptions
globOptions: {
// 忽略那些文件
// ignore: ['**/index.html'],
// 只有一个忽略的规则时 可以直接写一个字符串
ignore: '**/index.html'
}
}
]
})
],
entry: path.join(__dirname, "./src/index.js"),
output: {
path: path.join(__dirname, "./build"),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
// webpack5开始 可以不在使用file-loader和url-loader来进行打包图片了
// 我们直接使用 asset module type 资源模块类型 来替换上面loader
// 注意:asset是webpack5自带的
{
test: /\.(JPG|jpe?g|png)$/,
// 这里不在使用use属性 而是type属性
// 使用asset/resource 来代替 file-loader
// type:'asset/resource'
// 比较常用的我们一般直接写成 asset
type: 'asset',
// 配置相关的asset参数 使用parser属性
parser: {
// 数据url条件
dataUrlCondition: {
// 最大不超过多少kb的图片 我们转为 base64格式
maxSize: 100 * 1024
}
},
// 下面的配置也可以放在 output里面(了解)
// generator属性 生成 也就是打包后的图片存放时相关的配置
generator: {
// 配置图片名称和图片位置
// 这里的 [ext] 拿到的文件拓展名包含 .
filename: 'image/[name]-[hash:6][ext]'
}
},
// 也可以使用webpack提供的资源模块类型
{
test: /\.(eot|ttf|woff2?)$/,
type: 'asset/resource',
generator: {
// 这里使用的是filename属性 别忘了!!!!!
filename: 'font/[name]-[hash:6][ext]'
}
}
]
}
}